LCOV - code coverage report
Current view: top level - js/src/jit - JitFrameIterator.h (source / functions) Hit Total Coverage
Test: output.info Lines: 52 232 22.4 %
Date: 2017-07-14 16:53:18 Functions: 27 77 35.1 %
Legend: Lines: hit not hit

          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 */

Generated by: LCOV version 1.13