Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef jit_JitFrameIterator_h
8 : #define jit_JitFrameIterator_h
9 :
10 : #include "jsfun.h"
11 : #include "jsscript.h"
12 : #include "jstypes.h"
13 :
14 : #include "jit/IonCode.h"
15 : #include "jit/Snapshots.h"
16 :
17 : #include "js/ProfilingFrameIterator.h"
18 :
19 : namespace js {
20 : class ActivationIterator;
21 : } // namespace js
22 :
23 : namespace js {
24 : namespace jit {
25 :
26 : typedef void * CalleeToken;
27 :
28 : enum FrameType
29 : {
30 : // A JS frame is analogous to a js::InterpreterFrame, representing one scripted
31 : // function activation. IonJS frames are used by the optimizing compiler.
32 : JitFrame_IonJS,
33 :
34 : // JS frame used by the baseline JIT.
35 : JitFrame_BaselineJS,
36 :
37 : // Frame pushed by Baseline stubs that make non-tail calls, so that the
38 : // return address -> ICEntry mapping works.
39 : JitFrame_BaselineStub,
40 :
41 : // The entry frame is the initial prologue block transitioning from the VM
42 : // into the Ion world.
43 : JitFrame_Entry,
44 :
45 : // A rectifier frame sits in between two JS frames, adapting argc != nargs
46 : // mismatches in calls.
47 : JitFrame_Rectifier,
48 :
49 : // Ion IC calling a scripted getter/setter or a VMFunction.
50 : JitFrame_IonICCall,
51 :
52 : // An exit frame is necessary for transitioning from a JS frame into C++.
53 : // From within C++, an exit frame is always the last frame in any
54 : // JitActivation.
55 : JitFrame_Exit,
56 :
57 : // A bailout frame is a special IonJS jit frame after a bailout, and before
58 : // the reconstruction of the BaselineJS frame. From within C++, a bailout
59 : // frame is always the last frame in a JitActivation iff the bailout frame
60 : // information is recorded on the JitActivation.
61 : JitFrame_Bailout,
62 : };
63 :
64 : enum ReadFrameArgsBehavior {
65 : // Only read formals (i.e. [0 ... callee()->nargs]
66 : ReadFrame_Formals,
67 :
68 : // Only read overflown args (i.e. [callee()->nargs ... numActuals()]
69 : ReadFrame_Overflown,
70 :
71 : // Read all args (i.e. [0 ... numActuals()])
72 : ReadFrame_Actuals
73 : };
74 :
75 : class CommonFrameLayout;
76 : class JitFrameLayout;
77 : class ExitFrameLayout;
78 :
79 : class BaselineFrame;
80 :
81 : class JitActivation;
82 :
83 : // Iterate over the JIT stack to assert that all invariants are respected.
84 : // - Check that all entry frames are aligned on JitStackAlignment.
85 : // - Check that all rectifier frames keep the JitStackAlignment.
86 : void AssertJitStackInvariants(JSContext* cx);
87 :
88 : class JitFrameIterator
89 : {
90 : protected:
91 : uint8_t* current_;
92 : FrameType type_;
93 : uint8_t* returnAddressToFp_;
94 : size_t frameSize_;
95 :
96 : private:
97 : mutable const SafepointIndex* cachedSafepointIndex_;
98 : const JitActivation* activation_;
99 :
100 : void dumpBaseline() const;
101 :
102 : public:
103 : explicit JitFrameIterator();
104 : explicit JitFrameIterator(JSContext* cx);
105 : explicit JitFrameIterator(const ActivationIterator& activations);
106 :
107 : // Current frame information.
108 170 : FrameType type() const {
109 170 : return type_;
110 : }
111 60109 : uint8_t* fp() const {
112 60109 : return current_;
113 : }
114 0 : const JitActivation* activation() const {
115 0 : return activation_;
116 : }
117 :
118 104400 : CommonFrameLayout* current() const {
119 104400 : return (CommonFrameLayout*)current_;
120 : }
121 :
122 : inline uint8_t* returnAddress() const;
123 :
124 : // Return the pointer of the JitFrame, the iterator is assumed to be settled
125 : // on a scripted frame.
126 : JitFrameLayout* jsFrame() const;
127 :
128 : inline ExitFrameLayout* exitFrame() const;
129 :
130 : // Returns whether the JS frame has been invalidated and, if so,
131 : // places the invalidated Ion script in |ionScript|.
132 : bool checkInvalidation(IonScript** ionScript) const;
133 : bool checkInvalidation() const;
134 :
135 4428 : bool isExitFrame() const {
136 4428 : return type_ == JitFrame_Exit;
137 : }
138 64401 : bool isScripted() const {
139 64401 : return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
140 : }
141 158721 : bool isBaselineJS() const {
142 158721 : return type_ == JitFrame_BaselineJS;
143 : }
144 24472 : bool isIonScripted() const {
145 24472 : return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
146 : }
147 26605 : bool isIonJS() const {
148 26605 : return type_ == JitFrame_IonJS;
149 : }
150 1799 : bool isIonICCall() const {
151 1799 : return type_ == JitFrame_IonICCall;
152 : }
153 31651 : bool isBailoutJS() const {
154 31651 : return type_ == JitFrame_Bailout;
155 : }
156 4072 : bool isBaselineStub() const {
157 4072 : return type_ == JitFrame_BaselineStub;
158 : }
159 4072 : bool isRectifier() const {
160 4072 : return type_ == JitFrame_Rectifier;
161 : }
162 : bool isBareExit() const;
163 : template <typename T> bool isExitFrameLayout() const;
164 :
165 5978 : bool isEntry() const {
166 5978 : return type_ == JitFrame_Entry;
167 : }
168 : bool isFunctionFrame() const;
169 :
170 : bool isConstructing() const;
171 :
172 : void* calleeToken() const;
173 : JSFunction* callee() const;
174 : JSFunction* maybeCallee() const;
175 : unsigned numActualArgs() const;
176 : JSScript* script() const;
177 : void baselineScriptAndPc(JSScript** scriptRes, jsbytecode** pcRes) const;
178 : Value* actualArgs() const;
179 :
180 : // Returns the return address of the frame above this one (that is, the
181 : // return address that returns back to the current frame).
182 31015 : uint8_t* returnAddressToFp() const {
183 31015 : return returnAddressToFp_;
184 : }
185 :
186 : // Previous frame information extracted from the current frame.
187 : inline size_t prevFrameLocalSize() const;
188 : inline FrameType prevType() const;
189 : uint8_t* prevFp() const;
190 :
191 : // Returns the stack space used by the current frame, in bytes. This does
192 : // not include the size of its fixed header.
193 0 : size_t frameSize() const {
194 0 : MOZ_ASSERT(!isExitFrame());
195 0 : return frameSize_;
196 : }
197 :
198 : // Functions used to iterate on frames. When prevType is JitFrame_Entry,
199 : // the current frame is the last frame.
200 21109 : inline bool done() const {
201 21109 : return type_ == JitFrame_Entry;
202 : }
203 : JitFrameIterator& operator++();
204 :
205 : // Returns the IonScript associated with this JS frame.
206 : IonScript* ionScript() const;
207 :
208 : // Returns the IonScript associated with this JS frame; the frame must
209 : // not be invalidated.
210 : IonScript* ionScriptFromCalleeToken() const;
211 :
212 : // Returns the Safepoint associated with this JS frame. Incurs a lookup
213 : // overhead.
214 : const SafepointIndex* safepoint() const;
215 :
216 : // Returns the OSI index associated with this JS frame. Incurs a lookup
217 : // overhead.
218 : const OsiIndex* osiIndex() const;
219 :
220 : // Returns the Snapshot offset associated with this JS frame. Incurs a
221 : // lookup overhead.
222 : SnapshotOffset snapshotOffset() const;
223 :
224 : uintptr_t* spillBase() const;
225 : MachineState machineState() const;
226 :
227 : template <class Op>
228 0 : void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const {
229 0 : MOZ_ASSERT(isBaselineJS());
230 :
231 0 : unsigned nactual = numActualArgs();
232 : unsigned start, end;
233 0 : switch (behavior) {
234 : case ReadFrame_Formals:
235 0 : start = 0;
236 0 : end = callee()->nargs();
237 0 : break;
238 : case ReadFrame_Overflown:
239 0 : start = callee()->nargs();
240 0 : end = nactual;
241 0 : break;
242 : case ReadFrame_Actuals:
243 0 : start = 0;
244 0 : end = nactual;
245 : }
246 :
247 0 : Value* argv = actualArgs();
248 0 : for (unsigned i = start; i < end; i++)
249 0 : op(argv[i]);
250 0 : }
251 :
252 : void dump() const;
253 :
254 : inline BaselineFrame* baselineFrame() const;
255 :
256 : // This function isn't used, but we keep it here (debug-only) because it is
257 : // helpful when chasing issues with the jitcode map.
258 : #ifdef DEBUG
259 : bool verifyReturnAddressUsingNativeToBytecodeMap();
260 : #else
261 : inline bool verifyReturnAddressUsingNativeToBytecodeMap() { return true; }
262 : #endif
263 : };
264 :
265 : class JitcodeGlobalTable;
266 :
267 : class JitProfilingFrameIterator
268 : {
269 : uint8_t* fp_;
270 : FrameType type_;
271 : void* returnAddressToFp_;
272 :
273 : inline JitFrameLayout* framePtr();
274 : inline JSScript* frameScript();
275 : MOZ_MUST_USE bool tryInitWithPC(void* pc);
276 : MOZ_MUST_USE bool tryInitWithTable(JitcodeGlobalTable* table, void* pc, JSRuntime* rt,
277 : bool forLastCallSite);
278 : void fixBaselineReturnAddress();
279 :
280 : void moveToNextFrame(CommonFrameLayout* frame);
281 :
282 : public:
283 : JitProfilingFrameIterator(JSContext* cx,
284 : const JS::ProfilingFrameIterator::RegisterState& state);
285 : explicit JitProfilingFrameIterator(void* exitFrame);
286 :
287 : void operator++();
288 0 : bool done() const { return fp_ == nullptr; }
289 :
290 0 : void* fp() const { MOZ_ASSERT(!done()); return fp_; }
291 0 : void* stackAddress() const { return fp(); }
292 : FrameType frameType() const { MOZ_ASSERT(!done()); return type_; }
293 0 : void* returnAddressToFp() const { MOZ_ASSERT(!done()); return returnAddressToFp_; }
294 : };
295 :
296 : class RInstructionResults
297 : {
298 : // Vector of results of recover instructions.
299 : typedef mozilla::Vector<HeapPtr<Value>, 1, SystemAllocPolicy> Values;
300 : UniquePtr<Values> results_;
301 :
302 : // The frame pointer is used as a key to check if the current frame already
303 : // bailed out.
304 : JitFrameLayout* fp_;
305 :
306 : // Record if we tried and succeed at allocating and filling the vector of
307 : // recover instruction results, if needed. This flag is needed in order to
308 : // avoid evaluating the recover instruction twice.
309 : bool initialized_;
310 :
311 : public:
312 : explicit RInstructionResults(JitFrameLayout* fp);
313 : RInstructionResults(RInstructionResults&& src);
314 :
315 : RInstructionResults& operator=(RInstructionResults&& rhs);
316 :
317 : ~RInstructionResults();
318 :
319 : MOZ_MUST_USE bool init(JSContext* cx, uint32_t numResults);
320 : bool isInitialized() const;
321 : #ifdef DEBUG
322 : size_t length() const;
323 : #endif
324 :
325 : JitFrameLayout* frame() const;
326 :
327 : HeapPtr<Value>& operator[](size_t index);
328 :
329 : void trace(JSTracer* trc);
330 : };
331 :
332 : struct MaybeReadFallback
333 : {
334 : enum NoGCValue {
335 : NoGC_UndefinedValue,
336 : NoGC_MagicOptimizedOut
337 : };
338 :
339 : enum FallbackConsequence {
340 : Fallback_Invalidate,
341 : Fallback_DoNothing
342 : };
343 :
344 : JSContext* maybeCx;
345 : JitActivation* activation;
346 : const JitFrameIterator* frame;
347 : const NoGCValue unreadablePlaceholder_;
348 : const FallbackConsequence consequence;
349 :
350 0 : explicit MaybeReadFallback(const Value& placeholder = UndefinedValue())
351 0 : : maybeCx(nullptr),
352 : activation(nullptr),
353 : frame(nullptr),
354 0 : unreadablePlaceholder_(noGCPlaceholder(placeholder)),
355 0 : consequence(Fallback_Invalidate)
356 : {
357 0 : }
358 :
359 0 : MaybeReadFallback(JSContext* cx, JitActivation* activation, const JitFrameIterator* frame,
360 : FallbackConsequence consequence = Fallback_Invalidate)
361 0 : : maybeCx(cx),
362 : activation(activation),
363 : frame(frame),
364 : unreadablePlaceholder_(NoGC_UndefinedValue),
365 0 : consequence(consequence)
366 : {
367 0 : }
368 :
369 0 : bool canRecoverResults() { return maybeCx; }
370 :
371 0 : Value unreadablePlaceholder() const {
372 0 : if (unreadablePlaceholder_ == NoGC_MagicOptimizedOut)
373 0 : return MagicValue(JS_OPTIMIZED_OUT);
374 0 : return UndefinedValue();
375 : }
376 :
377 0 : NoGCValue noGCPlaceholder(const Value& v) const {
378 0 : if (v.isMagic(JS_OPTIMIZED_OUT))
379 0 : return NoGC_MagicOptimizedOut;
380 0 : return NoGC_UndefinedValue;
381 : }
382 : };
383 :
384 :
385 : class RResumePoint;
386 : class RSimdBox;
387 :
388 : // Reads frame information in snapshot-encoding order (that is, outermost frame
389 : // to innermost frame).
390 1680 : class SnapshotIterator
391 : {
392 : protected:
393 : SnapshotReader snapshot_;
394 : RecoverReader recover_;
395 : JitFrameLayout* fp_;
396 : const MachineState* machine_;
397 : IonScript* ionScript_;
398 : RInstructionResults* instructionResults_;
399 :
400 : enum ReadMethod {
401 : // Read the normal value.
402 : RM_Normal = 1 << 0,
403 :
404 : // Read the default value, or the normal value if there is no default.
405 : RM_AlwaysDefault = 1 << 1,
406 :
407 : // Try to read the normal value if it is readable, otherwise default to
408 : // the Default value.
409 : RM_NormalOrDefault = RM_Normal | RM_AlwaysDefault,
410 : };
411 :
412 : private:
413 : // Read a spilled register from the machine state.
414 0 : bool hasRegister(Register reg) const {
415 0 : return machine_->has(reg);
416 : }
417 0 : uintptr_t fromRegister(Register reg) const {
418 0 : return machine_->read(reg);
419 : }
420 :
421 0 : bool hasRegister(FloatRegister reg) const {
422 0 : return machine_->has(reg);
423 : }
424 0 : double fromRegister(FloatRegister reg) const {
425 0 : return machine_->read(reg);
426 : }
427 :
428 : // Read an uintptr_t from the stack.
429 0 : bool hasStack(int32_t offset) const {
430 0 : return true;
431 : }
432 : uintptr_t fromStack(int32_t offset) const;
433 :
434 0 : bool hasInstructionResult(uint32_t index) const {
435 0 : return instructionResults_;
436 : }
437 0 : bool hasInstructionResults() const {
438 0 : return instructionResults_;
439 : }
440 : Value fromInstructionResult(uint32_t index) const;
441 :
442 : Value allocationValue(const RValueAllocation& a, ReadMethod rm = RM_Normal);
443 : MOZ_MUST_USE bool allocationReadable(const RValueAllocation& a, ReadMethod rm = RM_Normal);
444 : void writeAllocationValuePayload(const RValueAllocation& a, const Value& v);
445 : void warnUnreadableAllocation();
446 :
447 : private:
448 : friend class RSimdBox;
449 : const FloatRegisters::RegisterContent* floatAllocationPointer(const RValueAllocation& a) const;
450 :
451 : public:
452 : // Handle iterating over RValueAllocations of the snapshots.
453 0 : inline RValueAllocation readAllocation() {
454 0 : MOZ_ASSERT(moreAllocations());
455 0 : return snapshot_.readAllocation();
456 : }
457 0 : Value skip() {
458 0 : snapshot_.skipAllocation();
459 0 : return UndefinedValue();
460 : }
461 :
462 : const RResumePoint* resumePoint() const;
463 1680 : const RInstruction* instruction() const {
464 1680 : return recover_.instruction();
465 : }
466 :
467 : uint32_t numAllocations() const;
468 0 : inline bool moreAllocations() const {
469 0 : return snapshot_.numAllocationsRead() < numAllocations();
470 : }
471 :
472 : int32_t readOuterNumActualArgs() const;
473 :
474 : // Used by recover instruction to store the value back into the instruction
475 : // results array.
476 : void storeInstructionResult(const Value& v);
477 :
478 : public:
479 : // Exhibits frame properties contained in the snapshot.
480 : uint32_t pcOffset() const;
481 0 : inline MOZ_MUST_USE bool resumeAfter() const {
482 : // Inline frames are inlined on calls, which are considered as being
483 : // resumed on the Call as baseline will push the pc once we return from
484 : // the call.
485 0 : if (moreFrames())
486 0 : return false;
487 0 : return recover_.resumeAfter();
488 : }
489 0 : inline BailoutKind bailoutKind() const {
490 0 : return snapshot_.bailoutKind();
491 : }
492 :
493 : public:
494 : // Read the next instruction available and get ready to either skip it or
495 : // evaluate it.
496 0 : inline void nextInstruction() {
497 0 : MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations());
498 0 : recover_.nextInstruction();
499 0 : snapshot_.resetNumAllocationsRead();
500 0 : }
501 :
502 : // Skip an Instruction by walking to the next instruction and by skipping
503 : // all the allocations corresponding to this instruction.
504 : void skipInstruction();
505 :
506 1680 : inline bool moreInstructions() const {
507 1680 : return recover_.moreInstructions();
508 : }
509 :
510 : protected:
511 : // Register a vector used for storing the results of the evaluation of
512 : // recover instructions. This vector should be registered before the
513 : // beginning of the iteration. This function is in charge of allocating
514 : // enough space for all instructions results, and return false iff it fails.
515 : MOZ_MUST_USE bool initInstructionResults(MaybeReadFallback& fallback);
516 :
517 : // This function is used internally for computing the result of the recover
518 : // instructions.
519 : MOZ_MUST_USE bool computeInstructionResults(JSContext* cx, RInstructionResults* results) const;
520 :
521 : public:
522 : // Handle iterating over frames of the snapshots.
523 : void nextFrame();
524 : void settleOnFrame();
525 :
526 1680 : inline bool moreFrames() const {
527 : // The last instruction is recovering the innermost frame, so as long as
528 : // there is more instruction there is necesseray more frames.
529 1680 : return moreInstructions();
530 : }
531 :
532 : public:
533 : // Connect all informations about the current script in order to recover the
534 : // content of baseline frames.
535 :
536 : SnapshotIterator(const JitFrameIterator& iter, const MachineState* machineState);
537 : SnapshotIterator();
538 :
539 0 : Value read() {
540 0 : return allocationValue(readAllocation());
541 : }
542 :
543 : // Read the |Normal| value unless it is not available and that the snapshot
544 : // provides a |Default| value. This is useful to avoid invalidations of the
545 : // frame while we are only interested in a few properties which are provided
546 : // by the |Default| value.
547 0 : Value readWithDefault(RValueAllocation* alloc) {
548 0 : *alloc = RValueAllocation();
549 0 : RValueAllocation a = readAllocation();
550 0 : if (allocationReadable(a))
551 0 : return allocationValue(a);
552 :
553 0 : *alloc = a;
554 0 : return allocationValue(a, RM_AlwaysDefault);
555 : }
556 :
557 : Value maybeRead(const RValueAllocation& a, MaybeReadFallback& fallback);
558 0 : Value maybeRead(MaybeReadFallback& fallback) {
559 0 : RValueAllocation a = readAllocation();
560 0 : return maybeRead(a, fallback);
561 : }
562 :
563 : void traceAllocation(JSTracer* trc);
564 :
565 : template <class Op>
566 0 : void readFunctionFrameArgs(Op& op, ArgumentsObject** argsObj, Value* thisv,
567 : unsigned start, unsigned end, JSScript* script,
568 : MaybeReadFallback& fallback)
569 : {
570 : // Assumes that the common frame arguments have already been read.
571 0 : if (script->argumentsHasVarBinding()) {
572 0 : if (argsObj) {
573 0 : Value v = read();
574 0 : if (v.isObject())
575 0 : *argsObj = &v.toObject().as<ArgumentsObject>();
576 : } else {
577 0 : skip();
578 : }
579 : }
580 :
581 0 : if (thisv)
582 0 : *thisv = maybeRead(fallback);
583 : else
584 0 : skip();
585 :
586 0 : unsigned i = 0;
587 0 : if (end < start)
588 0 : i = start;
589 :
590 0 : for (; i < start; i++)
591 0 : skip();
592 0 : for (; i < end; i++) {
593 : // We are not always able to read values from the snapshots, some values
594 : // such as non-gc things may still be live in registers and cause an
595 : // error while reading the machine state.
596 0 : Value v = maybeRead(fallback);
597 0 : op(v);
598 : }
599 0 : }
600 :
601 : // Iterate over all the allocations and return only the value of the
602 : // allocation located at one index.
603 : Value maybeReadAllocByIndex(size_t index);
604 :
605 : #ifdef TRACK_SNAPSHOTS
606 0 : void spewBailingFrom() const {
607 0 : snapshot_.spewBailingFrom();
608 0 : }
609 : #endif
610 : };
611 :
612 : // Reads frame information in callstack order (that is, innermost frame to
613 : // outermost frame).
614 3186 : class InlineFrameIterator
615 : {
616 : const JitFrameIterator* frame_;
617 : SnapshotIterator start_;
618 : SnapshotIterator si_;
619 : uint32_t framesRead_;
620 :
621 : // When the inline-frame-iterator is created, this variable is defined to
622 : // UINT32_MAX. Then the first iteration of findNextFrame, which settle on
623 : // the innermost frame, is used to update this counter to the number of
624 : // frames contained in the recover buffer.
625 : uint32_t frameCount_;
626 :
627 : // The |calleeTemplate_| fields contains either the JSFunction or the
628 : // template from which it is supposed to be cloned. The |calleeRVA_| is an
629 : // Invalid value allocation, if the |calleeTemplate_| field is the effective
630 : // JSFunction, and not its template. On the other hand, any other value
631 : // allocation implies that the |calleeTemplate_| is the template JSFunction
632 : // from which the effective one would be derived and cached by the Recover
633 : // instruction result.
634 : RootedFunction calleeTemplate_;
635 : RValueAllocation calleeRVA_;
636 :
637 : RootedScript script_;
638 : jsbytecode* pc_;
639 : uint32_t numActualArgs_;
640 :
641 : // Register state, used by all snapshot iterators.
642 : MachineState machine_;
643 :
644 : struct Nop {
645 0 : void operator()(const Value& v) { }
646 : };
647 :
648 : private:
649 : void findNextFrame();
650 : JSObject* computeEnvironmentChain(const Value& envChainValue, MaybeReadFallback& fallback,
651 : bool* hasInitialEnv = nullptr) const;
652 :
653 : public:
654 : InlineFrameIterator(JSContext* cx, const JitFrameIterator* iter);
655 : InlineFrameIterator(JSContext* cx, const InlineFrameIterator* iter);
656 :
657 1680 : bool more() const {
658 1680 : return frame_ && framesRead_ < frameCount_;
659 : }
660 :
661 : // Due to optimizations, we are not always capable of reading the callee of
662 : // inlined frames without invalidating the IonCode. This function might
663 : // return either the effective callee of the JSFunction which might be used
664 : // to create it.
665 : //
666 : // As such, the |calleeTemplate()| can be used to read most of the metadata
667 : // which are conserved across clones.
668 840 : JSFunction* calleeTemplate() const {
669 840 : MOZ_ASSERT(isFunctionFrame());
670 840 : return calleeTemplate_;
671 : }
672 0 : JSFunction* maybeCalleeTemplate() const {
673 0 : return calleeTemplate_;
674 : }
675 :
676 : JSFunction* callee(MaybeReadFallback& fallback) const;
677 :
678 0 : unsigned numActualArgs() const {
679 : // The number of actual arguments of inline frames is recovered by the
680 : // iteration process. It is recovered from the bytecode because this
681 : // property still hold since the for inlined frames. This property does not
682 : // hold for the parent frame because it can have optimize a call to
683 : // js_fun_call or js_fun_apply.
684 0 : if (more())
685 0 : return numActualArgs_;
686 :
687 0 : return frame_->numActualArgs();
688 : }
689 :
690 : template <class ArgOp, class LocalOp>
691 0 : void readFrameArgsAndLocals(JSContext* cx, ArgOp& argOp, LocalOp& localOp,
692 : JSObject** envChain, bool* hasInitialEnv,
693 : Value* rval, ArgumentsObject** argsObj,
694 : Value* thisv, Value* newTarget,
695 : ReadFrameArgsBehavior behavior,
696 : MaybeReadFallback& fallback) const
697 : {
698 0 : SnapshotIterator s(si_);
699 :
700 : // Read the env chain.
701 0 : if (envChain) {
702 0 : Value envChainValue = s.maybeRead(fallback);
703 0 : *envChain = computeEnvironmentChain(envChainValue, fallback, hasInitialEnv);
704 : } else {
705 0 : s.skip();
706 : }
707 :
708 : // Read return value.
709 0 : if (rval)
710 0 : *rval = s.maybeRead(fallback);
711 : else
712 0 : s.skip();
713 :
714 0 : if (newTarget) {
715 : // For now, only support reading new.target when we are reading
716 : // overflown arguments.
717 0 : MOZ_ASSERT(behavior != ReadFrame_Formals);
718 0 : newTarget->setUndefined();
719 : }
720 :
721 : // Read arguments, which only function frames have.
722 0 : if (isFunctionFrame()) {
723 0 : unsigned nactual = numActualArgs();
724 0 : unsigned nformal = calleeTemplate()->nargs();
725 :
726 : // Get the non overflown arguments, which are taken from the inlined
727 : // frame, because it will have the updated value when JSOP_SETARG is
728 : // done.
729 0 : if (behavior != ReadFrame_Overflown)
730 0 : s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, nformal, script(), fallback);
731 :
732 0 : if (behavior != ReadFrame_Formals) {
733 0 : if (more()) {
734 : // There is still a parent frame of this inlined frame. All
735 : // arguments (also the overflown) are the last pushed values
736 : // in the parent frame. To get the overflown arguments, we
737 : // need to take them from there.
738 :
739 : // The overflown arguments are not available in current frame.
740 : // They are the last pushed arguments in the parent frame of
741 : // this inlined frame.
742 0 : InlineFrameIterator it(cx, this);
743 0 : ++it;
744 0 : unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
745 0 : bool hasNewTarget = isConstructing();
746 0 : SnapshotIterator parent_s(it.snapshotIterator());
747 :
748 : // Skip over all slots until we get to the last slots
749 : // (= arguments slots of callee) the +3 is for [this], [returnvalue],
750 : // [envchain], and maybe +1 for [argsObj]
751 0 : MOZ_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj + hasNewTarget);
752 0 : unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj - hasNewTarget;
753 0 : for (unsigned j = 0; j < skip; j++)
754 0 : parent_s.skip();
755 :
756 : // Get the overflown arguments
757 0 : MaybeReadFallback unusedFallback;
758 0 : parent_s.skip(); // env chain
759 0 : parent_s.skip(); // return value
760 0 : parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr,
761 : nformal, nactual, it.script(),
762 : fallback);
763 0 : if (newTarget && isConstructing())
764 0 : *newTarget = parent_s.maybeRead(fallback);
765 : } else {
766 : // There is no parent frame to this inlined frame, we can read
767 : // from the frame's Value vector directly.
768 0 : Value* argv = frame_->actualArgs();
769 0 : for (unsigned i = nformal; i < nactual; i++)
770 0 : argOp(argv[i]);
771 0 : if (newTarget && isConstructing())
772 0 : *newTarget = argv[nactual];
773 : }
774 : }
775 : }
776 :
777 : // At this point we've read all the formals in s, and can read the
778 : // locals.
779 0 : for (unsigned i = 0; i < script()->nfixed(); i++)
780 0 : localOp(s.maybeRead(fallback));
781 0 : }
782 :
783 : template <class Op>
784 0 : void unaliasedForEachActual(JSContext* cx, Op op,
785 : ReadFrameArgsBehavior behavior,
786 : MaybeReadFallback& fallback) const
787 : {
788 : Nop nop;
789 0 : readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr,
790 : nullptr, nullptr, behavior, fallback);
791 0 : }
792 :
793 2520 : JSScript* script() const {
794 2520 : return script_;
795 : }
796 840 : jsbytecode* pc() const {
797 840 : return pc_;
798 : }
799 0 : SnapshotIterator snapshotIterator() const {
800 0 : return si_;
801 : }
802 : bool isFunctionFrame() const;
803 : bool isModuleFrame() const;
804 : bool isConstructing() const;
805 :
806 0 : JSObject* environmentChain(MaybeReadFallback& fallback) const {
807 0 : SnapshotIterator s(si_);
808 :
809 : // envChain
810 0 : Value v = s.maybeRead(fallback);
811 0 : return computeEnvironmentChain(v, fallback);
812 : }
813 :
814 0 : Value thisArgument(MaybeReadFallback& fallback) const {
815 0 : SnapshotIterator s(si_);
816 :
817 : // envChain
818 0 : s.skip();
819 :
820 : // return value
821 0 : s.skip();
822 :
823 : // Arguments object.
824 0 : if (script()->argumentsHasVarBinding())
825 0 : s.skip();
826 :
827 0 : return s.maybeRead(fallback);
828 : }
829 :
830 0 : InlineFrameIterator& operator++() {
831 0 : findNextFrame();
832 0 : return *this;
833 : }
834 :
835 : void dump() const;
836 :
837 : void resetOn(const JitFrameIterator* iter);
838 :
839 0 : const JitFrameIterator& frame() const {
840 0 : return *frame_;
841 : }
842 :
843 : // Inline frame number, 0 for the outermost (non-inlined) frame.
844 2520 : size_t frameNo() const {
845 2520 : return frameCount() - framesRead_;
846 : }
847 2520 : size_t frameCount() const {
848 2520 : MOZ_ASSERT(frameCount_ != UINT32_MAX);
849 2520 : return frameCount_;
850 : }
851 :
852 : private:
853 : InlineFrameIterator() = delete;
854 : InlineFrameIterator(const InlineFrameIterator& iter) = delete;
855 : };
856 :
857 : } // namespace jit
858 : } // namespace js
859 :
860 : #endif /* jit_JitFrameIterator_h */
|