js/src/jit/JitFrameIterator.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/JitFrameIterator.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,689 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef jit_JitFrameIterator_h
    1.11 +#define jit_JitFrameIterator_h
    1.12 +
    1.13 +#ifdef JS_ION
    1.14 +
    1.15 +#include "jsfun.h"
    1.16 +#include "jsscript.h"
    1.17 +#include "jstypes.h"
    1.18 +
    1.19 +#include "jit/IonCode.h"
    1.20 +#include "jit/Snapshots.h"
    1.21 +
    1.22 +namespace js {
    1.23 +    class ActivationIterator;
    1.24 +};
    1.25 +
    1.26 +namespace js {
    1.27 +namespace jit {
    1.28 +
    1.29 +enum FrameType
    1.30 +{
    1.31 +    // A JS frame is analagous to a js::InterpreterFrame, representing one scripted
    1.32 +    // functon activation. IonJS frames are used by the optimizing compiler.
    1.33 +    JitFrame_IonJS,
    1.34 +
    1.35 +    // JS frame used by the baseline JIT.
    1.36 +    JitFrame_BaselineJS,
    1.37 +
    1.38 +    // Frame pushed for baseline JIT stubs that make non-tail calls, so that the
    1.39 +    // return address -> ICEntry mapping works.
    1.40 +    JitFrame_BaselineStub,
    1.41 +
    1.42 +    // The entry frame is the initial prologue block transitioning from the VM
    1.43 +    // into the Ion world.
    1.44 +    JitFrame_Entry,
    1.45 +
    1.46 +    // A rectifier frame sits in between two JS frames, adapting argc != nargs
    1.47 +    // mismatches in calls.
    1.48 +    JitFrame_Rectifier,
    1.49 +
    1.50 +    // An unwound JS frame is a JS frame signalling that its callee frame has been
    1.51 +    // turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and
    1.52 +    // Baseline exception unwinding.
    1.53 +    JitFrame_Unwound_IonJS,
    1.54 +
    1.55 +    // Like Unwound_IonJS, but the caller is a baseline stub frame.
    1.56 +    JitFrame_Unwound_BaselineStub,
    1.57 +
    1.58 +    // An unwound rectifier frame is a rectifier frame signalling that its callee
    1.59 +    // frame has been turned into an exit frame (see EnsureExitFrame).
    1.60 +    JitFrame_Unwound_Rectifier,
    1.61 +
    1.62 +    // An exit frame is necessary for transitioning from a JS frame into C++.
    1.63 +    // From within C++, an exit frame is always the last frame in any
    1.64 +    // JitActivation.
    1.65 +    JitFrame_Exit
    1.66 +};
    1.67 +
    1.68 +enum ReadFrameArgsBehavior {
    1.69 +    // Only read formals (i.e. [0 ... callee()->nargs]
    1.70 +    ReadFrame_Formals,
    1.71 +
    1.72 +    // Only read overflown args (i.e. [callee()->nargs ... numActuals()]
    1.73 +    ReadFrame_Overflown,
    1.74 +
    1.75 +    // Read all args (i.e. [0 ... numActuals()])
    1.76 +    ReadFrame_Actuals
    1.77 +};
    1.78 +
    1.79 +class IonCommonFrameLayout;
    1.80 +class IonJSFrameLayout;
    1.81 +class IonExitFrameLayout;
    1.82 +
    1.83 +class BaselineFrame;
    1.84 +
    1.85 +class JitActivation;
    1.86 +
    1.87 +class JitFrameIterator
    1.88 +{
    1.89 +  protected:
    1.90 +    uint8_t *current_;
    1.91 +    FrameType type_;
    1.92 +    uint8_t *returnAddressToFp_;
    1.93 +    size_t frameSize_;
    1.94 +
    1.95 +  private:
    1.96 +    mutable const SafepointIndex *cachedSafepointIndex_;
    1.97 +    const JitActivation *activation_;
    1.98 +    ExecutionMode mode_;
    1.99 +
   1.100 +    void dumpBaseline() const;
   1.101 +
   1.102 +  public:
   1.103 +    explicit JitFrameIterator(uint8_t *top, ExecutionMode mode)
   1.104 +      : current_(top),
   1.105 +        type_(JitFrame_Exit),
   1.106 +        returnAddressToFp_(nullptr),
   1.107 +        frameSize_(0),
   1.108 +        cachedSafepointIndex_(nullptr),
   1.109 +        activation_(nullptr),
   1.110 +        mode_(mode)
   1.111 +    { }
   1.112 +
   1.113 +    explicit JitFrameIterator(JSContext *cx);
   1.114 +    explicit JitFrameIterator(const ActivationIterator &activations);
   1.115 +    explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
   1.116 +
   1.117 +    // Current frame information.
   1.118 +    FrameType type() const {
   1.119 +        return type_;
   1.120 +    }
   1.121 +    uint8_t *fp() const {
   1.122 +        return current_;
   1.123 +    }
   1.124 +    const JitActivation *activation() const {
   1.125 +        return activation_;
   1.126 +    }
   1.127 +
   1.128 +    IonCommonFrameLayout *current() const {
   1.129 +        return (IonCommonFrameLayout *)current_;
   1.130 +    }
   1.131 +
   1.132 +    inline uint8_t *returnAddress() const;
   1.133 +
   1.134 +    IonJSFrameLayout *jsFrame() const {
   1.135 +        JS_ASSERT(isScripted());
   1.136 +        return (IonJSFrameLayout *) fp();
   1.137 +    }
   1.138 +
   1.139 +    // Returns true iff this exit frame was created using EnsureExitFrame.
   1.140 +    inline bool isFakeExitFrame() const;
   1.141 +
   1.142 +    inline IonExitFrameLayout *exitFrame() const;
   1.143 +
   1.144 +    // Returns whether the JS frame has been invalidated and, if so,
   1.145 +    // places the invalidated Ion script in |ionScript|.
   1.146 +    bool checkInvalidation(IonScript **ionScript) const;
   1.147 +    bool checkInvalidation() const;
   1.148 +
   1.149 +    bool isScripted() const {
   1.150 +        return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS;
   1.151 +    }
   1.152 +    bool isBaselineJS() const {
   1.153 +        return type_ == JitFrame_BaselineJS;
   1.154 +    }
   1.155 +    bool isIonJS() const {
   1.156 +        return type_ == JitFrame_IonJS;
   1.157 +    }
   1.158 +    bool isBaselineStub() const {
   1.159 +        return type_ == JitFrame_BaselineStub;
   1.160 +    }
   1.161 +    bool isNative() const;
   1.162 +    bool isOOLNative() const;
   1.163 +    bool isOOLPropertyOp() const;
   1.164 +    bool isOOLProxy() const;
   1.165 +    bool isDOMExit() const;
   1.166 +    bool isEntry() const {
   1.167 +        return type_ == JitFrame_Entry;
   1.168 +    }
   1.169 +    bool isFunctionFrame() const;
   1.170 +
   1.171 +    bool isConstructing() const;
   1.172 +
   1.173 +    void *calleeToken() const;
   1.174 +    JSFunction *callee() const;
   1.175 +    JSFunction *maybeCallee() const;
   1.176 +    unsigned numActualArgs() const;
   1.177 +    JSScript *script() const;
   1.178 +    void baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const;
   1.179 +    Value *actualArgs() const;
   1.180 +
   1.181 +    // Returns the return address of the frame above this one (that is, the
   1.182 +    // return address that returns back to the current frame).
   1.183 +    uint8_t *returnAddressToFp() const {
   1.184 +        return returnAddressToFp_;
   1.185 +    }
   1.186 +
   1.187 +    // Previous frame information extracted from the current frame.
   1.188 +    inline size_t prevFrameLocalSize() const;
   1.189 +    inline FrameType prevType() const;
   1.190 +    uint8_t *prevFp() const;
   1.191 +
   1.192 +    // Returns the stack space used by the current frame, in bytes. This does
   1.193 +    // not include the size of its fixed header.
   1.194 +    size_t frameSize() const {
   1.195 +        JS_ASSERT(type_ != JitFrame_Exit);
   1.196 +        return frameSize_;
   1.197 +    }
   1.198 +
   1.199 +    // Functions used to iterate on frames. When prevType is JitFrame_Entry,
   1.200 +    // the current frame is the last frame.
   1.201 +    inline bool done() const {
   1.202 +        return type_ == JitFrame_Entry;
   1.203 +    }
   1.204 +    JitFrameIterator &operator++();
   1.205 +
   1.206 +    // Returns the IonScript associated with this JS frame.
   1.207 +    IonScript *ionScript() const;
   1.208 +
   1.209 +    // Returns the Safepoint associated with this JS frame. Incurs a lookup
   1.210 +    // overhead.
   1.211 +    const SafepointIndex *safepoint() const;
   1.212 +
   1.213 +    // Returns the OSI index associated with this JS frame. Incurs a lookup
   1.214 +    // overhead.
   1.215 +    const OsiIndex *osiIndex() const;
   1.216 +
   1.217 +    uintptr_t *spillBase() const;
   1.218 +    MachineState machineState() const;
   1.219 +
   1.220 +    template <class Op>
   1.221 +    void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const {
   1.222 +        JS_ASSERT(isBaselineJS());
   1.223 +
   1.224 +        unsigned nactual = numActualArgs();
   1.225 +        unsigned start, end;
   1.226 +        switch (behavior) {
   1.227 +          case ReadFrame_Formals:
   1.228 +            start = 0;
   1.229 +            end = callee()->nargs();
   1.230 +            break;
   1.231 +          case ReadFrame_Overflown:
   1.232 +            start = callee()->nargs();
   1.233 +            end = nactual;
   1.234 +            break;
   1.235 +          case ReadFrame_Actuals:
   1.236 +            start = 0;
   1.237 +            end = nactual;
   1.238 +        }
   1.239 +
   1.240 +        Value *argv = actualArgs();
   1.241 +        for (unsigned i = start; i < end; i++)
   1.242 +            op(argv[i]);
   1.243 +    }
   1.244 +
   1.245 +    void dump() const;
   1.246 +
   1.247 +    inline BaselineFrame *baselineFrame() const;
   1.248 +};
   1.249 +
   1.250 +class IonJSFrameLayout;
   1.251 +class IonBailoutIterator;
   1.252 +
   1.253 +class RResumePoint;
   1.254 +
   1.255 +// Reads frame information in snapshot-encoding order (that is, outermost frame
   1.256 +// to innermost frame).
   1.257 +class SnapshotIterator
   1.258 +{
   1.259 +    SnapshotReader snapshot_;
   1.260 +    RecoverReader recover_;
   1.261 +    IonJSFrameLayout *fp_;
   1.262 +    MachineState machine_;
   1.263 +    IonScript *ionScript_;
   1.264 +
   1.265 +  private:
   1.266 +    // Read a spilled register from the machine state.
   1.267 +    bool hasRegister(Register reg) const {
   1.268 +        return machine_.has(reg);
   1.269 +    }
   1.270 +    uintptr_t fromRegister(Register reg) const {
   1.271 +        return machine_.read(reg);
   1.272 +    }
   1.273 +
   1.274 +    bool hasRegister(FloatRegister reg) const {
   1.275 +        return machine_.has(reg);
   1.276 +    }
   1.277 +    double fromRegister(FloatRegister reg) const {
   1.278 +        return machine_.read(reg);
   1.279 +    }
   1.280 +
   1.281 +    // Read an uintptr_t from the stack.
   1.282 +    bool hasStack(int32_t offset) const {
   1.283 +        return true;
   1.284 +    }
   1.285 +    uintptr_t fromStack(int32_t offset) const;
   1.286 +
   1.287 +    Value allocationValue(const RValueAllocation &a);
   1.288 +    bool allocationReadable(const RValueAllocation &a);
   1.289 +    void warnUnreadableAllocation();
   1.290 +
   1.291 +  public:
   1.292 +    // Handle iterating over RValueAllocations of the snapshots.
   1.293 +    inline RValueAllocation readAllocation() {
   1.294 +        MOZ_ASSERT(moreAllocations());
   1.295 +        return snapshot_.readAllocation();
   1.296 +    }
   1.297 +    Value skip() {
   1.298 +        snapshot_.skipAllocation();
   1.299 +        return UndefinedValue();
   1.300 +    }
   1.301 +
   1.302 +    const RResumePoint *resumePoint() const;
   1.303 +    const RInstruction *instruction() const {
   1.304 +        return recover_.instruction();
   1.305 +    }
   1.306 +
   1.307 +    uint32_t numAllocations() const;
   1.308 +    inline bool moreAllocations() const {
   1.309 +        return snapshot_.numAllocationsRead() < numAllocations();
   1.310 +    }
   1.311 +
   1.312 +  public:
   1.313 +    // Exhibits frame properties contained in the snapshot.
   1.314 +    uint32_t pcOffset() const;
   1.315 +    inline bool resumeAfter() const {
   1.316 +        // Inline frames are inlined on calls, which are considered as being
   1.317 +        // resumed on the Call as baseline will push the pc once we return from
   1.318 +        // the call.
   1.319 +        if (moreFrames())
   1.320 +            return false;
   1.321 +        return recover_.resumeAfter();
   1.322 +    }
   1.323 +    inline BailoutKind bailoutKind() const {
   1.324 +        return snapshot_.bailoutKind();
   1.325 +    }
   1.326 +
   1.327 +  public:
   1.328 +    // Read the next instruction available and get ready to either skip it or
   1.329 +    // evaluate it.
   1.330 +    inline void nextInstruction() {
   1.331 +        MOZ_ASSERT(snapshot_.numAllocationsRead() == numAllocations());
   1.332 +        recover_.nextInstruction();
   1.333 +        snapshot_.resetNumAllocationsRead();
   1.334 +    }
   1.335 +
   1.336 +    // Skip an Instruction by walking to the next instruction and by skipping
   1.337 +    // all the allocations corresponding to this instruction.
   1.338 +    void skipInstruction();
   1.339 +
   1.340 +    inline bool moreInstructions() const {
   1.341 +        return recover_.moreInstructions();
   1.342 +    }
   1.343 +
   1.344 +  public:
   1.345 +    // Handle iterating over frames of the snapshots.
   1.346 +    void nextFrame();
   1.347 +
   1.348 +    inline bool moreFrames() const {
   1.349 +        // The last instruction is recovering the innermost frame, so as long as
   1.350 +        // there is more instruction there is necesseray more frames.
   1.351 +        return moreInstructions();
   1.352 +    }
   1.353 +
   1.354 +  public:
   1.355 +    // Connect all informations about the current script in order to recover the
   1.356 +    // content of baseline frames.
   1.357 +
   1.358 +    SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
   1.359 +                     IonJSFrameLayout *fp, const MachineState &machine);
   1.360 +    SnapshotIterator(const JitFrameIterator &iter);
   1.361 +    SnapshotIterator(const IonBailoutIterator &iter);
   1.362 +    SnapshotIterator();
   1.363 +
   1.364 +    Value read() {
   1.365 +        return allocationValue(readAllocation());
   1.366 +    }
   1.367 +    Value maybeRead(bool silentFailure = false) {
   1.368 +        RValueAllocation a = readAllocation();
   1.369 +        if (allocationReadable(a))
   1.370 +            return allocationValue(a);
   1.371 +        if (!silentFailure)
   1.372 +            warnUnreadableAllocation();
   1.373 +        return UndefinedValue();
   1.374 +    }
   1.375 +
   1.376 +    void readCommonFrameSlots(Value *scopeChain, Value *rval) {
   1.377 +        if (scopeChain)
   1.378 +            *scopeChain = read();
   1.379 +        else
   1.380 +            skip();
   1.381 +
   1.382 +        if (rval)
   1.383 +            *rval = read();
   1.384 +        else
   1.385 +            skip();
   1.386 +    }
   1.387 +
   1.388 +    template <class Op>
   1.389 +    void readFunctionFrameArgs(Op &op, ArgumentsObject **argsObj, Value *thisv,
   1.390 +                               unsigned start, unsigned end, JSScript *script)
   1.391 +    {
   1.392 +        // Assumes that the common frame arguments have already been read.
   1.393 +        if (script->argumentsHasVarBinding()) {
   1.394 +            if (argsObj) {
   1.395 +                Value v = read();
   1.396 +                if (v.isObject())
   1.397 +                    *argsObj = &v.toObject().as<ArgumentsObject>();
   1.398 +            } else {
   1.399 +                skip();
   1.400 +            }
   1.401 +        }
   1.402 +
   1.403 +        if (thisv)
   1.404 +            *thisv = read();
   1.405 +        else
   1.406 +            skip();
   1.407 +
   1.408 +        unsigned i = 0;
   1.409 +        if (end < start)
   1.410 +            i = start;
   1.411 +
   1.412 +        for (; i < start; i++)
   1.413 +            skip();
   1.414 +        for (; i < end; i++) {
   1.415 +            // We are not always able to read values from the snapshots, some values
   1.416 +            // such as non-gc things may still be live in registers and cause an
   1.417 +            // error while reading the machine state.
   1.418 +            Value v = maybeRead();
   1.419 +            op(v);
   1.420 +        }
   1.421 +    }
   1.422 +
   1.423 +    Value maybeReadAllocByIndex(size_t index) {
   1.424 +        while (index--) {
   1.425 +            JS_ASSERT(moreAllocations());
   1.426 +            skip();
   1.427 +        }
   1.428 +
   1.429 +        Value s = maybeRead(true);
   1.430 +
   1.431 +        while (moreAllocations())
   1.432 +            skip();
   1.433 +
   1.434 +        return s;
   1.435 +    }
   1.436 +};
   1.437 +
   1.438 +// Reads frame information in callstack order (that is, innermost frame to
   1.439 +// outermost frame).
   1.440 +template <AllowGC allowGC=CanGC>
   1.441 +class InlineFrameIteratorMaybeGC
   1.442 +{
   1.443 +    const JitFrameIterator *frame_;
   1.444 +    SnapshotIterator start_;
   1.445 +    SnapshotIterator si_;
   1.446 +    uint32_t framesRead_;
   1.447 +
   1.448 +    // When the inline-frame-iterator is created, this variable is defined to
   1.449 +    // UINT32_MAX. Then the first iteration of findNextFrame, which settle on
   1.450 +    // the innermost frame, is used to update this counter to the number of
   1.451 +    // frames contained in the recover buffer.
   1.452 +    uint32_t frameCount_;
   1.453 +
   1.454 +    typename MaybeRooted<JSFunction*, allowGC>::RootType callee_;
   1.455 +    typename MaybeRooted<JSScript*, allowGC>::RootType script_;
   1.456 +    jsbytecode *pc_;
   1.457 +    uint32_t numActualArgs_;
   1.458 +
   1.459 +    struct Nop {
   1.460 +        void operator()(const Value &v) { }
   1.461 +    };
   1.462 +
   1.463 +  private:
   1.464 +    void findNextFrame();
   1.465 +
   1.466 +    JSObject *computeScopeChain(Value scopeChainValue) const {
   1.467 +        if (scopeChainValue.isObject())
   1.468 +            return &scopeChainValue.toObject();
   1.469 +
   1.470 +        if (isFunctionFrame()) {
   1.471 +            // Heavyweight functions should always have a scope chain.
   1.472 +            MOZ_ASSERT(!callee()->isHeavyweight());
   1.473 +            return callee()->environment();
   1.474 +        }
   1.475 +
   1.476 +        // Ion does not handle scripts that are not compile-and-go.
   1.477 +        MOZ_ASSERT(!script()->isForEval());
   1.478 +        MOZ_ASSERT(script()->compileAndGo());
   1.479 +        return &script()->global();
   1.480 +    }
   1.481 +
   1.482 +  public:
   1.483 +    InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter)
   1.484 +      : callee_(cx),
   1.485 +        script_(cx)
   1.486 +    {
   1.487 +        resetOn(iter);
   1.488 +    }
   1.489 +
   1.490 +    InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter)
   1.491 +      : callee_(rt),
   1.492 +        script_(rt)
   1.493 +    {
   1.494 +        resetOn(iter);
   1.495 +    }
   1.496 +
   1.497 +    InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter);
   1.498 +
   1.499 +    InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter)
   1.500 +      : frame_(iter ? iter->frame_ : nullptr),
   1.501 +        framesRead_(0),
   1.502 +        frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
   1.503 +        callee_(cx),
   1.504 +        script_(cx)
   1.505 +    {
   1.506 +        if (frame_) {
   1.507 +            start_ = SnapshotIterator(*frame_);
   1.508 +            // findNextFrame will iterate to the next frame and init. everything.
   1.509 +            // Therefore to settle on the same frame, we report one frame less readed.
   1.510 +            framesRead_ = iter->framesRead_ - 1;
   1.511 +            findNextFrame();
   1.512 +        }
   1.513 +    }
   1.514 +
   1.515 +    bool more() const {
   1.516 +        return frame_ && framesRead_ < frameCount_;
   1.517 +    }
   1.518 +    JSFunction *callee() const {
   1.519 +        JS_ASSERT(callee_);
   1.520 +        return callee_;
   1.521 +    }
   1.522 +    JSFunction *maybeCallee() const {
   1.523 +        return callee_;
   1.524 +    }
   1.525 +
   1.526 +    unsigned numActualArgs() const {
   1.527 +        // The number of actual arguments of inline frames is recovered by the
   1.528 +        // iteration process. It is recovered from the bytecode because this
   1.529 +        // property still hold since the for inlined frames. This property does not
   1.530 +        // hold for the parent frame because it can have optimize a call to
   1.531 +        // js_fun_call or js_fun_apply.
   1.532 +        if (more())
   1.533 +            return numActualArgs_;
   1.534 +
   1.535 +        return frame_->numActualArgs();
   1.536 +    }
   1.537 +
   1.538 +    template <class ArgOp, class LocalOp>
   1.539 +    void readFrameArgsAndLocals(JSContext *cx, ArgOp &argOp, LocalOp &localOp,
   1.540 +                                JSObject **scopeChain, Value *rval,
   1.541 +                                ArgumentsObject **argsObj, Value *thisv,
   1.542 +                                ReadFrameArgsBehavior behavior) const
   1.543 +    {
   1.544 +        SnapshotIterator s(si_);
   1.545 +
   1.546 +        // Read frame slots common to both function and global frames.
   1.547 +        Value scopeChainValue;
   1.548 +        s.readCommonFrameSlots(&scopeChainValue, rval);
   1.549 +
   1.550 +        if (scopeChain)
   1.551 +            *scopeChain = computeScopeChain(scopeChainValue);
   1.552 +
   1.553 +        // Read arguments, which only function frames have.
   1.554 +        if (isFunctionFrame()) {
   1.555 +            unsigned nactual = numActualArgs();
   1.556 +            unsigned nformal = callee()->nargs();
   1.557 +
   1.558 +            // Get the non overflown arguments, which are taken from the inlined
   1.559 +            // frame, because it will have the updated value when JSOP_SETARG is
   1.560 +            // done.
   1.561 +            if (behavior != ReadFrame_Overflown)
   1.562 +                s.readFunctionFrameArgs(argOp, argsObj, thisv, 0, nformal, script());
   1.563 +
   1.564 +            if (behavior != ReadFrame_Formals) {
   1.565 +                if (more()) {
   1.566 +                    // There is still a parent frame of this inlined frame.  All
   1.567 +                    // arguments (also the overflown) are the last pushed values
   1.568 +                    // in the parent frame.  To get the overflown arguments, we
   1.569 +                    // need to take them from there.
   1.570 +
   1.571 +                    // The overflown arguments are not available in current frame.
   1.572 +                    // They are the last pushed arguments in the parent frame of
   1.573 +                    // this inlined frame.
   1.574 +                    InlineFrameIteratorMaybeGC it(cx, this);
   1.575 +                    ++it;
   1.576 +                    unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
   1.577 +                    SnapshotIterator parent_s(it.snapshotIterator());
   1.578 +
   1.579 +                    // Skip over all slots until we get to the last slots
   1.580 +                    // (= arguments slots of callee) the +3 is for [this], [returnvalue],
   1.581 +                    // [scopechain], and maybe +1 for [argsObj]
   1.582 +                    JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj);
   1.583 +                    unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj;
   1.584 +                    for (unsigned j = 0; j < skip; j++)
   1.585 +                        parent_s.skip();
   1.586 +
   1.587 +                    // Get the overflown arguments
   1.588 +                    parent_s.readCommonFrameSlots(nullptr, nullptr);
   1.589 +                    parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr,
   1.590 +                                                   nformal, nactual, it.script());
   1.591 +                } else {
   1.592 +                    // There is no parent frame to this inlined frame, we can read
   1.593 +                    // from the frame's Value vector directly.
   1.594 +                    Value *argv = frame_->actualArgs();
   1.595 +                    for (unsigned i = nformal; i < nactual; i++)
   1.596 +                        argOp(argv[i]);
   1.597 +                }
   1.598 +            }
   1.599 +        }
   1.600 +
   1.601 +        // At this point we've read all the formals in s, and can read the
   1.602 +        // locals.
   1.603 +        for (unsigned i = 0; i < script()->nfixed(); i++)
   1.604 +            localOp(s.read());
   1.605 +    }
   1.606 +
   1.607 +    template <class Op>
   1.608 +    void unaliasedForEachActual(JSContext *cx, Op op, ReadFrameArgsBehavior behavior) const {
   1.609 +        Nop nop;
   1.610 +        readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior);
   1.611 +    }
   1.612 +
   1.613 +    JSScript *script() const {
   1.614 +        return script_;
   1.615 +    }
   1.616 +    jsbytecode *pc() const {
   1.617 +        return pc_;
   1.618 +    }
   1.619 +    SnapshotIterator snapshotIterator() const {
   1.620 +        return si_;
   1.621 +    }
   1.622 +    bool isFunctionFrame() const;
   1.623 +    bool isConstructing() const;
   1.624 +
   1.625 +    JSObject *scopeChain() const {
   1.626 +        SnapshotIterator s(si_);
   1.627 +
   1.628 +        // scopeChain
   1.629 +        Value v = s.read();
   1.630 +        return computeScopeChain(v);
   1.631 +    }
   1.632 +
   1.633 +    JSObject *thisObject() const {
   1.634 +        // In strict modes, |this| may not be an object and thus may not be
   1.635 +        // readable which can either segv in read or trigger the assertion.
   1.636 +        Value v = thisValue();
   1.637 +        JS_ASSERT(v.isObject());
   1.638 +        return &v.toObject();
   1.639 +    }
   1.640 +
   1.641 +    Value thisValue() const {
   1.642 +        // JS_ASSERT(isConstructing(...));
   1.643 +        SnapshotIterator s(si_);
   1.644 +
   1.645 +        // scopeChain
   1.646 +        s.skip();
   1.647 +
   1.648 +        // return value
   1.649 +        s.skip();
   1.650 +
   1.651 +        // Arguments object.
   1.652 +        if (script()->argumentsHasVarBinding())
   1.653 +            s.skip();
   1.654 +
   1.655 +        return s.read();
   1.656 +    }
   1.657 +
   1.658 +    InlineFrameIteratorMaybeGC &operator++() {
   1.659 +        findNextFrame();
   1.660 +        return *this;
   1.661 +    }
   1.662 +
   1.663 +    void dump() const;
   1.664 +
   1.665 +    void resetOn(const JitFrameIterator *iter);
   1.666 +
   1.667 +    const JitFrameIterator &frame() const {
   1.668 +        return *frame_;
   1.669 +    }
   1.670 +
   1.671 +    // Inline frame number, 0 for the outermost (non-inlined) frame.
   1.672 +    size_t frameNo() const {
   1.673 +        return frameCount() - framesRead_;
   1.674 +    }
   1.675 +    size_t frameCount() const {
   1.676 +        MOZ_ASSERT(frameCount_ != UINT32_MAX);
   1.677 +        return frameCount_;
   1.678 +    }
   1.679 +
   1.680 +  private:
   1.681 +    InlineFrameIteratorMaybeGC() MOZ_DELETE;
   1.682 +    InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE;
   1.683 +};
   1.684 +typedef InlineFrameIteratorMaybeGC<CanGC> InlineFrameIterator;
   1.685 +typedef InlineFrameIteratorMaybeGC<NoGC> InlineFrameIteratorNoGC;
   1.686 +
   1.687 +} // namespace jit
   1.688 +} // namespace js
   1.689 +
   1.690 +#endif // JS_ION
   1.691 +
   1.692 +#endif /* jit_JitFrameIterator_h */

mercurial