js/src/jit/JitFrameIterator.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #ifndef jit_JitFrameIterator_h
     8 #define jit_JitFrameIterator_h
    10 #ifdef JS_ION
    12 #include "jsfun.h"
    13 #include "jsscript.h"
    14 #include "jstypes.h"
    16 #include "jit/IonCode.h"
    17 #include "jit/Snapshots.h"
    19 namespace js {
    20     class ActivationIterator;
    21 };
    23 namespace js {
    24 namespace jit {
    26 enum FrameType
    27 {
    28     // A JS frame is analagous to a js::InterpreterFrame, representing one scripted
    29     // functon activation. IonJS frames are used by the optimizing compiler.
    30     JitFrame_IonJS,
    32     // JS frame used by the baseline JIT.
    33     JitFrame_BaselineJS,
    35     // Frame pushed for baseline JIT stubs that make non-tail calls, so that the
    36     // return address -> ICEntry mapping works.
    37     JitFrame_BaselineStub,
    39     // The entry frame is the initial prologue block transitioning from the VM
    40     // into the Ion world.
    41     JitFrame_Entry,
    43     // A rectifier frame sits in between two JS frames, adapting argc != nargs
    44     // mismatches in calls.
    45     JitFrame_Rectifier,
    47     // An unwound JS frame is a JS frame signalling that its callee frame has been
    48     // turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and
    49     // Baseline exception unwinding.
    50     JitFrame_Unwound_IonJS,
    52     // Like Unwound_IonJS, but the caller is a baseline stub frame.
    53     JitFrame_Unwound_BaselineStub,
    55     // An unwound rectifier frame is a rectifier frame signalling that its callee
    56     // frame has been turned into an exit frame (see EnsureExitFrame).
    57     JitFrame_Unwound_Rectifier,
    59     // An exit frame is necessary for transitioning from a JS frame into C++.
    60     // From within C++, an exit frame is always the last frame in any
    61     // JitActivation.
    62     JitFrame_Exit
    63 };
    65 enum ReadFrameArgsBehavior {
    66     // Only read formals (i.e. [0 ... callee()->nargs]
    67     ReadFrame_Formals,
    69     // Only read overflown args (i.e. [callee()->nargs ... numActuals()]
    70     ReadFrame_Overflown,
    72     // Read all args (i.e. [0 ... numActuals()])
    73     ReadFrame_Actuals
    74 };
    76 class IonCommonFrameLayout;
    77 class IonJSFrameLayout;
    78 class IonExitFrameLayout;
    80 class BaselineFrame;
    82 class JitActivation;
    84 class JitFrameIterator
    85 {
    86   protected:
    87     uint8_t *current_;
    88     FrameType type_;
    89     uint8_t *returnAddressToFp_;
    90     size_t frameSize_;
    92   private:
    93     mutable const SafepointIndex *cachedSafepointIndex_;
    94     const JitActivation *activation_;
    95     ExecutionMode mode_;
    97     void dumpBaseline() const;
    99   public:
   100     explicit JitFrameIterator(uint8_t *top, ExecutionMode mode)
   101       : current_(top),
   102         type_(JitFrame_Exit),
   103         returnAddressToFp_(nullptr),
   104         frameSize_(0),
   105         cachedSafepointIndex_(nullptr),
   106         activation_(nullptr),
   107         mode_(mode)
   108     { }
   110     explicit JitFrameIterator(JSContext *cx);
   111     explicit JitFrameIterator(const ActivationIterator &activations);
   112     explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
   114     // Current frame information.
   115     FrameType type() const {
   116         return type_;
   117     }
   118     uint8_t *fp() const {
   119         return current_;
   120     }
   121     const JitActivation *activation() const {
   122         return activation_;
   123     }
   125     IonCommonFrameLayout *current() const {
   126         return (IonCommonFrameLayout *)current_;
   127     }
   129     inline uint8_t *returnAddress() const;
   131     IonJSFrameLayout *jsFrame() const {
   132         JS_ASSERT(isScripted());
   133         return (IonJSFrameLayout *) fp();
   134     }
   136     // Returns true iff this exit frame was created using EnsureExitFrame.
   137     inline bool isFakeExitFrame() const;
   139     inline IonExitFrameLayout *exitFrame() const;
   141     // Returns whether the JS frame has been invalidated and, if so,
   142     // places the invalidated Ion script in |ionScript|.
   143     bool checkInvalidation(IonScript **ionScript) const;
   144     bool checkInvalidation() const;
   146     bool isScripted() const {
   147         return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS;
   148     }
   149     bool isBaselineJS() const {
   150         return type_ == JitFrame_BaselineJS;
   151     }
   152     bool isIonJS() const {
   153         return type_ == JitFrame_IonJS;
   154     }
   155     bool isBaselineStub() const {
   156         return type_ == JitFrame_BaselineStub;
   157     }
   158     bool isNative() const;
   159     bool isOOLNative() const;
   160     bool isOOLPropertyOp() const;
   161     bool isOOLProxy() const;
   162     bool isDOMExit() const;
   163     bool isEntry() const {
   164         return type_ == JitFrame_Entry;
   165     }
   166     bool isFunctionFrame() const;
   168     bool isConstructing() const;
   170     void *calleeToken() const;
   171     JSFunction *callee() const;
   172     JSFunction *maybeCallee() const;
   173     unsigned numActualArgs() const;
   174     JSScript *script() const;
   175     void baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const;
   176     Value *actualArgs() const;
   178     // Returns the return address of the frame above this one (that is, the
   179     // return address that returns back to the current frame).
   180     uint8_t *returnAddressToFp() const {
   181         return returnAddressToFp_;
   182     }
   184     // Previous frame information extracted from the current frame.
   185     inline size_t prevFrameLocalSize() const;
   186     inline FrameType prevType() const;
   187     uint8_t *prevFp() const;
   189     // Returns the stack space used by the current frame, in bytes. This does
   190     // not include the size of its fixed header.
   191     size_t frameSize() const {
   192         JS_ASSERT(type_ != JitFrame_Exit);
   193         return frameSize_;
   194     }
   196     // Functions used to iterate on frames. When prevType is JitFrame_Entry,
   197     // the current frame is the last frame.
   198     inline bool done() const {
   199         return type_ == JitFrame_Entry;
   200     }
   201     JitFrameIterator &operator++();
   203     // Returns the IonScript associated with this JS frame.
   204     IonScript *ionScript() const;
   206     // Returns the Safepoint associated with this JS frame. Incurs a lookup
   207     // overhead.
   208     const SafepointIndex *safepoint() const;
   210     // Returns the OSI index associated with this JS frame. Incurs a lookup
   211     // overhead.
   212     const OsiIndex *osiIndex() const;
   214     uintptr_t *spillBase() const;
   215     MachineState machineState() const;
   217     template <class Op>
   218     void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const {
   219         JS_ASSERT(isBaselineJS());
   221         unsigned nactual = numActualArgs();
   222         unsigned start, end;
   223         switch (behavior) {
   224           case ReadFrame_Formals:
   225             start = 0;
   226             end = callee()->nargs();
   227             break;
   228           case ReadFrame_Overflown:
   229             start = callee()->nargs();
   230             end = nactual;
   231             break;
   232           case ReadFrame_Actuals:
   233             start = 0;
   234             end = nactual;
   235         }
   237         Value *argv = actualArgs();
   238         for (unsigned i = start; i < end; i++)
   239             op(argv[i]);
   240     }
   242     void dump() const;
   244     inline BaselineFrame *baselineFrame() const;
   245 };
   247 class IonJSFrameLayout;
   248 class IonBailoutIterator;
   250 class RResumePoint;
   252 // Reads frame information in snapshot-encoding order (that is, outermost frame
   253 // to innermost frame).
   254 class SnapshotIterator
   255 {
   256     SnapshotReader snapshot_;
   257     RecoverReader recover_;
   258     IonJSFrameLayout *fp_;
   259     MachineState machine_;
   260     IonScript *ionScript_;
   262   private:
   263     // Read a spilled register from the machine state.
   264     bool hasRegister(Register reg) const {
   265         return machine_.has(reg);
   266     }
   267     uintptr_t fromRegister(Register reg) const {
   268         return machine_.read(reg);
   269     }
   271     bool hasRegister(FloatRegister reg) const {
   272         return machine_.has(reg);
   273     }
   274     double fromRegister(FloatRegister reg) const {
   275         return machine_.read(reg);
   276     }
   278     // Read an uintptr_t from the stack.
   279     bool hasStack(int32_t offset) const {
   280         return true;
   281     }
   282     uintptr_t fromStack(int32_t offset) const;
   284     Value allocationValue(const RValueAllocation &a);
   285     bool allocationReadable(const RValueAllocation &a);
   286     void warnUnreadableAllocation();
   288   public:
   289     // Handle iterating over RValueAllocations of the snapshots.
   290     inline RValueAllocation readAllocation() {
   291         MOZ_ASSERT(moreAllocations());
   292         return snapshot_.readAllocation();
   293     }
   294     Value skip() {
   295         snapshot_.skipAllocation();
   296         return UndefinedValue();
   297     }
   299     const RResumePoint *resumePoint() const;
   300     const RInstruction *instruction() const {
   301         return recover_.instruction();
   302     }
   304     uint32_t numAllocations() const;
   305     inline bool moreAllocations() const {
   306         return snapshot_.numAllocationsRead() < numAllocations();
   307     }
   309   public:
   310     // Exhibits frame properties contained in the snapshot.
   311     uint32_t pcOffset() const;
   312     inline bool resumeAfter() const {
   313         // Inline frames are inlined on calls, which are considered as being
   314         // resumed on the Call as baseline will push the pc once we return from
   315         // the call.
   316         if (moreFrames())
   317             return false;
   318         return recover_.resumeAfter();
   319     }
   320     inline BailoutKind bailoutKind() const {
   321         return snapshot_.bailoutKind();
   322     }
   324   public:
   325     // Read the next instruction available and get ready to either skip it or
   326     // evaluate it.
   327     inline void nextInstruction() {
   328         MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations());
   329         recover_.nextInstruction();
   330         snapshot_.resetNumAllocationsRead();
   331     }
   333     // Skip an Instruction by walking to the next instruction and by skipping
   334     // all the allocations corresponding to this instruction.
   335     void skipInstruction();
   337     inline bool moreInstructions() const {
   338         return recover_.moreInstructions();
   339     }
   341   public:
   342     // Handle iterating over frames of the snapshots.
   343     void nextFrame();
   345     inline bool moreFrames() const {
   346         // The last instruction is recovering the innermost frame, so as long as
   347         // there is more instruction there is necesseray more frames.
   348         return moreInstructions();
   349     }
   351   public:
   352     // Connect all informations about the current script in order to recover the
   353     // content of baseline frames.
   355     SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
   356                      IonJSFrameLayout *fp, const MachineState &machine);
   357     SnapshotIterator(const JitFrameIterator &iter);
   358     SnapshotIterator(const IonBailoutIterator &iter);
   359     SnapshotIterator();
   361     Value read() {
   362         return allocationValue(readAllocation());
   363     }
   364     Value maybeRead(bool silentFailure = false) {
   365         RValueAllocation a = readAllocation();
   366         if (allocationReadable(a))
   367             return allocationValue(a);
   368         if (!silentFailure)
   369             warnUnreadableAllocation();
   370         return UndefinedValue();
   371     }
   373     void readCommonFrameSlots(Value *scopeChain, Value *rval) {
   374         if (scopeChain)
   375             *scopeChain = read();
   376         else
   377             skip();
   379         if (rval)
   380             *rval = read();
   381         else
   382             skip();
   383     }
   385     template <class Op>
   386     void readFunctionFrameArgs(Op &op, ArgumentsObject **argsObj, Value *thisv,
   387                                unsigned start, unsigned end, JSScript *script)
   388     {
   389         // Assumes that the common frame arguments have already been read.
   390         if (script->argumentsHasVarBinding()) {
   391             if (argsObj) {
   392                 Value v = read();
   393                 if (v.isObject())
   394                     *argsObj = &v.toObject().as<ArgumentsObject>();
   395             } else {
   396                 skip();
   397             }
   398         }
   400         if (thisv)
   401             *thisv = read();
   402         else
   403             skip();
   405         unsigned i = 0;
   406         if (end < start)
   407             i = start;
   409         for (; i < start; i++)
   410             skip();
   411         for (; i < end; i++) {
   412             // We are not always able to read values from the snapshots, some values
   413             // such as non-gc things may still be live in registers and cause an
   414             // error while reading the machine state.
   415             Value v = maybeRead();
   416             op(v);
   417         }
   418     }
   420     Value maybeReadAllocByIndex(size_t index) {
   421         while (index--) {
   422             JS_ASSERT(moreAllocations());
   423             skip();
   424         }
   426         Value s = maybeRead(true);
   428         while (moreAllocations())
   429             skip();
   431         return s;
   432     }
   433 };
   435 // Reads frame information in callstack order (that is, innermost frame to
   436 // outermost frame).
   437 template <AllowGC allowGC=CanGC>
   438 class InlineFrameIteratorMaybeGC
   439 {
   440     const JitFrameIterator *frame_;
   441     SnapshotIterator start_;
   442     SnapshotIterator si_;
   443     uint32_t framesRead_;
   445     // When the inline-frame-iterator is created, this variable is defined to
   446     // UINT32_MAX. Then the first iteration of findNextFrame, which settle on
   447     // the innermost frame, is used to update this counter to the number of
   448     // frames contained in the recover buffer.
   449     uint32_t frameCount_;
   451     typename MaybeRooted<JSFunction*, allowGC>::RootType callee_;
   452     typename MaybeRooted<JSScript*, allowGC>::RootType script_;
   453     jsbytecode *pc_;
   454     uint32_t numActualArgs_;
   456     struct Nop {
   457         void operator()(const Value &v) { }
   458     };
   460   private:
   461     void findNextFrame();
   463     JSObject *computeScopeChain(Value scopeChainValue) const {
   464         if (scopeChainValue.isObject())
   465             return &scopeChainValue.toObject();
   467         if (isFunctionFrame()) {
   468             // Heavyweight functions should always have a scope chain.
   469             MOZ_ASSERT(!callee()->isHeavyweight());
   470             return callee()->environment();
   471         }
   473         // Ion does not handle scripts that are not compile-and-go.
   474         MOZ_ASSERT(!script()->isForEval());
   475         MOZ_ASSERT(script()->compileAndGo());
   476         return &script()->global();
   477     }
   479   public:
   480     InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter)
   481       : callee_(cx),
   482         script_(cx)
   483     {
   484         resetOn(iter);
   485     }
   487     InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter)
   488       : callee_(rt),
   489         script_(rt)
   490     {
   491         resetOn(iter);
   492     }
   494     InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter);
   496     InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter)
   497       : frame_(iter ? iter->frame_ : nullptr),
   498         framesRead_(0),
   499         frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
   500         callee_(cx),
   501         script_(cx)
   502     {
   503         if (frame_) {
   504             start_ = SnapshotIterator(*frame_);
   505             // findNextFrame will iterate to the next frame and init. everything.
   506             // Therefore to settle on the same frame, we report one frame less readed.
   507             framesRead_ = iter->framesRead_ - 1;
   508             findNextFrame();
   509         }
   510     }
   512     bool more() const {
   513         return frame_ && framesRead_ < frameCount_;
   514     }
   515     JSFunction *callee() const {
   516         JS_ASSERT(callee_);
   517         return callee_;
   518     }
   519     JSFunction *maybeCallee() const {
   520         return callee_;
   521     }
   523     unsigned numActualArgs() const {
   524         // The number of actual arguments of inline frames is recovered by the
   525         // iteration process. It is recovered from the bytecode because this
   526         // property still hold since the for inlined frames. This property does not
   527         // hold for the parent frame because it can have optimize a call to
   528         // js_fun_call or js_fun_apply.
   529         if (more())
   530             return numActualArgs_;
   532         return frame_->numActualArgs();
   533     }
   535     template <class ArgOp, class LocalOp>
   536     void readFrameArgsAndLocals(JSContext *cx, ArgOp &argOp, LocalOp &localOp,
   537                                 JSObject **scopeChain, Value *rval,
   538                                 ArgumentsObject **argsObj, Value *thisv,
   539                                 ReadFrameArgsBehavior behavior) const
   540     {
   541         SnapshotIterator s(si_);
   543         // Read frame slots common to both function and global frames.
   544         Value scopeChainValue;
   545         s.readCommonFrameSlots(&scopeChainValue, rval);
   547         if (scopeChain)
   548             *scopeChain = computeScopeChain(scopeChainValue);
   550         // Read arguments, which only function frames have.
   551         if (isFunctionFrame()) {
   552             unsigned nactual = numActualArgs();
   553             unsigned nformal = callee()->nargs();
   555             // Get the non overflown arguments, which are taken from the inlined
   556             // frame, because it will have the updated value when JSOP_SETARG is
   557             // done.
   558             if (behavior != ReadFrame_Overflown)
   559                 s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, nformal, script());
   561             if (behavior != ReadFrame_Formals) {
   562                 if (more()) {
   563                     // There is still a parent frame of this inlined frame.  All
   564                     // arguments (also the overflown) are the last pushed values
   565                     // in the parent frame.  To get the overflown arguments, we
   566                     // need to take them from there.
   568                     // The overflown arguments are not available in current frame.
   569                     // They are the last pushed arguments in the parent frame of
   570                     // this inlined frame.
   571                     InlineFrameIteratorMaybeGC it(cx, this);
   572                     ++it;
   573                     unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
   574                     SnapshotIterator parent_s(it.snapshotIterator());
   576                     // Skip over all slots until we get to the last slots
   577                     // (= arguments slots of callee) the +3 is for [this], [returnvalue],
   578                     // [scopechain], and maybe +1 for [argsObj]
   579                     JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj);
   580                     unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj;
   581                     for (unsigned j = 0; j < skip; j++)
   582                         parent_s.skip();
   584                     // Get the overflown arguments
   585                     parent_s.readCommonFrameSlots(nullptr, nullptr);
   586                     parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr,
   587                                                    nformal, nactual, it.script());
   588                 } else {
   589                     // There is no parent frame to this inlined frame, we can read
   590                     // from the frame's Value vector directly.
   591                     Value *argv = frame_->actualArgs();
   592                     for (unsigned i = nformal; i < nactual; i++)
   593                         argOp(argv[i]);
   594                 }
   595             }
   596         }
   598         // At this point we've read all the formals in s, and can read the
   599         // locals.
   600         for (unsigned i = 0; i < script()->nfixed(); i++)
   601             localOp(s.read());
   602     }
   604     template <class Op>
   605     void unaliasedForEachActual(JSContext *cx, Op op, ReadFrameArgsBehavior behavior) const {
   606         Nop nop;
   607         readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior);
   608     }
   610     JSScript *script() const {
   611         return script_;
   612     }
   613     jsbytecode *pc() const {
   614         return pc_;
   615     }
   616     SnapshotIterator snapshotIterator() const {
   617         return si_;
   618     }
   619     bool isFunctionFrame() const;
   620     bool isConstructing() const;
   622     JSObject *scopeChain() const {
   623         SnapshotIterator s(si_);
   625         // scopeChain
   626         Value v = s.read();
   627         return computeScopeChain(v);
   628     }
   630     JSObject *thisObject() const {
   631         // In strict modes, |this| may not be an object and thus may not be
   632         // readable which can either segv in read or trigger the assertion.
   633         Value v = thisValue();
   634         JS_ASSERT(v.isObject());
   635         return &v.toObject();
   636     }
   638     Value thisValue() const {
   639         // JS_ASSERT(isConstructing(...));
   640         SnapshotIterator s(si_);
   642         // scopeChain
   643         s.skip();
   645         // return value
   646         s.skip();
   648         // Arguments object.
   649         if (script()->argumentsHasVarBinding())
   650             s.skip();
   652         return s.read();
   653     }
   655     InlineFrameIteratorMaybeGC &operator++() {
   656         findNextFrame();
   657         return *this;
   658     }
   660     void dump() const;
   662     void resetOn(const JitFrameIterator *iter);
   664     const JitFrameIterator &frame() const {
   665         return *frame_;
   666     }
   668     // Inline frame number, 0 for the outermost (non-inlined) frame.
   669     size_t frameNo() const {
   670         return frameCount() - framesRead_;
   671     }
   672     size_t frameCount() const {
   673         MOZ_ASSERT(frameCount_ != UINT32_MAX);
   674         return frameCount_;
   675     }
   677   private:
   678     InlineFrameIteratorMaybeGC() MOZ_DELETE;
   679     InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE;
   680 };
   681 typedef InlineFrameIteratorMaybeGC<CanGC> InlineFrameIterator;
   682 typedef InlineFrameIteratorMaybeGC<NoGC> InlineFrameIteratorNoGC;
   684 } // namespace jit
   685 } // namespace js
   687 #endif // JS_ION
   689 #endif /* jit_JitFrameIterator_h */

mercurial