Bug 1885489 - Part 6: Add SnapshotIterator::readNumber(). r=iain
[gecko.git] / js / src / jit / JSJitFrameIter.h
blobe6b5cd3bfca2aee8825b31e64afd0d1bfad6845d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #ifndef jit_JSJitFrameIter_h
8 #define jit_JSJitFrameIter_h
10 #include "mozilla/Maybe.h"
12 #include "jstypes.h"
14 #include "jit/JitCode.h"
15 #include "jit/MachineState.h"
16 #include "jit/Snapshots.h"
17 #include "js/ProfilingFrameIterator.h"
18 #include "vm/JSFunction.h"
19 #include "vm/JSScript.h"
21 namespace js {
23 class ArgumentsObject;
25 namespace jit {
27 enum class FrameType {
28 // A JS frame is analogous to a js::InterpreterFrame, representing one
29 // scripted function activation. IonJS frames are used by the optimizing
30 // compiler.
31 IonJS,
33 // JS frame used by the Baseline Interpreter and Baseline JIT.
34 BaselineJS,
36 // Frame pushed by Baseline stubs that make non-tail calls, so that the
37 // return address -> ICEntry mapping works.
38 BaselineStub,
40 // The entry frame is the initial prologue block transitioning from the VM
41 // into the Ion world.
42 CppToJSJit,
44 // This entry frame sits right before the baseline interpreter
45 // so that external profilers can identify which function is being
46 // interpreted. Only used under the --emit-interpreter-entry option.
47 BaselineInterpreterEntry,
49 // A rectifier frame sits in between two JS frames, adapting argc != nargs
50 // mismatches in calls.
51 Rectifier,
53 // Ion IC calling a scripted getter/setter or a VMFunction.
54 IonICCall,
56 // An exit frame is necessary for transitioning from a JS frame into C++.
57 // From within C++, an exit frame is always the last frame in any
58 // JitActivation.
59 Exit,
61 // A bailout frame is a special IonJS jit frame after a bailout, and before
62 // the reconstruction of the BaselineJS frame. From within C++, a bailout
63 // frame is always the last frame in a JitActivation iff the bailout frame
64 // information is recorded on the JitActivation.
65 Bailout,
67 // A wasm to JS frame is constructed during fast calls from wasm to the JS
68 // jits, used as a marker to interleave JS jit and wasm frames. From the
69 // point of view of JS JITs, this is just another kind of entry frame.
70 WasmToJSJit,
72 // A JS to wasm frame is constructed during fast calls from any JS jits to
73 // wasm, and is a special kind of exit frame that doesn't have the exit
74 // footer. From the point of view of the jit, it can be skipped as an exit.
75 JSJitToWasm,
77 // Frame for a TrampolineNative, a JS builtin implemented with a JIT
78 // trampoline. See jit/TrampolineNatives.h.
79 TrampolineNative,
82 enum class ReadFrameArgsBehavior {
83 // Read all actual arguments. Will invoke the callback numActualArgs times.
84 Actuals,
86 // Read all argument values in the stack frame. Will invoke the callback
87 // max(numFormalArgs, numActualArgs) times.
88 ActualsAndFormals,
91 class CommonFrameLayout;
92 class JitFrameLayout;
93 class ExitFrameLayout;
95 class BaselineFrame;
96 class JitActivation;
97 class SafepointIndex;
98 class OsiIndex;
100 // Iterate over the JIT stack to assert that all invariants are respected.
101 // - Check that all entry frames are aligned on JitStackAlignment.
102 // - Check that all rectifier frames keep the JitStackAlignment.
104 void AssertJitStackInvariants(JSContext* cx);
106 // A JSJitFrameIter can iterate over a linear frame group of JS jit frames
107 // only. It will stop at the first frame that is not of the same kind, or at
108 // the end of an activation.
110 // If you want to handle every kind of frames (including wasm frames), use
111 // JitFrameIter. If you want to skip interleaved frames of other kinds, use
112 // OnlyJSJitFrameIter.
114 class JSJitFrameIter {
115 protected:
116 uint8_t* current_;
117 FrameType type_;
118 uint8_t* resumePCinCurrentFrame_;
120 // Size of the current Baseline frame. Equivalent to
121 // BaselineFrame::debugFrameSize_ in debug builds.
122 mozilla::Maybe<uint32_t> baselineFrameSize_;
124 private:
125 mutable const SafepointIndex* cachedSafepointIndex_;
126 const JitActivation* activation_;
128 void dumpBaseline() const;
130 public:
131 // See comment above the class.
132 explicit JSJitFrameIter(const JitActivation* activation);
134 // A constructor specialized for jit->wasm frames, which starts at a
135 // specific FP.
136 JSJitFrameIter(const JitActivation* activation, FrameType frameType,
137 uint8_t* fp);
139 void setResumePCInCurrentFrame(uint8_t* newAddr) {
140 resumePCinCurrentFrame_ = newAddr;
143 // Current frame information.
144 FrameType type() const { return type_; }
145 uint8_t* fp() const { return current_; }
146 const JitActivation* activation() const { return activation_; }
148 CommonFrameLayout* current() const { return (CommonFrameLayout*)current_; }
150 inline uint8_t* returnAddress() const;
152 // Return the pointer of the JitFrame, the iterator is assumed to be settled
153 // on a scripted frame.
154 JitFrameLayout* jsFrame() const;
156 inline ExitFrameLayout* exitFrame() const;
158 // Returns whether the JS frame has been invalidated and, if so,
159 // places the invalidated Ion script in |ionScript|.
160 bool checkInvalidation(IonScript** ionScript) const;
161 bool checkInvalidation() const;
163 bool isExitFrame() const { return type_ == FrameType::Exit; }
164 bool isScripted() const {
165 return type_ == FrameType::BaselineJS || type_ == FrameType::IonJS ||
166 type_ == FrameType::Bailout;
168 bool isBaselineJS() const { return type_ == FrameType::BaselineJS; }
169 bool isIonScripted() const {
170 return type_ == FrameType::IonJS || type_ == FrameType::Bailout;
172 bool isIonJS() const { return type_ == FrameType::IonJS; }
173 bool isIonICCall() const { return type_ == FrameType::IonICCall; }
174 bool isBailoutJS() const { return type_ == FrameType::Bailout; }
175 bool isBaselineStub() const { return type_ == FrameType::BaselineStub; }
176 bool isBaselineInterpreterEntry() const {
177 return type_ == FrameType::BaselineInterpreterEntry;
179 bool isRectifier() const { return type_ == FrameType::Rectifier; }
180 bool isBareExit() const;
181 bool isUnwoundJitExit() const;
182 template <typename T>
183 bool isExitFrameLayout() const;
185 static bool isEntry(FrameType type) {
186 return type == FrameType::CppToJSJit || type == FrameType::WasmToJSJit;
188 bool isEntry() const { return isEntry(type_); }
190 bool isFunctionFrame() const;
192 bool isConstructing() const;
194 void* calleeToken() const;
195 JSFunction* callee() const;
196 JSFunction* maybeCallee() const;
197 unsigned numActualArgs() const;
198 JSScript* script() const;
199 JSScript* maybeForwardedScript() const;
200 void baselineScriptAndPc(JSScript** scriptRes, jsbytecode** pcRes) const;
201 Value* actualArgs() const;
203 // Returns the address of the next instruction that will execute in this
204 // frame, once control returns to this frame.
205 uint8_t* resumePCinCurrentFrame() const { return resumePCinCurrentFrame_; }
207 // Previous frame information extracted from the current frame.
208 inline FrameType prevType() const;
209 uint8_t* prevFp() const;
211 // Functions used to iterate on frames. When prevType is an entry,
212 // the current frame is the last JS Jit frame.
213 bool done() const { return isEntry(); }
214 void operator++();
216 // Returns the IonScript associated with this JS frame.
217 IonScript* ionScript() const;
219 // Returns the IonScript associated with this JS frame; the frame must
220 // not be invalidated.
221 IonScript* ionScriptFromCalleeToken() const;
223 // Returns the Safepoint associated with this JS frame. Incurs a lookup
224 // overhead.
225 const SafepointIndex* safepoint() const;
227 // Returns the OSI index associated with this JS frame. Incurs a lookup
228 // overhead.
229 const OsiIndex* osiIndex() const;
231 // Returns the Snapshot offset associated with this JS frame. Incurs a
232 // lookup overhead.
233 SnapshotOffset snapshotOffset() const;
235 uintptr_t* spillBase() const;
236 MachineState machineState() const;
238 template <class Op>
239 void unaliasedForEachActual(Op op) const {
240 MOZ_ASSERT(isBaselineJS());
242 unsigned nactual = numActualArgs();
243 Value* argv = actualArgs();
244 for (unsigned i = 0; i < nactual; i++) {
245 op(argv[i]);
249 void dump() const;
251 inline BaselineFrame* baselineFrame() const;
253 // Returns the number of local and expression stack Values for the current
254 // Baseline frame.
255 inline uint32_t baselineFrameNumValueSlots() const;
257 // This function isn't used, but we keep it here (debug-only) because it is
258 // helpful when chasing issues with the jitcode map.
259 #ifdef DEBUG
260 bool verifyReturnAddressUsingNativeToBytecodeMap();
261 #else
262 bool verifyReturnAddressUsingNativeToBytecodeMap() { return true; }
263 #endif
266 class JitcodeGlobalTable;
268 class JSJitProfilingFrameIterator {
269 uint8_t* fp_;
270 // See JS::ProfilingFrameIterator::endStackAddress_ comment.
271 void* endStackAddress_ = nullptr;
272 FrameType type_;
273 void* resumePCinCurrentFrame_;
275 inline JSScript* frameScript() const;
276 [[nodiscard]] bool tryInitWithPC(void* pc);
277 [[nodiscard]] bool tryInitWithTable(JitcodeGlobalTable* table, void* pc,
278 bool forLastCallSite);
280 void moveToNextFrame(CommonFrameLayout* frame);
282 public:
283 JSJitProfilingFrameIterator(JSContext* cx, void* pc, void* sp);
284 explicit JSJitProfilingFrameIterator(CommonFrameLayout* exitFP);
286 void operator++();
287 bool done() const { return fp_ == nullptr; }
289 const char* baselineInterpreterLabel() const;
290 void baselineInterpreterScriptPC(JSScript** script, jsbytecode** pc,
291 uint64_t* realmID) const;
293 void* fp() const {
294 MOZ_ASSERT(!done());
295 return fp_;
297 inline JitFrameLayout* framePtr() const;
298 void* stackAddress() const { return fp(); }
299 FrameType frameType() const {
300 MOZ_ASSERT(!done());
301 return type_;
303 void* resumePCinCurrentFrame() const {
304 MOZ_ASSERT(!done());
305 return resumePCinCurrentFrame_;
308 void* endStackAddress() const { return endStackAddress_; }
311 class RInstructionResults {
312 // Vector of results of recover instructions.
313 typedef mozilla::Vector<HeapPtr<Value>, 1, SystemAllocPolicy> Values;
314 UniquePtr<Values> results_;
316 // The frame pointer is used as a key to check if the current frame already
317 // bailed out.
318 JitFrameLayout* fp_;
320 // Record if we tried and succeed at allocating and filling the vector of
321 // recover instruction results, if needed. This flag is needed in order to
322 // avoid evaluating the recover instruction twice.
323 bool initialized_;
325 public:
326 explicit RInstructionResults(JitFrameLayout* fp);
327 RInstructionResults(RInstructionResults&& src);
329 RInstructionResults& operator=(RInstructionResults&& rhs);
331 ~RInstructionResults();
333 [[nodiscard]] bool init(JSContext* cx, uint32_t numResults);
334 bool isInitialized() const;
335 size_t length() const;
337 JitFrameLayout* frame() const;
339 HeapPtr<Value>& operator[](size_t index);
341 void trace(JSTracer* trc);
344 struct MaybeReadFallback {
345 enum FallbackConsequence { Fallback_Invalidate, Fallback_DoNothing };
347 JSContext* maybeCx = nullptr;
348 JitActivation* activation = nullptr;
349 const JSJitFrameIter* frame = nullptr;
350 const FallbackConsequence consequence = Fallback_Invalidate;
352 MaybeReadFallback() = default;
354 MaybeReadFallback(JSContext* cx, JitActivation* activation,
355 const JSJitFrameIter* frame,
356 FallbackConsequence consequence = Fallback_Invalidate)
357 : maybeCx(cx),
358 activation(activation),
359 frame(frame),
360 consequence(consequence) {}
362 bool canRecoverResults() { return maybeCx; }
365 class RResumePoint;
367 // Reads frame information in snapshot-encoding order (that is, outermost frame
368 // to innermost frame).
369 class SnapshotIterator {
370 protected:
371 SnapshotReader snapshot_;
372 RecoverReader recover_;
373 JitFrameLayout* fp_;
374 const MachineState* machine_;
375 IonScript* ionScript_;
376 RInstructionResults* instructionResults_;
378 enum class ReadMethod : bool {
379 // Read the normal value.
380 Normal,
382 // Read the default value, or the normal value if there is no default.
383 AlwaysDefault,
386 private:
387 // Read a spilled register from the machine state.
388 bool hasRegister(Register reg) const { return machine_->has(reg); }
389 uintptr_t fromRegister(Register reg) const { return machine_->read(reg); }
391 bool hasRegister(FloatRegister reg) const { return machine_->has(reg); }
392 template <typename T>
393 T fromRegister(FloatRegister reg) const {
394 return machine_->read<T>(reg);
397 // Read an uintptr_t from the stack.
398 bool hasStack(int32_t offset) const { return true; }
399 uintptr_t fromStack(int32_t offset) const;
401 bool hasInstructionResult(uint32_t index) const {
402 return instructionResults_;
404 bool hasInstructionResults() const { return instructionResults_; }
405 Value fromInstructionResult(uint32_t index) const;
407 Value allocationValue(const RValueAllocation& a,
408 ReadMethod rm = ReadMethod::Normal);
409 [[nodiscard]] bool allocationReadable(const RValueAllocation& a,
410 ReadMethod rm = ReadMethod::Normal);
411 void writeAllocationValuePayload(const RValueAllocation& a, const Value& v);
412 void warnUnreadableAllocation();
414 public:
415 // Handle iterating over RValueAllocations of the snapshots.
416 inline RValueAllocation readAllocation() {
417 MOZ_ASSERT(moreAllocations());
418 return snapshot_.readAllocation();
420 void skip() { snapshot_.skipAllocation(); }
422 const RResumePoint* resumePoint() const;
423 const RInstruction* instruction() const { return recover_.instruction(); }
425 uint32_t numAllocations() const;
426 inline bool moreAllocations() const {
427 return snapshot_.numAllocationsRead() < numAllocations();
430 JitFrameLayout* frame() { return fp_; };
432 // Used by recover instruction to store the value back into the instruction
433 // results array.
434 void storeInstructionResult(const Value& v);
436 public:
437 // Exhibits frame properties contained in the snapshot.
438 uint32_t pcOffset() const;
439 ResumeMode resumeMode() const;
441 bool resumeAfter() const {
442 // Calls in outer frames are never considered resume-after.
443 MOZ_ASSERT_IF(moreFrames(), !IsResumeAfter(resumeMode()));
444 return IsResumeAfter(resumeMode());
446 inline BailoutKind bailoutKind() const { return snapshot_.bailoutKind(); }
448 IonScript* ionScript() const { return ionScript_; }
450 public:
451 // Read the next instruction available and get ready to either skip it or
452 // evaluate it.
453 inline void nextInstruction() {
454 MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations());
455 recover_.nextInstruction();
456 snapshot_.resetNumAllocationsRead();
459 // Skip an Instruction by walking to the next instruction and by skipping
460 // all the allocations corresponding to this instruction.
461 void skipInstruction();
463 inline bool moreInstructions() const { return recover_.moreInstructions(); }
465 // Register a vector used for storing the results of the evaluation of
466 // recover instructions. This vector should be registered before the
467 // beginning of the iteration. This function is in charge of allocating
468 // enough space for all instructions results, and return false iff it fails.
469 [[nodiscard]] bool initInstructionResults(MaybeReadFallback& fallback);
471 protected:
472 // This function is used internally for computing the result of the recover
473 // instructions.
474 [[nodiscard]] bool computeInstructionResults(
475 JSContext* cx, RInstructionResults* results) const;
477 public:
478 // Handle iterating over frames of the snapshots.
479 void nextFrame();
480 void settleOnFrame();
482 inline bool moreFrames() const {
483 // The last instruction is recovering the innermost frame, so as long as
484 // there is more instruction there is necesseray more frames.
485 return moreInstructions();
488 public:
489 // Connect all informations about the current script in order to recover the
490 // content of baseline frames.
492 SnapshotIterator(const JSJitFrameIter& iter,
493 const MachineState* machineState);
494 SnapshotIterator();
496 Value read() { return allocationValue(readAllocation()); }
498 int32_t readInt32() {
499 Value val = read();
500 MOZ_RELEASE_ASSERT(val.isInt32());
501 return val.toInt32();
504 double readNumber() {
505 Value val = read();
506 MOZ_RELEASE_ASSERT(val.isNumber());
507 return val.toNumber();
510 // Read the |Normal| value unless it is not available and that the snapshot
511 // provides a |Default| value. This is useful to avoid invalidations of the
512 // frame while we are only interested in a few properties which are provided
513 // by the |Default| value.
514 Value readWithDefault(RValueAllocation* alloc) {
515 *alloc = RValueAllocation();
516 RValueAllocation a = readAllocation();
517 if (allocationReadable(a)) {
518 return allocationValue(a);
521 *alloc = a;
522 return allocationValue(a, ReadMethod::AlwaysDefault);
525 Value maybeRead(const RValueAllocation& a, MaybeReadFallback& fallback);
526 Value maybeRead(MaybeReadFallback& fallback) {
527 RValueAllocation a = readAllocation();
528 return maybeRead(a, fallback);
531 bool tryRead(Value* result);
533 void traceAllocation(JSTracer* trc);
535 template <class Op>
536 void readFunctionFrameArgs(Op& op, ArgumentsObject** argsObj, Value* thisv,
537 unsigned start, unsigned end, JSScript* script,
538 MaybeReadFallback& fallback) {
539 // Assumes that the common frame arguments have already been read.
540 if (script->needsArgsObj()) {
541 if (argsObj) {
542 Value v = maybeRead(fallback);
543 if (v.isObject()) {
544 *argsObj = &v.toObject().as<ArgumentsObject>();
546 } else {
547 skip();
551 if (thisv) {
552 *thisv = maybeRead(fallback);
553 } else {
554 skip();
557 unsigned i = 0;
558 if (end < start) {
559 i = start;
562 for (; i < start; i++) {
563 skip();
565 for (; i < end; i++) {
566 // We are not always able to read values from the snapshots, some values
567 // such as non-gc things may still be live in registers and cause an
568 // error while reading the machine state.
569 Value v = maybeRead(fallback);
570 op(v);
574 // Iterate over all the allocations and return only the value of the
575 // allocation located at one index.
576 Value maybeReadAllocByIndex(size_t index);
578 #ifdef TRACK_SNAPSHOTS
579 void spewBailingFrom() const { snapshot_.spewBailingFrom(); }
580 #endif
583 // Reads frame information in callstack order (that is, innermost frame to
584 // outermost frame).
585 class InlineFrameIterator {
586 const JSJitFrameIter* frame_;
587 SnapshotIterator start_;
588 SnapshotIterator si_;
589 uint32_t framesRead_;
591 // When the inline-frame-iterator is created, this variable is defined to
592 // UINT32_MAX. Then the first iteration of findNextFrame, which settle on
593 // the innermost frame, is used to update this counter to the number of
594 // frames contained in the recover buffer.
595 uint32_t frameCount_;
597 // The |calleeTemplate_| fields contains either the JSFunction or the
598 // template from which it is supposed to be cloned. The |calleeRVA_| is an
599 // Invalid value allocation, if the |calleeTemplate_| field is the effective
600 // JSFunction, and not its template. On the other hand, any other value
601 // allocation implies that the |calleeTemplate_| is the template JSFunction
602 // from which the effective one would be derived and cached by the Recover
603 // instruction result.
604 RootedFunction calleeTemplate_;
605 RValueAllocation calleeRVA_;
607 RootedScript script_;
608 jsbytecode* pc_;
609 uint32_t numActualArgs_;
611 // Register state, used by all snapshot iterators.
612 MachineState machine_;
614 struct Nop {
615 void operator()(const Value& v) {}
618 private:
619 void findNextFrame();
620 JSObject* computeEnvironmentChain(const Value& envChainValue,
621 MaybeReadFallback& fallback,
622 bool* hasInitialEnv = nullptr) const;
624 public:
625 InlineFrameIterator(JSContext* cx, const JSJitFrameIter* iter);
626 InlineFrameIterator(JSContext* cx, const InlineFrameIterator* iter);
628 bool more() const { return frame_ && framesRead_ < frameCount_; }
630 // Due to optimizations, we are not always capable of reading the callee of
631 // inlined frames without invalidating the IonCode. This function might
632 // return either the effective callee of the JSFunction which might be used
633 // to create it.
635 // As such, the |calleeTemplate()| can be used to read most of the metadata
636 // which are conserved across clones.
637 JSFunction* calleeTemplate() const {
638 MOZ_ASSERT(isFunctionFrame());
639 return calleeTemplate_;
641 JSFunction* maybeCalleeTemplate() const { return calleeTemplate_; }
643 JSFunction* callee(MaybeReadFallback& fallback) const;
645 unsigned numActualArgs() const {
646 // The number of actual arguments for inline frames is determined by this
647 // iterator based on the caller's bytecode instruction (Call, FunCall,
648 // GetProp/SetProp, etc). For the outer function it's stored in the stack
649 // frame.
650 if (more()) {
651 return numActualArgs_;
654 return frame_->numActualArgs();
657 template <class ArgOp, class LocalOp>
658 void readFrameArgsAndLocals(JSContext* cx, ArgOp& argOp, LocalOp& localOp,
659 JSObject** envChain, bool* hasInitialEnv,
660 Value* rval, ArgumentsObject** argsObj,
661 Value* thisv, ReadFrameArgsBehavior behavior,
662 MaybeReadFallback& fallback) const {
663 SnapshotIterator s(si_);
665 // Read the env chain.
666 if (envChain) {
667 Value envChainValue = s.maybeRead(fallback);
668 *envChain =
669 computeEnvironmentChain(envChainValue, fallback, hasInitialEnv);
670 } else {
671 s.skip();
674 // Read return value.
675 if (rval) {
676 *rval = s.maybeRead(fallback);
677 } else {
678 s.skip();
681 // Read arguments, which only function frames have.
682 if (isFunctionFrame()) {
683 unsigned nactual = numActualArgs();
684 unsigned nformal = calleeTemplate()->nargs();
686 // Read the formal arguments, which are taken from the inlined frame,
687 // because it will have the updated value when JSOp::SetArg is used.
688 unsigned numFormalsToRead;
689 if (behavior == ReadFrameArgsBehavior::Actuals) {
690 numFormalsToRead = std::min(nactual, nformal);
691 } else {
692 MOZ_ASSERT(behavior == ReadFrameArgsBehavior::ActualsAndFormals);
693 numFormalsToRead = nformal;
695 s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, numFormalsToRead,
696 script(), fallback);
698 // Skip formals we didn't read.
699 for (unsigned i = numFormalsToRead; i < nformal; i++) {
700 s.skip();
703 if (nactual > nformal) {
704 if (more()) {
705 // There is still a parent frame of this inlined frame. All
706 // arguments (also the overflown) are the last pushed values
707 // in the parent frame. To get the overflown arguments, we
708 // need to take them from there.
710 // The overflown arguments are not available in current frame.
711 // They are the last pushed arguments in the parent frame of
712 // this inlined frame.
713 InlineFrameIterator it(cx, this);
714 ++it;
715 unsigned argsObjAdj = it.script()->needsArgsObj() ? 1 : 0;
716 bool hasNewTarget = isConstructing();
717 SnapshotIterator parent_s(it.snapshotIterator());
719 // Skip over all slots until we get to the last slots
720 // (= arguments slots of callee) the +3 is for [this], [returnvalue],
721 // [envchain], and maybe +1 for [argsObj]
722 MOZ_ASSERT(parent_s.numAllocations() >=
723 nactual + 3 + argsObjAdj + hasNewTarget);
724 unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj -
725 hasNewTarget;
726 for (unsigned j = 0; j < skip; j++) {
727 parent_s.skip();
730 // Get the overflown arguments
731 parent_s.skip(); // env chain
732 parent_s.skip(); // return value
733 parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr, nformal,
734 nactual, it.script(), fallback);
735 } else {
736 // There is no parent frame to this inlined frame, we can read
737 // from the frame's Value vector directly.
738 Value* argv = frame_->actualArgs();
739 for (unsigned i = nformal; i < nactual; i++) {
740 argOp(argv[i]);
746 // At this point we've read all the formals in s, and can read the
747 // locals.
748 for (unsigned i = 0; i < script()->nfixed(); i++) {
749 localOp(s.maybeRead(fallback));
753 template <class Op>
754 void unaliasedForEachActual(JSContext* cx, Op op,
755 MaybeReadFallback& fallback) const {
756 Nop nop;
757 readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr,
758 nullptr, ReadFrameArgsBehavior::Actuals, fallback);
761 JSScript* script() const { return script_; }
762 jsbytecode* pc() const { return pc_; }
763 SnapshotIterator snapshotIterator() const { return si_; }
764 bool isFunctionFrame() const;
765 bool isModuleFrame() const;
766 bool isConstructing() const;
768 JSObject* environmentChain(MaybeReadFallback& fallback,
769 bool* hasInitialEnvironment = nullptr) const {
770 SnapshotIterator s(si_);
772 // envChain
773 Value v = s.maybeRead(fallback);
774 return computeEnvironmentChain(v, fallback, hasInitialEnvironment);
777 Value thisArgument(MaybeReadFallback& fallback) const {
778 SnapshotIterator s(si_);
780 // envChain
781 s.skip();
783 // return value
784 s.skip();
786 // Arguments object.
787 if (script()->needsArgsObj()) {
788 s.skip();
791 return s.maybeRead(fallback);
794 InlineFrameIterator& operator++() {
795 findNextFrame();
796 return *this;
799 void dump() const;
801 void resetOn(const JSJitFrameIter* iter);
803 const JSJitFrameIter& frame() const { return *frame_; }
805 // Inline frame number, 0 for the outermost (non-inlined) frame.
806 size_t frameNo() const { return frameCount() - framesRead_; }
807 size_t frameCount() const {
808 MOZ_ASSERT(frameCount_ != UINT32_MAX);
809 return frameCount_;
812 private:
813 InlineFrameIterator() = delete;
814 InlineFrameIterator(const InlineFrameIterator& iter) = delete;
817 } // namespace jit
818 } // namespace js
820 #endif /* jit_JSJitFrameIter_h */