js/src/vm/Stack.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/vm/Stack.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1886 @@
     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 vm_Stack_h
    1.11 +#define vm_Stack_h
    1.12 +
    1.13 +#include "mozilla/MemoryReporting.h"
    1.14 +
    1.15 +#include "jsfun.h"
    1.16 +#include "jsscript.h"
    1.17 +
    1.18 +#include "jit/AsmJSLink.h"
    1.19 +#include "jit/JitFrameIterator.h"
    1.20 +#ifdef CHECK_OSIPOINT_REGISTERS
    1.21 +#include "jit/Registers.h" // for RegisterDump
    1.22 +#endif
    1.23 +#include "js/OldDebugAPI.h"
    1.24 +
    1.25 +struct JSCompartment;
    1.26 +struct JSGenerator;
    1.27 +
    1.28 +namespace js {
    1.29 +
    1.30 +class ArgumentsObject;
    1.31 +class AsmJSModule;
    1.32 +class InterpreterRegs;
    1.33 +class ScopeObject;
    1.34 +class ScriptFrameIter;
    1.35 +class SPSProfiler;
    1.36 +class InterpreterFrame;
    1.37 +class StaticBlockObject;
    1.38 +
    1.39 +struct ScopeCoordinate;
    1.40 +
    1.41 +// VM stack layout
    1.42 +//
    1.43 +// A JSRuntime's stack consists of a linked list of activations. Every activation
    1.44 +// contains a number of scripted frames that are either running in the interpreter
    1.45 +// (InterpreterActivation) or JIT code (JitActivation). The frames inside a single
    1.46 +// activation are contiguous: whenever C++ calls back into JS, a new activation is
    1.47 +// pushed.
    1.48 +//
    1.49 +// Every activation is tied to a single JSContext and JSCompartment. This means we
    1.50 +// can reconstruct a given context's stack by skipping activations belonging to other
    1.51 +// contexts. This happens whenever an embedding enters the JS engine on cx1 and
    1.52 +// then, from a native called by the JS engine, reenters the VM on cx2.
    1.53 +
    1.54 +// Interpreter frames (InterpreterFrame)
    1.55 +//
    1.56 +// Each interpreter script activation (global or function code) is given a
    1.57 +// fixed-size header (js::InterpreterFrame). The frame contains bookkeeping
    1.58 +// information about the activation and links to the previous frame.
    1.59 +//
    1.60 +// The values after an InterpreterFrame in memory are its locals followed by its
    1.61 +// expression stack. InterpreterFrame::argv_ points to the frame's arguments.
    1.62 +// Missing formal arguments are padded with |undefined|, so the number of
    1.63 +// arguments is always >= the number of formals.
    1.64 +//
    1.65 +// The top of an activation's current frame's expression stack is pointed to by
    1.66 +// the activation's "current regs", which contains the stack pointer 'sp'. In
    1.67 +// the interpreter, sp is adjusted as individual values are pushed and popped
    1.68 +// from the stack and the InterpreterRegs struct (pointed to by the
    1.69 +// InterpreterActivation) is a local var of js::Interpret.
    1.70 +
    1.71 +enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
    1.72 +
    1.73 +/*****************************************************************************/
    1.74 +
    1.75 +#ifdef DEBUG
    1.76 +extern void
    1.77 +CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i);
    1.78 +#endif
    1.79 +
    1.80 +namespace jit {
    1.81 +    class BaselineFrame;
    1.82 +    class RematerializedFrame;
    1.83 +}
    1.84 +
    1.85 +/*
    1.86 + * Pointer to either a ScriptFrameIter::Data, an InterpreterFrame, or a Baseline
    1.87 + * JIT frame.
    1.88 + *
    1.89 + * The Debugger may cache ScriptFrameIter::Data as a bookmark to reconstruct a
    1.90 + * ScriptFrameIter without doing a full stack walk.
    1.91 + *
    1.92 + * There is no way to directly create such an AbstractFramePtr. To do so, the
    1.93 + * user must call ScriptFrameIter::copyDataAsAbstractFramePtr().
    1.94 + *
    1.95 + * ScriptFrameIter::abstractFramePtr() will never return an AbstractFramePtr
    1.96 + * that is in fact a ScriptFrameIter::Data.
    1.97 + *
    1.98 + * To recover a ScriptFrameIter settled at the location pointed to by an
    1.99 + * AbstractFramePtr, use the THIS_FRAME_ITER macro in Debugger.cpp. As an
   1.100 + * aside, no asScriptFrameIterData() is provided because C++ is stupid and
   1.101 + * cannot forward declare inner classes.
   1.102 + */
   1.103 +
   1.104 +class AbstractFramePtr
   1.105 +{
   1.106 +    friend class FrameIter;
   1.107 +
   1.108 +    uintptr_t ptr_;
   1.109 +
   1.110 +    enum {
   1.111 +        Tag_ScriptFrameIterData = 0x0,
   1.112 +        Tag_InterpreterFrame = 0x1,
   1.113 +        Tag_BaselineFrame = 0x2,
   1.114 +        Tag_RematerializedFrame = 0x3,
   1.115 +        TagMask = 0x3
   1.116 +    };
   1.117 +
   1.118 +  public:
   1.119 +    AbstractFramePtr()
   1.120 +      : ptr_(0)
   1.121 +    {}
   1.122 +
   1.123 +    AbstractFramePtr(InterpreterFrame *fp)
   1.124 +      : ptr_(fp ? uintptr_t(fp) | Tag_InterpreterFrame : 0)
   1.125 +    {
   1.126 +        MOZ_ASSERT_IF(fp, asInterpreterFrame() == fp);
   1.127 +    }
   1.128 +
   1.129 +    AbstractFramePtr(jit::BaselineFrame *fp)
   1.130 +      : ptr_(fp ? uintptr_t(fp) | Tag_BaselineFrame : 0)
   1.131 +    {
   1.132 +        MOZ_ASSERT_IF(fp, asBaselineFrame() == fp);
   1.133 +    }
   1.134 +
   1.135 +    AbstractFramePtr(jit::RematerializedFrame *fp)
   1.136 +      : ptr_(fp ? uintptr_t(fp) | Tag_RematerializedFrame : 0)
   1.137 +    {
   1.138 +        MOZ_ASSERT_IF(fp, asRematerializedFrame() == fp);
   1.139 +    }
   1.140 +
   1.141 +    explicit AbstractFramePtr(JSAbstractFramePtr frame)
   1.142 +        : ptr_(uintptr_t(frame.raw()))
   1.143 +    {
   1.144 +    }
   1.145 +
   1.146 +    static AbstractFramePtr FromRaw(void *raw) {
   1.147 +        AbstractFramePtr frame;
   1.148 +        frame.ptr_ = uintptr_t(raw);
   1.149 +        return frame;
   1.150 +    }
   1.151 +
   1.152 +    bool isScriptFrameIterData() const {
   1.153 +        return !!ptr_ && (ptr_ & TagMask) == Tag_ScriptFrameIterData;
   1.154 +    }
   1.155 +    bool isInterpreterFrame() const {
   1.156 +        return (ptr_ & TagMask) == Tag_InterpreterFrame;
   1.157 +    }
   1.158 +    InterpreterFrame *asInterpreterFrame() const {
   1.159 +        JS_ASSERT(isInterpreterFrame());
   1.160 +        InterpreterFrame *res = (InterpreterFrame *)(ptr_ & ~TagMask);
   1.161 +        JS_ASSERT(res);
   1.162 +        return res;
   1.163 +    }
   1.164 +    bool isBaselineFrame() const {
   1.165 +        return (ptr_ & TagMask) == Tag_BaselineFrame;
   1.166 +    }
   1.167 +    jit::BaselineFrame *asBaselineFrame() const {
   1.168 +        JS_ASSERT(isBaselineFrame());
   1.169 +        jit::BaselineFrame *res = (jit::BaselineFrame *)(ptr_ & ~TagMask);
   1.170 +        JS_ASSERT(res);
   1.171 +        return res;
   1.172 +    }
   1.173 +    bool isRematerializedFrame() const {
   1.174 +        return (ptr_ & TagMask) == Tag_RematerializedFrame;
   1.175 +    }
   1.176 +    jit::RematerializedFrame *asRematerializedFrame() const {
   1.177 +        JS_ASSERT(isRematerializedFrame());
   1.178 +        jit::RematerializedFrame *res = (jit::RematerializedFrame *)(ptr_ & ~TagMask);
   1.179 +        JS_ASSERT(res);
   1.180 +        return res;
   1.181 +    }
   1.182 +
   1.183 +    void *raw() const { return reinterpret_cast<void *>(ptr_); }
   1.184 +
   1.185 +    bool operator ==(const AbstractFramePtr &other) const { return ptr_ == other.ptr_; }
   1.186 +    bool operator !=(const AbstractFramePtr &other) const { return ptr_ != other.ptr_; }
   1.187 +
   1.188 +    operator bool() const { return !!ptr_; }
   1.189 +
   1.190 +    inline JSObject *scopeChain() const;
   1.191 +    inline CallObject &callObj() const;
   1.192 +    inline bool initFunctionScopeObjects(JSContext *cx);
   1.193 +    inline void pushOnScopeChain(ScopeObject &scope);
   1.194 +
   1.195 +    inline JSCompartment *compartment() const;
   1.196 +
   1.197 +    inline bool hasCallObj() const;
   1.198 +    inline bool isGeneratorFrame() const;
   1.199 +    inline bool isYielding() const;
   1.200 +    inline bool isFunctionFrame() const;
   1.201 +    inline bool isGlobalFrame() const;
   1.202 +    inline bool isEvalFrame() const;
   1.203 +    inline bool isFramePushedByExecute() const;
   1.204 +    inline bool isDebuggerFrame() const;
   1.205 +
   1.206 +    inline JSScript *script() const;
   1.207 +    inline JSFunction *fun() const;
   1.208 +    inline JSFunction *maybeFun() const;
   1.209 +    inline JSFunction *callee() const;
   1.210 +    inline Value calleev() const;
   1.211 +    inline Value &thisValue() const;
   1.212 +
   1.213 +    inline bool isNonEvalFunctionFrame() const;
   1.214 +    inline bool isNonStrictDirectEvalFrame() const;
   1.215 +    inline bool isStrictEvalFrame() const;
   1.216 +
   1.217 +    inline unsigned numActualArgs() const;
   1.218 +    inline unsigned numFormalArgs() const;
   1.219 +
   1.220 +    inline Value *argv() const;
   1.221 +
   1.222 +    inline bool hasArgs() const;
   1.223 +    inline bool hasArgsObj() const;
   1.224 +    inline ArgumentsObject &argsObj() const;
   1.225 +    inline void initArgsObj(ArgumentsObject &argsobj) const;
   1.226 +    inline bool useNewType() const;
   1.227 +
   1.228 +    inline bool copyRawFrameSlots(AutoValueVector *vec) const;
   1.229 +
   1.230 +    inline Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
   1.231 +    inline Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
   1.232 +    inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
   1.233 +    inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
   1.234 +    template <class Op> inline void unaliasedForEachActual(JSContext *cx, Op op);
   1.235 +
   1.236 +    inline bool prevUpToDate() const;
   1.237 +    inline void setPrevUpToDate() const;
   1.238 +
   1.239 +    JSObject *evalPrevScopeChain(JSContext *cx) const;
   1.240 +
   1.241 +    inline void *maybeHookData() const;
   1.242 +    inline void setHookData(void *data) const;
   1.243 +    inline HandleValue returnValue() const;
   1.244 +    inline void setReturnValue(const Value &rval) const;
   1.245 +
   1.246 +    bool hasPushedSPSFrame() const;
   1.247 +
   1.248 +    inline void popBlock(JSContext *cx) const;
   1.249 +    inline void popWith(JSContext *cx) const;
   1.250 +};
   1.251 +
   1.252 +class NullFramePtr : public AbstractFramePtr
   1.253 +{
   1.254 +  public:
   1.255 +    NullFramePtr()
   1.256 +      : AbstractFramePtr()
   1.257 +    { }
   1.258 +};
   1.259 +
   1.260 +/*****************************************************************************/
   1.261 +
   1.262 +/* Flags specified for a frame as it is constructed. */
   1.263 +enum InitialFrameFlags {
   1.264 +    INITIAL_NONE           =          0,
   1.265 +    INITIAL_CONSTRUCT      =       0x20, /* == InterpreterFrame::CONSTRUCTING, asserted below */
   1.266 +};
   1.267 +
   1.268 +enum ExecuteType {
   1.269 +    EXECUTE_GLOBAL         =        0x1, /* == InterpreterFrame::GLOBAL */
   1.270 +    EXECUTE_DIRECT_EVAL    =        0x4, /* == InterpreterFrame::EVAL */
   1.271 +    EXECUTE_INDIRECT_EVAL  =        0x5, /* == InterpreterFrame::GLOBAL | EVAL */
   1.272 +    EXECUTE_DEBUG          =        0xc, /* == InterpreterFrame::EVAL | DEBUGGER */
   1.273 +    EXECUTE_DEBUG_GLOBAL   =        0xd  /* == InterpreterFrame::EVAL | DEBUGGER | GLOBAL */
   1.274 +};
   1.275 +
   1.276 +/*****************************************************************************/
   1.277 +
   1.278 +class InterpreterFrame
   1.279 +{
   1.280 +  public:
   1.281 +    enum Flags {
   1.282 +        /* Primary frame type */
   1.283 +        GLOBAL             =        0x1,  /* frame pushed for a global script */
   1.284 +        FUNCTION           =        0x2,  /* frame pushed for a scripted call */
   1.285 +
   1.286 +        /* Frame subtypes */
   1.287 +        EVAL               =        0x4,  /* frame pushed for eval() or debugger eval */
   1.288 +
   1.289 +
   1.290 +        /*
   1.291 +         * Frame pushed for debugger eval.
   1.292 +         * - Don't bother to JIT it, because it's probably short-lived.
   1.293 +         * - It is required to have a scope chain object outside the
   1.294 +         *   js::ScopeObject hierarchy: either a global object, or a
   1.295 +         *   DebugScopeObject (not a ScopeObject, despite the name)
   1.296 +         * - If evalInFramePrev_ is set, then this frame was created for an
   1.297 +         *   "eval in frame" call, which can push a successor to any live
   1.298 +         *   frame; so its logical "prev" frame is not necessarily the
   1.299 +         *   previous frame in memory. Iteration should treat
   1.300 +         *   evalInFramePrev_ as this frame's previous frame.
   1.301 +         */
   1.302 +        DEBUGGER           =        0x8,
   1.303 +
   1.304 +        GENERATOR          =       0x10,  /* frame is associated with a generator */
   1.305 +        CONSTRUCTING       =       0x20,  /* frame is for a constructor invocation */
   1.306 +
   1.307 +        /*
   1.308 +         * Generator frame state
   1.309 +         *
   1.310 +         * YIELDING and SUSPENDED are similar, but there are differences. After
   1.311 +         * a generator yields, SendToGenerator immediately clears the YIELDING
   1.312 +         * flag, but the frame will still have the SUSPENDED flag. Also, when the
   1.313 +         * generator returns but before it's GC'ed, YIELDING is not set but
   1.314 +         * SUSPENDED is.
   1.315 +         */
   1.316 +        YIELDING           =       0x40,  /* Interpret dispatched JSOP_YIELD */
   1.317 +        SUSPENDED          =       0x80,  /* Generator is not running. */
   1.318 +
   1.319 +        /* Function prologue state */
   1.320 +        HAS_CALL_OBJ       =      0x100,  /* CallObject created for heavyweight fun */
   1.321 +        HAS_ARGS_OBJ       =      0x200,  /* ArgumentsObject created for needsArgsObj script */
   1.322 +
   1.323 +        /* Lazy frame initialization */
   1.324 +        HAS_HOOK_DATA      =      0x400,  /* frame has hookData_ set */
   1.325 +        HAS_RVAL           =      0x800,  /* frame has rval_ set */
   1.326 +        HAS_SCOPECHAIN     =     0x1000,  /* frame has scopeChain_ set */
   1.327 +
   1.328 +        /* Debugger state */
   1.329 +        PREV_UP_TO_DATE    =     0x4000,  /* see DebugScopes::updateLiveScopes */
   1.330 +
   1.331 +        /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
   1.332 +        HAS_PUSHED_SPS_FRAME =   0x8000,  /* SPS was notified of enty */
   1.333 +
   1.334 +        /*
   1.335 +         * If set, we entered one of the JITs and ScriptFrameIter should skip
   1.336 +         * this frame.
   1.337 +         */
   1.338 +        RUNNING_IN_JIT     =    0x10000,
   1.339 +
   1.340 +        /* Miscellaneous state. */
   1.341 +        USE_NEW_TYPE       =    0x20000   /* Use new type for constructed |this| object. */
   1.342 +    };
   1.343 +
   1.344 +  private:
   1.345 +    mutable uint32_t    flags_;         /* bits described by Flags */
   1.346 +    union {                             /* describes what code is executing in a */
   1.347 +        JSScript        *script;        /*   global frame */
   1.348 +        JSFunction      *fun;           /*   function frame, pre GetScopeChain */
   1.349 +    } exec;
   1.350 +    union {                             /* describes the arguments of a function */
   1.351 +        unsigned        nactual;        /*   for non-eval frames */
   1.352 +        JSScript        *evalScript;    /*   the script of an eval-in-function */
   1.353 +    } u;
   1.354 +    mutable JSObject    *scopeChain_;   /* if HAS_SCOPECHAIN, current scope chain */
   1.355 +    Value               rval_;          /* if HAS_RVAL, return value of the frame */
   1.356 +    ArgumentsObject     *argsObj_;      /* if HAS_ARGS_OBJ, the call's arguments object */
   1.357 +
   1.358 +    /*
   1.359 +     * Previous frame and its pc and sp. Always nullptr for
   1.360 +     * InterpreterActivation's entry frame, always non-nullptr for inline
   1.361 +     * frames.
   1.362 +     */
   1.363 +    InterpreterFrame    *prev_;
   1.364 +    jsbytecode          *prevpc_;
   1.365 +    Value               *prevsp_;
   1.366 +
   1.367 +    void                *hookData_;     /* if HAS_HOOK_DATA, closure returned by call hook */
   1.368 +
   1.369 +    /*
   1.370 +     * For an eval-in-frame DEBUGGER frame, the frame in whose scope we're
   1.371 +     * evaluating code. Iteration treats this as our previous frame.
   1.372 +     */
   1.373 +    AbstractFramePtr    evalInFramePrev_;
   1.374 +
   1.375 +    Value               *argv_;         /* If hasArgs(), points to frame's arguments. */
   1.376 +    LifoAlloc::Mark     mark_;          /* Used to release memory for this frame. */
   1.377 +
   1.378 +    static void staticAsserts() {
   1.379 +        JS_STATIC_ASSERT(offsetof(InterpreterFrame, rval_) % sizeof(Value) == 0);
   1.380 +        JS_STATIC_ASSERT(sizeof(InterpreterFrame) % sizeof(Value) == 0);
   1.381 +    }
   1.382 +
   1.383 +    void writeBarrierPost();
   1.384 +
   1.385 +    /*
   1.386 +     * The utilities are private since they are not able to assert that only
   1.387 +     * unaliased vars/formals are accessed. Normal code should prefer the
   1.388 +     * InterpreterFrame::unaliased* members (or InterpreterRegs::stackDepth for
   1.389 +     * the usual "depth is at least" assertions).
   1.390 +     */
   1.391 +    Value *slots() const { return (Value *)(this + 1); }
   1.392 +    Value *base() const { return slots() + script()->nfixed(); }
   1.393 +
   1.394 +    friend class FrameIter;
   1.395 +    friend class InterpreterRegs;
   1.396 +    friend class InterpreterStack;
   1.397 +    friend class jit::BaselineFrame;
   1.398 +
   1.399 +    /*
   1.400 +     * Frame initialization, called by InterpreterStack operations after acquiring
   1.401 +     * the raw memory for the frame:
   1.402 +     */
   1.403 +
   1.404 +    /* Used for Invoke and Interpret. */
   1.405 +    void initCallFrame(JSContext *cx, InterpreterFrame *prev, jsbytecode *prevpc, Value *prevsp,
   1.406 +                       JSFunction &callee, JSScript *script, Value *argv, uint32_t nactual,
   1.407 +                       InterpreterFrame::Flags flags);
   1.408 +
   1.409 +    /* Used for global and eval frames. */
   1.410 +    void initExecuteFrame(JSContext *cx, JSScript *script, AbstractFramePtr prev,
   1.411 +                          const Value &thisv, JSObject &scopeChain, ExecuteType type);
   1.412 +
   1.413 +  public:
   1.414 +    /*
   1.415 +     * Frame prologue/epilogue
   1.416 +     *
   1.417 +     * Every stack frame must have 'prologue' called before executing the
   1.418 +     * first op and 'epilogue' called after executing the last op and before
   1.419 +     * popping the frame (whether the exit is exceptional or not).
   1.420 +     *
   1.421 +     * For inline JS calls/returns, it is easy to call the prologue/epilogue
   1.422 +     * exactly once. When calling JS from C++, Invoke/Execute push the stack
   1.423 +     * frame but do *not* call the prologue/epilogue. That means Interpret
   1.424 +     * must call the prologue/epilogue for the entry frame. This scheme
   1.425 +     * simplifies jit compilation.
   1.426 +     *
   1.427 +     * An important corner case is what happens when an error occurs (OOM,
   1.428 +     * over-recursed) after pushing the stack frame but before 'prologue' is
   1.429 +     * called or completes fully. To simplify usage, 'epilogue' does not assume
   1.430 +     * 'prologue' has completed and handles all the intermediate state details.
   1.431 +     */
   1.432 +
   1.433 +    bool prologue(JSContext *cx);
   1.434 +    void epilogue(JSContext *cx);
   1.435 +
   1.436 +    bool initFunctionScopeObjects(JSContext *cx);
   1.437 +
   1.438 +    /* Initialize local variables of newly-pushed frame. */
   1.439 +    void initVarsToUndefined();
   1.440 +
   1.441 +    /*
   1.442 +     * Stack frame type
   1.443 +     *
   1.444 +     * A stack frame may have one of three types, which determines which
   1.445 +     * members of the frame may be accessed and other invariants:
   1.446 +     *
   1.447 +     *  global frame:   execution of global code or an eval in global code
   1.448 +     *  function frame: execution of function code or an eval in a function
   1.449 +     */
   1.450 +
   1.451 +    bool isFunctionFrame() const {
   1.452 +        return !!(flags_ & FUNCTION);
   1.453 +    }
   1.454 +
   1.455 +    bool isGlobalFrame() const {
   1.456 +        return !!(flags_ & GLOBAL);
   1.457 +    }
   1.458 +
   1.459 +    /*
   1.460 +     * Eval frames
   1.461 +     *
   1.462 +     * As noted above, global and function frames may optionally be 'eval
   1.463 +     * frames'. Eval code shares its parent's arguments which means that the
   1.464 +     * arg-access members of InterpreterFrame may not be used for eval frames.
   1.465 +     * Search for 'hasArgs' below for more details.
   1.466 +     *
   1.467 +     * A further sub-classification of eval frames is whether the frame was
   1.468 +     * pushed for an ES5 strict-mode eval().
   1.469 +     */
   1.470 +
   1.471 +    bool isEvalFrame() const {
   1.472 +        return flags_ & EVAL;
   1.473 +    }
   1.474 +
   1.475 +    bool isEvalInFunction() const {
   1.476 +        return (flags_ & (EVAL | FUNCTION)) == (EVAL | FUNCTION);
   1.477 +    }
   1.478 +
   1.479 +    bool isNonEvalFunctionFrame() const {
   1.480 +        return (flags_ & (FUNCTION | EVAL)) == FUNCTION;
   1.481 +    }
   1.482 +
   1.483 +    inline bool isStrictEvalFrame() const {
   1.484 +        return isEvalFrame() && script()->strict();
   1.485 +    }
   1.486 +
   1.487 +    bool isNonStrictEvalFrame() const {
   1.488 +        return isEvalFrame() && !script()->strict();
   1.489 +    }
   1.490 +
   1.491 +    bool isDirectEvalFrame() const {
   1.492 +        return isEvalFrame() && script()->staticLevel() > 0;
   1.493 +    }
   1.494 +
   1.495 +    bool isNonStrictDirectEvalFrame() const {
   1.496 +        return isNonStrictEvalFrame() && isDirectEvalFrame();
   1.497 +    }
   1.498 +
   1.499 +    /*
   1.500 +     * Previous frame
   1.501 +     *
   1.502 +     * A frame's 'prev' frame is either null or the previous frame pointed to
   1.503 +     * by cx->regs->fp when this frame was pushed. Often, given two prev-linked
   1.504 +     * frames, the next-frame is a function or eval that was called by the
   1.505 +     * prev-frame, but not always: the prev-frame may have called a native that
   1.506 +     * reentered the VM through JS_CallFunctionValue on the same context
   1.507 +     * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
   1.508 +     * 'prev' has little semantic meaning and basically just tells the VM what
   1.509 +     * to set cx->regs->fp to when this frame is popped.
   1.510 +     */
   1.511 +
   1.512 +    InterpreterFrame *prev() const {
   1.513 +        return prev_;
   1.514 +    }
   1.515 +
   1.516 +    AbstractFramePtr evalInFramePrev() const {
   1.517 +        JS_ASSERT(isEvalFrame());
   1.518 +        return evalInFramePrev_;
   1.519 +    }
   1.520 +
   1.521 +    /*
   1.522 +     * (Unaliased) locals and arguments
   1.523 +     *
   1.524 +     * Only non-eval function frames have arguments. The arguments pushed by
   1.525 +     * the caller are the 'actual' arguments. The declared arguments of the
   1.526 +     * callee are the 'formal' arguments. When the caller passes less actual
   1.527 +     * arguments, missing formal arguments are padded with |undefined|.
   1.528 +     *
   1.529 +     * When a local/formal variable is "aliased" (accessed by nested closures,
   1.530 +     * dynamic scope operations, or 'arguments), the canonical location for
   1.531 +     * that value is the slot of an activation object (scope or arguments).
   1.532 +     * Currently, all variables are given slots in *both* the stack frame and
   1.533 +     * heap objects, even though, as just described, only one should ever be
   1.534 +     * accessed. Thus, it is up to the code performing an access to access the
   1.535 +     * correct value. These functions assert that accesses to stack values are
   1.536 +     * unaliased. For more about canonical values locations.
   1.537 +     */
   1.538 +
   1.539 +    inline Value &unaliasedVar(uint32_t i, MaybeCheckAliasing = CHECK_ALIASING);
   1.540 +    inline Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing = CHECK_ALIASING);
   1.541 +
   1.542 +    bool hasArgs() const { return isNonEvalFunctionFrame(); }
   1.543 +    inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
   1.544 +    inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
   1.545 +    template <class Op> inline void unaliasedForEachActual(Op op);
   1.546 +
   1.547 +    bool copyRawFrameSlots(AutoValueVector *v);
   1.548 +
   1.549 +    unsigned numFormalArgs() const { JS_ASSERT(hasArgs()); return fun()->nargs(); }
   1.550 +    unsigned numActualArgs() const { JS_ASSERT(hasArgs()); return u.nactual; }
   1.551 +
   1.552 +    /* Watch out, this exposes a pointer to the unaliased formal arg array. */
   1.553 +    Value *argv() const { return argv_; }
   1.554 +
   1.555 +    /*
   1.556 +     * Arguments object
   1.557 +     *
   1.558 +     * If a non-eval function has script->needsArgsObj, an arguments object is
   1.559 +     * created in the prologue and stored in the local variable for the
   1.560 +     * 'arguments' binding (script->argumentsLocal). Since this local is
   1.561 +     * mutable, the arguments object can be overwritten and we can "lose" the
   1.562 +     * arguments object. Thus, InterpreterFrame keeps an explicit argsObj_ field so
   1.563 +     * that the original arguments object is always available.
   1.564 +     */
   1.565 +
   1.566 +    ArgumentsObject &argsObj() const;
   1.567 +    void initArgsObj(ArgumentsObject &argsobj);
   1.568 +
   1.569 +    JSObject *createRestParameter(JSContext *cx);
   1.570 +
   1.571 +    /*
   1.572 +     * Scope chain
   1.573 +     *
   1.574 +     * In theory, the scope chain would contain an object for every lexical
   1.575 +     * scope. However, only objects that are required for dynamic lookup are
   1.576 +     * actually created.
   1.577 +     *
   1.578 +     * Given that an InterpreterFrame corresponds roughly to a ES5 Execution Context
   1.579 +     * (ES5 10.3), InterpreterFrame::varObj corresponds to the VariableEnvironment
   1.580 +     * component of a Exection Context. Intuitively, the variables object is
   1.581 +     * where new bindings (variables and functions) are stored. One might
   1.582 +     * expect that this is either the Call object or scopeChain.globalObj for
   1.583 +     * function or global code, respectively, however the JSAPI allows calls of
   1.584 +     * Execute to specify a variables object on the scope chain other than the
   1.585 +     * call/global object. This allows embeddings to run multiple scripts under
   1.586 +     * the same global, each time using a new variables object to collect and
   1.587 +     * discard the script's global variables.
   1.588 +     */
   1.589 +
   1.590 +    inline HandleObject scopeChain() const;
   1.591 +
   1.592 +    inline ScopeObject &aliasedVarScope(ScopeCoordinate sc) const;
   1.593 +    inline GlobalObject &global() const;
   1.594 +    inline CallObject &callObj() const;
   1.595 +    inline JSObject &varObj();
   1.596 +
   1.597 +    inline void pushOnScopeChain(ScopeObject &scope);
   1.598 +    inline void popOffScopeChain();
   1.599 +
   1.600 +    /*
   1.601 +     * For blocks with aliased locals, these interfaces push and pop entries on
   1.602 +     * the scope chain.
   1.603 +     */
   1.604 +
   1.605 +    bool pushBlock(JSContext *cx, StaticBlockObject &block);
   1.606 +    void popBlock(JSContext *cx);
   1.607 +
   1.608 +    /*
   1.609 +     * With
   1.610 +     *
   1.611 +     * Entering/leaving a |with| block pushes/pops an object on the scope chain.
   1.612 +     * Pushing uses pushOnScopeChain, popping should use popWith.
   1.613 +     */
   1.614 +
   1.615 +    void popWith(JSContext *cx);
   1.616 +
   1.617 +    /*
   1.618 +     * Script
   1.619 +     *
   1.620 +     * All function and global frames have an associated JSScript which holds
   1.621 +     * the bytecode being executed for the frame. This script/bytecode does
   1.622 +     * not reflect any inlining that has been performed by the method JIT.
   1.623 +     * If other frames were inlined into this one, the script/pc reflect the
   1.624 +     * point of the outermost call. Inlined frame invariants:
   1.625 +     *
   1.626 +     * - Inlined frames have the same scope chain as the outer frame.
   1.627 +     * - Inlined frames have the same strictness as the outer frame.
   1.628 +     * - Inlined frames can only make calls to other JIT frames associated with
   1.629 +     *   the same VMFrame. Other calls force expansion of the inlined frames.
   1.630 +     */
   1.631 +
   1.632 +    JSScript *script() const {
   1.633 +        return isFunctionFrame()
   1.634 +               ? isEvalFrame()
   1.635 +                 ? u.evalScript
   1.636 +                 : fun()->nonLazyScript()
   1.637 +               : exec.script;
   1.638 +    }
   1.639 +
   1.640 +    /* Return the previous frame's pc. */
   1.641 +    jsbytecode *prevpc() {
   1.642 +        JS_ASSERT(prev_);
   1.643 +        return prevpc_;
   1.644 +    }
   1.645 +
   1.646 +    /* Return the previous frame's sp. */
   1.647 +    Value *prevsp() {
   1.648 +        JS_ASSERT(prev_);
   1.649 +        return prevsp_;
   1.650 +    }
   1.651 +
   1.652 +    /*
   1.653 +     * Function
   1.654 +     *
   1.655 +     * All function frames have an associated interpreted JSFunction. The
   1.656 +     * function returned by fun() and maybeFun() is not necessarily the
   1.657 +     * original canonical function which the frame's script was compiled
   1.658 +     * against.
   1.659 +     */
   1.660 +
   1.661 +    JSFunction* fun() const {
   1.662 +        JS_ASSERT(isFunctionFrame());
   1.663 +        return exec.fun;
   1.664 +    }
   1.665 +
   1.666 +    JSFunction* maybeFun() const {
   1.667 +        return isFunctionFrame() ? fun() : nullptr;
   1.668 +    }
   1.669 +
   1.670 +    /*
   1.671 +     * This value
   1.672 +     *
   1.673 +     * Every frame has a this value although, until 'this' is computed, the
   1.674 +     * value may not be the semantically-correct 'this' value.
   1.675 +     *
   1.676 +     * The 'this' value is stored before the formal arguments for function
   1.677 +     * frames and directly before the frame for global frames. The *Args
   1.678 +     * members assert !isEvalFrame(), so we implement specialized inline
   1.679 +     * methods for accessing 'this'. When the caller has static knowledge that
   1.680 +     * a frame is a function, 'functionThis' allows more efficient access.
   1.681 +     */
   1.682 +
   1.683 +    Value &functionThis() const {
   1.684 +        JS_ASSERT(isFunctionFrame());
   1.685 +        if (isEvalFrame())
   1.686 +            return ((Value *)this)[-1];
   1.687 +        return argv()[-1];
   1.688 +    }
   1.689 +
   1.690 +    JSObject &constructorThis() const {
   1.691 +        JS_ASSERT(hasArgs());
   1.692 +        return argv()[-1].toObject();
   1.693 +    }
   1.694 +
   1.695 +    Value &thisValue() const {
   1.696 +        if (flags_ & (EVAL | GLOBAL))
   1.697 +            return ((Value *)this)[-1];
   1.698 +        return argv()[-1];
   1.699 +    }
   1.700 +
   1.701 +    /*
   1.702 +     * Callee
   1.703 +     *
   1.704 +     * Only function frames have a callee. An eval frame in a function has the
   1.705 +     * same callee as its containing function frame. maybeCalleev can be used
   1.706 +     * to return a value that is either the callee object (for function frames) or
   1.707 +     * null (for global frames).
   1.708 +     */
   1.709 +
   1.710 +    JSFunction &callee() const {
   1.711 +        JS_ASSERT(isFunctionFrame());
   1.712 +        return calleev().toObject().as<JSFunction>();
   1.713 +    }
   1.714 +
   1.715 +    const Value &calleev() const {
   1.716 +        JS_ASSERT(isFunctionFrame());
   1.717 +        return mutableCalleev();
   1.718 +    }
   1.719 +
   1.720 +    const Value &maybeCalleev() const {
   1.721 +        Value &calleev = flags_ & (EVAL | GLOBAL)
   1.722 +                         ? ((Value *)this)[-2]
   1.723 +                         : argv()[-2];
   1.724 +        JS_ASSERT(calleev.isObjectOrNull());
   1.725 +        return calleev;
   1.726 +    }
   1.727 +
   1.728 +    Value &mutableCalleev() const {
   1.729 +        JS_ASSERT(isFunctionFrame());
   1.730 +        if (isEvalFrame())
   1.731 +            return ((Value *)this)[-2];
   1.732 +        return argv()[-2];
   1.733 +    }
   1.734 +
   1.735 +    CallReceiver callReceiver() const {
   1.736 +        return CallReceiverFromArgv(argv());
   1.737 +    }
   1.738 +
   1.739 +    /*
   1.740 +     * Frame compartment
   1.741 +     *
   1.742 +     * A stack frame's compartment is the frame's containing context's
   1.743 +     * compartment when the frame was pushed.
   1.744 +     */
   1.745 +
   1.746 +    inline JSCompartment *compartment() const;
   1.747 +
   1.748 +    /* Debugger hook data */
   1.749 +
   1.750 +    bool hasHookData() const {
   1.751 +        return !!(flags_ & HAS_HOOK_DATA);
   1.752 +    }
   1.753 +
   1.754 +    void* hookData() const {
   1.755 +        JS_ASSERT(hasHookData());
   1.756 +        return hookData_;
   1.757 +    }
   1.758 +
   1.759 +    void* maybeHookData() const {
   1.760 +        return hasHookData() ? hookData_ : nullptr;
   1.761 +    }
   1.762 +
   1.763 +    void setHookData(void *v) {
   1.764 +        hookData_ = v;
   1.765 +        flags_ |= HAS_HOOK_DATA;
   1.766 +    }
   1.767 +
   1.768 +    bool hasPushedSPSFrame() {
   1.769 +        return !!(flags_ & HAS_PUSHED_SPS_FRAME);
   1.770 +    }
   1.771 +
   1.772 +    void setPushedSPSFrame() {
   1.773 +        flags_ |= HAS_PUSHED_SPS_FRAME;
   1.774 +    }
   1.775 +
   1.776 +    void unsetPushedSPSFrame() {
   1.777 +        flags_ &= ~HAS_PUSHED_SPS_FRAME;
   1.778 +    }
   1.779 +
   1.780 +    /* Return value */
   1.781 +
   1.782 +    bool hasReturnValue() const {
   1.783 +        return !!(flags_ & HAS_RVAL);
   1.784 +    }
   1.785 +
   1.786 +    MutableHandleValue returnValue() {
   1.787 +        if (!(flags_ & HAS_RVAL))
   1.788 +            rval_.setUndefined();
   1.789 +        return MutableHandleValue::fromMarkedLocation(&rval_);
   1.790 +    }
   1.791 +
   1.792 +    void markReturnValue() {
   1.793 +        flags_ |= HAS_RVAL;
   1.794 +    }
   1.795 +
   1.796 +    void setReturnValue(const Value &v) {
   1.797 +        rval_ = v;
   1.798 +        markReturnValue();
   1.799 +    }
   1.800 +
   1.801 +    void clearReturnValue() {
   1.802 +        rval_.setUndefined();
   1.803 +        markReturnValue();
   1.804 +    }
   1.805 +
   1.806 +    /*
   1.807 +     * A "generator" frame is a function frame associated with a generator.
   1.808 +     * Since generators are not executed LIFO, the VM copies a single abstract
   1.809 +     * generator frame back and forth between the LIFO VM stack (when the
   1.810 +     * generator is active) and a snapshot stored in JSGenerator (when the
   1.811 +     * generator is inactive). A generator frame is comprised of an
   1.812 +     * InterpreterFrame structure and the values that make up the arguments,
   1.813 +     * locals, and expression stack. The layout in the JSGenerator snapshot
   1.814 +     * matches the layout on the stack (see the "VM stack layout" comment
   1.815 +     * above).
   1.816 +     */
   1.817 +
   1.818 +    bool isGeneratorFrame() const {
   1.819 +        bool ret = flags_ & GENERATOR;
   1.820 +        JS_ASSERT_IF(ret, isNonEvalFunctionFrame());
   1.821 +        return ret;
   1.822 +    }
   1.823 +
   1.824 +    void initGeneratorFrame() const {
   1.825 +        JS_ASSERT(!isGeneratorFrame());
   1.826 +        JS_ASSERT(isNonEvalFunctionFrame());
   1.827 +        flags_ |= GENERATOR;
   1.828 +    }
   1.829 +
   1.830 +    Value *generatorArgsSnapshotBegin() const {
   1.831 +        JS_ASSERT(isGeneratorFrame());
   1.832 +        return argv() - 2;
   1.833 +    }
   1.834 +
   1.835 +    Value *generatorArgsSnapshotEnd() const {
   1.836 +        JS_ASSERT(isGeneratorFrame());
   1.837 +        return argv() + js::Max(numActualArgs(), numFormalArgs());
   1.838 +    }
   1.839 +
   1.840 +    Value *generatorSlotsSnapshotBegin() const {
   1.841 +        JS_ASSERT(isGeneratorFrame());
   1.842 +        return (Value *)(this + 1);
   1.843 +    }
   1.844 +
   1.845 +    enum TriggerPostBarriers {
   1.846 +        DoPostBarrier = true,
   1.847 +        NoPostBarrier = false
   1.848 +    };
   1.849 +    template <TriggerPostBarriers doPostBarrier>
   1.850 +    void copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp,
   1.851 +                            const Value *othervp, Value *othersp);
   1.852 +
   1.853 +    /*
   1.854 +     * js::Execute pushes both global and function frames (since eval() in a
   1.855 +     * function pushes a frame with isFunctionFrame() && isEvalFrame()). Most
   1.856 +     * code should not care where a frame was pushed, but if it is necessary to
   1.857 +     * pick out frames pushed by js::Execute, this is the right query:
   1.858 +     */
   1.859 +
   1.860 +    bool isFramePushedByExecute() const {
   1.861 +        return !!(flags_ & (GLOBAL | EVAL));
   1.862 +    }
   1.863 +
   1.864 +    /*
   1.865 +     * Other flags
   1.866 +     */
   1.867 +
   1.868 +    InitialFrameFlags initialFlags() const {
   1.869 +        JS_STATIC_ASSERT((int)INITIAL_NONE == 0);
   1.870 +        JS_STATIC_ASSERT((int)INITIAL_CONSTRUCT == (int)CONSTRUCTING);
   1.871 +        uint32_t mask = CONSTRUCTING;
   1.872 +        JS_ASSERT((flags_ & mask) != mask);
   1.873 +        return InitialFrameFlags(flags_ & mask);
   1.874 +    }
   1.875 +
   1.876 +    void setConstructing() {
   1.877 +        flags_ |= CONSTRUCTING;
   1.878 +    }
   1.879 +
   1.880 +    bool isConstructing() const {
   1.881 +        return !!(flags_ & CONSTRUCTING);
   1.882 +    }
   1.883 +
   1.884 +    /*
   1.885 +     * These two queries should not be used in general: the presence/absence of
   1.886 +     * the call/args object is determined by the static(ish) properties of the
   1.887 +     * JSFunction/JSScript. These queries should only be performed when probing
   1.888 +     * a stack frame that may be in the middle of the prologue (during which
   1.889 +     * time the call/args object are created).
   1.890 +     */
   1.891 +
   1.892 +    inline bool hasCallObj() const;
   1.893 +
   1.894 +    bool hasCallObjUnchecked() const {
   1.895 +        return flags_ & HAS_CALL_OBJ;
   1.896 +    }
   1.897 +
   1.898 +    bool hasArgsObj() const {
   1.899 +        JS_ASSERT(script()->needsArgsObj());
   1.900 +        return flags_ & HAS_ARGS_OBJ;
   1.901 +    }
   1.902 +
   1.903 +    void setUseNewType() {
   1.904 +        JS_ASSERT(isConstructing());
   1.905 +        flags_ |= USE_NEW_TYPE;
   1.906 +    }
   1.907 +    bool useNewType() const {
   1.908 +        JS_ASSERT(isConstructing());
   1.909 +        return flags_ & USE_NEW_TYPE;
   1.910 +    }
   1.911 +
   1.912 +    bool isDebuggerFrame() const {
   1.913 +        return !!(flags_ & DEBUGGER);
   1.914 +    }
   1.915 +
   1.916 +    bool prevUpToDate() const {
   1.917 +        return !!(flags_ & PREV_UP_TO_DATE);
   1.918 +    }
   1.919 +
   1.920 +    void setPrevUpToDate() {
   1.921 +        flags_ |= PREV_UP_TO_DATE;
   1.922 +    }
   1.923 +
   1.924 +    bool isYielding() {
   1.925 +        return !!(flags_ & YIELDING);
   1.926 +    }
   1.927 +
   1.928 +    void setYielding() {
   1.929 +        flags_ |= YIELDING;
   1.930 +    }
   1.931 +
   1.932 +    void clearYielding() {
   1.933 +        flags_ &= ~YIELDING;
   1.934 +    }
   1.935 +
   1.936 +    bool isSuspended() const {
   1.937 +        JS_ASSERT(isGeneratorFrame());
   1.938 +        return flags_ & SUSPENDED;
   1.939 +    }
   1.940 +
   1.941 +    void setSuspended() {
   1.942 +        JS_ASSERT(isGeneratorFrame());
   1.943 +        flags_ |= SUSPENDED;
   1.944 +    }
   1.945 +
   1.946 +    void clearSuspended() {
   1.947 +        JS_ASSERT(isGeneratorFrame());
   1.948 +        flags_ &= ~SUSPENDED;
   1.949 +    }
   1.950 +
   1.951 +  public:
   1.952 +    void mark(JSTracer *trc);
   1.953 +    void markValues(JSTracer *trc, unsigned start, unsigned end);
   1.954 +    void markValues(JSTracer *trc, Value *sp, jsbytecode *pc);
   1.955 +
   1.956 +    // Entered Baseline/Ion from the interpreter.
   1.957 +    bool runningInJit() const {
   1.958 +        return !!(flags_ & RUNNING_IN_JIT);
   1.959 +    }
   1.960 +    void setRunningInJit() {
   1.961 +        flags_ |= RUNNING_IN_JIT;
   1.962 +    }
   1.963 +    void clearRunningInJit() {
   1.964 +        flags_ &= ~RUNNING_IN_JIT;
   1.965 +    }
   1.966 +};
   1.967 +
   1.968 +static const size_t VALUES_PER_STACK_FRAME = sizeof(InterpreterFrame) / sizeof(Value);
   1.969 +
   1.970 +static inline InterpreterFrame::Flags
   1.971 +ToFrameFlags(InitialFrameFlags initial)
   1.972 +{
   1.973 +    return InterpreterFrame::Flags(initial);
   1.974 +}
   1.975 +
   1.976 +static inline InitialFrameFlags
   1.977 +InitialFrameFlagsFromConstructing(bool b)
   1.978 +{
   1.979 +    return b ? INITIAL_CONSTRUCT : INITIAL_NONE;
   1.980 +}
   1.981 +
   1.982 +static inline bool
   1.983 +InitialFrameFlagsAreConstructing(InitialFrameFlags initial)
   1.984 +{
   1.985 +    return !!(initial & INITIAL_CONSTRUCT);
   1.986 +}
   1.987 +
   1.988 +/*****************************************************************************/
   1.989 +
   1.990 +class InterpreterRegs
   1.991 +{
   1.992 +  public:
   1.993 +    Value *sp;
   1.994 +    jsbytecode *pc;
   1.995 +  private:
   1.996 +    InterpreterFrame *fp_;
   1.997 +  public:
   1.998 +    InterpreterFrame *fp() const { return fp_; }
   1.999 +
  1.1000 +    unsigned stackDepth() const {
  1.1001 +        JS_ASSERT(sp >= fp_->base());
  1.1002 +        return sp - fp_->base();
  1.1003 +    }
  1.1004 +
  1.1005 +    Value *spForStackDepth(unsigned depth) const {
  1.1006 +        JS_ASSERT(fp_->script()->nfixed() + depth <= fp_->script()->nslots());
  1.1007 +        return fp_->base() + depth;
  1.1008 +    }
  1.1009 +
  1.1010 +    /* For generators. */
  1.1011 +    void rebaseFromTo(const InterpreterRegs &from, InterpreterFrame &to) {
  1.1012 +        fp_ = &to;
  1.1013 +        sp = to.slots() + (from.sp - from.fp_->slots());
  1.1014 +        pc = from.pc;
  1.1015 +        JS_ASSERT(fp_);
  1.1016 +    }
  1.1017 +
  1.1018 +    void popInlineFrame() {
  1.1019 +        pc = fp_->prevpc();
  1.1020 +        sp = fp_->prevsp() - fp_->numActualArgs() - 1;
  1.1021 +        fp_ = fp_->prev();
  1.1022 +        JS_ASSERT(fp_);
  1.1023 +    }
  1.1024 +    void prepareToRun(InterpreterFrame &fp, JSScript *script) {
  1.1025 +        pc = script->code();
  1.1026 +        sp = fp.slots() + script->nfixed();
  1.1027 +        fp_ = &fp;
  1.1028 +    }
  1.1029 +
  1.1030 +    void setToEndOfScript();
  1.1031 +
  1.1032 +    MutableHandleValue stackHandleAt(int i) {
  1.1033 +        return MutableHandleValue::fromMarkedLocation(&sp[i]);
  1.1034 +    }
  1.1035 +
  1.1036 +    HandleValue stackHandleAt(int i) const {
  1.1037 +        return HandleValue::fromMarkedLocation(&sp[i]);
  1.1038 +    }
  1.1039 +};
  1.1040 +
  1.1041 +/*****************************************************************************/
  1.1042 +
  1.1043 +class InterpreterStack
  1.1044 +{
  1.1045 +    friend class InterpreterActivation;
  1.1046 +
  1.1047 +    static const size_t DEFAULT_CHUNK_SIZE = 4 * 1024;
  1.1048 +    LifoAlloc allocator_;
  1.1049 +
  1.1050 +    // Number of interpreter frames on the stack, for over-recursion checks.
  1.1051 +    static const size_t MAX_FRAMES = 50 * 1000;
  1.1052 +    static const size_t MAX_FRAMES_TRUSTED = MAX_FRAMES + 1000;
  1.1053 +    size_t frameCount_;
  1.1054 +
  1.1055 +    inline uint8_t *allocateFrame(JSContext *cx, size_t size);
  1.1056 +
  1.1057 +    inline InterpreterFrame *
  1.1058 +    getCallFrame(JSContext *cx, const CallArgs &args, HandleScript script,
  1.1059 +                 InterpreterFrame::Flags *pflags, Value **pargv);
  1.1060 +
  1.1061 +    void releaseFrame(InterpreterFrame *fp) {
  1.1062 +        frameCount_--;
  1.1063 +        allocator_.release(fp->mark_);
  1.1064 +    }
  1.1065 +
  1.1066 +  public:
  1.1067 +    InterpreterStack()
  1.1068 +      : allocator_(DEFAULT_CHUNK_SIZE),
  1.1069 +        frameCount_(0)
  1.1070 +    { }
  1.1071 +
  1.1072 +    ~InterpreterStack() {
  1.1073 +        JS_ASSERT(frameCount_ == 0);
  1.1074 +    }
  1.1075 +
  1.1076 +    // For execution of eval or global code.
  1.1077 +    InterpreterFrame *pushExecuteFrame(JSContext *cx, HandleScript script, const Value &thisv,
  1.1078 +                                 HandleObject scopeChain, ExecuteType type,
  1.1079 +                                 AbstractFramePtr evalInFrame);
  1.1080 +
  1.1081 +    // Called to invoke a function.
  1.1082 +    InterpreterFrame *pushInvokeFrame(JSContext *cx, const CallArgs &args,
  1.1083 +                                      InitialFrameFlags initial);
  1.1084 +
  1.1085 +    // The interpreter can push light-weight, "inline" frames without entering a
  1.1086 +    // new InterpreterActivation or recursively calling Interpret.
  1.1087 +    bool pushInlineFrame(JSContext *cx, InterpreterRegs &regs, const CallArgs &args,
  1.1088 +                         HandleScript script, InitialFrameFlags initial);
  1.1089 +
  1.1090 +    void popInlineFrame(InterpreterRegs &regs);
  1.1091 +
  1.1092 +    inline void purge(JSRuntime *rt);
  1.1093 +
  1.1094 +    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  1.1095 +        return allocator_.sizeOfExcludingThis(mallocSizeOf);
  1.1096 +    }
  1.1097 +};
  1.1098 +
  1.1099 +void MarkInterpreterActivations(JSRuntime *rt, JSTracer *trc);
  1.1100 +
  1.1101 +/*****************************************************************************/
  1.1102 +
  1.1103 +class InvokeArgs : public JS::CallArgs
  1.1104 +{
  1.1105 +    AutoValueVector v_;
  1.1106 +
  1.1107 +  public:
  1.1108 +    InvokeArgs(JSContext *cx) : v_(cx) {}
  1.1109 +
  1.1110 +    bool init(unsigned argc) {
  1.1111 +        if (!v_.resize(2 + argc))
  1.1112 +            return false;
  1.1113 +        ImplicitCast<CallArgs>(*this) = CallArgsFromVp(argc, v_.begin());
  1.1114 +        return true;
  1.1115 +    }
  1.1116 +};
  1.1117 +
  1.1118 +template <>
  1.1119 +struct DefaultHasher<AbstractFramePtr> {
  1.1120 +    typedef AbstractFramePtr Lookup;
  1.1121 +
  1.1122 +    static js::HashNumber hash(const Lookup &key) {
  1.1123 +        return size_t(key.raw());
  1.1124 +    }
  1.1125 +
  1.1126 +    static bool match(const AbstractFramePtr &k, const Lookup &l) {
  1.1127 +        return k == l;
  1.1128 +    }
  1.1129 +};
  1.1130 +
  1.1131 +/*****************************************************************************/
  1.1132 +
  1.1133 +class InterpreterActivation;
  1.1134 +class ForkJoinActivation;
  1.1135 +class AsmJSActivation;
  1.1136 +
  1.1137 +namespace jit {
  1.1138 +    class JitActivation;
  1.1139 +};
  1.1140 +
  1.1141 +class Activation
  1.1142 +{
  1.1143 +  protected:
  1.1144 +    JSContext *cx_;
  1.1145 +    JSCompartment *compartment_;
  1.1146 +    Activation *prev_;
  1.1147 +
  1.1148 +    // Counter incremented by JS_SaveFrameChain on the top-most activation and
  1.1149 +    // decremented by JS_RestoreFrameChain. If > 0, ScriptFrameIter should stop
  1.1150 +    // iterating when it reaches this activation (if GO_THROUGH_SAVED is not
  1.1151 +    // set).
  1.1152 +    size_t savedFrameChain_;
  1.1153 +
  1.1154 +    // Counter incremented by JS::HideScriptedCaller and decremented by
  1.1155 +    // JS::UnhideScriptedCaller. If > 0 for the top activation,
  1.1156 +    // DescribeScriptedCaller will return null instead of querying that
  1.1157 +    // activation, which should prompt the caller to consult embedding-specific
  1.1158 +    // data structures instead.
  1.1159 +    size_t hideScriptedCallerCount_;
  1.1160 +
  1.1161 +    enum Kind { Interpreter, Jit, ForkJoin, AsmJS };
  1.1162 +    Kind kind_;
  1.1163 +
  1.1164 +    inline Activation(JSContext *cx, Kind kind_);
  1.1165 +    inline ~Activation();
  1.1166 +
  1.1167 +  public:
  1.1168 +    JSContext *cx() const {
  1.1169 +        return cx_;
  1.1170 +    }
  1.1171 +    JSCompartment *compartment() const {
  1.1172 +        return compartment_;
  1.1173 +    }
  1.1174 +    Activation *prev() const {
  1.1175 +        return prev_;
  1.1176 +    }
  1.1177 +
  1.1178 +    bool isInterpreter() const {
  1.1179 +        return kind_ == Interpreter;
  1.1180 +    }
  1.1181 +    bool isJit() const {
  1.1182 +        return kind_ == Jit;
  1.1183 +    }
  1.1184 +    bool isForkJoin() const {
  1.1185 +        return kind_ == ForkJoin;
  1.1186 +    }
  1.1187 +    bool isAsmJS() const {
  1.1188 +        return kind_ == AsmJS;
  1.1189 +    }
  1.1190 +
  1.1191 +    InterpreterActivation *asInterpreter() const {
  1.1192 +        JS_ASSERT(isInterpreter());
  1.1193 +        return (InterpreterActivation *)this;
  1.1194 +    }
  1.1195 +    jit::JitActivation *asJit() const {
  1.1196 +        JS_ASSERT(isJit());
  1.1197 +        return (jit::JitActivation *)this;
  1.1198 +    }
  1.1199 +    ForkJoinActivation *asForkJoin() const {
  1.1200 +        JS_ASSERT(isForkJoin());
  1.1201 +        return (ForkJoinActivation *)this;
  1.1202 +    }
  1.1203 +    AsmJSActivation *asAsmJS() const {
  1.1204 +        JS_ASSERT(isAsmJS());
  1.1205 +        return (AsmJSActivation *)this;
  1.1206 +    }
  1.1207 +
  1.1208 +    void saveFrameChain() {
  1.1209 +        savedFrameChain_++;
  1.1210 +    }
  1.1211 +    void restoreFrameChain() {
  1.1212 +        JS_ASSERT(savedFrameChain_ > 0);
  1.1213 +        savedFrameChain_--;
  1.1214 +    }
  1.1215 +    bool hasSavedFrameChain() const {
  1.1216 +        return savedFrameChain_ > 0;
  1.1217 +    }
  1.1218 +
  1.1219 +    void hideScriptedCaller() {
  1.1220 +        hideScriptedCallerCount_++;
  1.1221 +    }
  1.1222 +    void unhideScriptedCaller() {
  1.1223 +        JS_ASSERT(hideScriptedCallerCount_ > 0);
  1.1224 +        hideScriptedCallerCount_--;
  1.1225 +    }
  1.1226 +    bool scriptedCallerIsHidden() const {
  1.1227 +        return hideScriptedCallerCount_ > 0;
  1.1228 +    }
  1.1229 +
  1.1230 +  private:
  1.1231 +    Activation(const Activation &other) MOZ_DELETE;
  1.1232 +    void operator=(const Activation &other) MOZ_DELETE;
  1.1233 +};
  1.1234 +
  1.1235 +// This variable holds a special opcode value which is greater than all normal
  1.1236 +// opcodes, and is chosen such that the bitwise or of this value with any
  1.1237 +// opcode is this value.
  1.1238 +static const jsbytecode EnableInterruptsPseudoOpcode = -1;
  1.1239 +
  1.1240 +static_assert(EnableInterruptsPseudoOpcode >= JSOP_LIMIT,
  1.1241 +              "EnableInterruptsPseudoOpcode must be greater than any opcode");
  1.1242 +static_assert(EnableInterruptsPseudoOpcode == jsbytecode(-1),
  1.1243 +              "EnableInterruptsPseudoOpcode must be the maximum jsbytecode value");
  1.1244 +
  1.1245 +class InterpreterFrameIterator;
  1.1246 +class RunState;
  1.1247 +
  1.1248 +class InterpreterActivation : public Activation
  1.1249 +{
  1.1250 +    friend class js::InterpreterFrameIterator;
  1.1251 +
  1.1252 +    RunState &state_;
  1.1253 +    InterpreterRegs regs_;
  1.1254 +    InterpreterFrame *entryFrame_;
  1.1255 +    size_t opMask_; // For debugger interrupts, see js::Interpret.
  1.1256 +
  1.1257 +#ifdef DEBUG
  1.1258 +    size_t oldFrameCount_;
  1.1259 +#endif
  1.1260 +
  1.1261 +  public:
  1.1262 +    inline InterpreterActivation(RunState &state, JSContext *cx, InterpreterFrame *entryFrame);
  1.1263 +    inline ~InterpreterActivation();
  1.1264 +
  1.1265 +    inline bool pushInlineFrame(const CallArgs &args, HandleScript script,
  1.1266 +                                InitialFrameFlags initial);
  1.1267 +    inline void popInlineFrame(InterpreterFrame *frame);
  1.1268 +
  1.1269 +    InterpreterFrame *current() const {
  1.1270 +        return regs_.fp();
  1.1271 +    }
  1.1272 +    InterpreterRegs &regs() {
  1.1273 +        return regs_;
  1.1274 +    }
  1.1275 +    InterpreterFrame *entryFrame() const {
  1.1276 +        return entryFrame_;
  1.1277 +    }
  1.1278 +    size_t opMask() const {
  1.1279 +        return opMask_;
  1.1280 +    }
  1.1281 +
  1.1282 +    // If this js::Interpret frame is running |script|, enable interrupts.
  1.1283 +    void enableInterruptsIfRunning(JSScript *script) {
  1.1284 +        if (regs_.fp()->script() == script)
  1.1285 +            enableInterruptsUnconditionally();
  1.1286 +    }
  1.1287 +    void enableInterruptsUnconditionally() {
  1.1288 +        opMask_ = EnableInterruptsPseudoOpcode;
  1.1289 +    }
  1.1290 +    void clearInterruptsMask() {
  1.1291 +        opMask_ = 0;
  1.1292 +    }
  1.1293 +};
  1.1294 +
  1.1295 +// Iterates over a runtime's activation list.
  1.1296 +class ActivationIterator
  1.1297 +{
  1.1298 +    uint8_t *jitTop_;
  1.1299 +
  1.1300 +  protected:
  1.1301 +    Activation *activation_;
  1.1302 +
  1.1303 +  private:
  1.1304 +    void settle();
  1.1305 +
  1.1306 +  public:
  1.1307 +    explicit ActivationIterator(JSRuntime *rt);
  1.1308 +
  1.1309 +    ActivationIterator &operator++();
  1.1310 +
  1.1311 +    Activation *operator->() const {
  1.1312 +        return activation_;
  1.1313 +    }
  1.1314 +    Activation *activation() const {
  1.1315 +        return activation_;
  1.1316 +    }
  1.1317 +    uint8_t *jitTop() const {
  1.1318 +        JS_ASSERT(activation_->isJit());
  1.1319 +        return jitTop_;
  1.1320 +    }
  1.1321 +    bool done() const {
  1.1322 +        return activation_ == nullptr;
  1.1323 +    }
  1.1324 +};
  1.1325 +
  1.1326 +namespace jit {
  1.1327 +
  1.1328 +// A JitActivation is used for frames running in Baseline or Ion.
  1.1329 +class JitActivation : public Activation
  1.1330 +{
  1.1331 +    uint8_t *prevIonTop_;
  1.1332 +    JSContext *prevJitJSContext_;
  1.1333 +    bool firstFrameIsConstructing_;
  1.1334 +    bool active_;
  1.1335 +
  1.1336 +#ifdef JS_ION
  1.1337 +    // Rematerialized Ion frames which has info copied out of snapshots. Maps
  1.1338 +    // frame pointers (i.e. ionTop) to a vector of rematerializations of all
  1.1339 +    // inline frames associated with that frame.
  1.1340 +    //
  1.1341 +    // This table is lazily initialized by calling getRematerializedFrame.
  1.1342 +    typedef Vector<RematerializedFrame *, 1> RematerializedFrameVector;
  1.1343 +    typedef HashMap<uint8_t *, RematerializedFrameVector> RematerializedFrameTable;
  1.1344 +    RematerializedFrameTable rematerializedFrames_;
  1.1345 +
  1.1346 +    void freeRematerializedFramesInVector(RematerializedFrameVector &frames);
  1.1347 +    void clearRematerializedFrames();
  1.1348 +#endif
  1.1349 +
  1.1350 +#ifdef CHECK_OSIPOINT_REGISTERS
  1.1351 +  protected:
  1.1352 +    // Used to verify that live registers don't change between a VM call and
  1.1353 +    // the OsiPoint that follows it. Protected to silence Clang warning.
  1.1354 +    uint32_t checkRegs_;
  1.1355 +    RegisterDump regs_;
  1.1356 +#endif
  1.1357 +
  1.1358 +  public:
  1.1359 +    JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active = true);
  1.1360 +    ~JitActivation();
  1.1361 +
  1.1362 +    bool isActive() const {
  1.1363 +        return active_;
  1.1364 +    }
  1.1365 +    void setActive(JSContext *cx, bool active = true);
  1.1366 +
  1.1367 +    uint8_t *prevIonTop() const {
  1.1368 +        return prevIonTop_;
  1.1369 +    }
  1.1370 +    JSCompartment *compartment() const {
  1.1371 +        return compartment_;
  1.1372 +    }
  1.1373 +    bool firstFrameIsConstructing() const {
  1.1374 +        return firstFrameIsConstructing_;
  1.1375 +    }
  1.1376 +    static size_t offsetOfPrevIonTop() {
  1.1377 +        return offsetof(JitActivation, prevIonTop_);
  1.1378 +    }
  1.1379 +    static size_t offsetOfPrevJitJSContext() {
  1.1380 +        return offsetof(JitActivation, prevJitJSContext_);
  1.1381 +    }
  1.1382 +    static size_t offsetOfActiveUint8() {
  1.1383 +        JS_ASSERT(sizeof(bool) == 1);
  1.1384 +        return offsetof(JitActivation, active_);
  1.1385 +    }
  1.1386 +
  1.1387 +#ifdef CHECK_OSIPOINT_REGISTERS
  1.1388 +    void setCheckRegs(bool check) {
  1.1389 +        checkRegs_ = check;
  1.1390 +    }
  1.1391 +    static size_t offsetOfCheckRegs() {
  1.1392 +        return offsetof(JitActivation, checkRegs_);
  1.1393 +    }
  1.1394 +    static size_t offsetOfRegs() {
  1.1395 +        return offsetof(JitActivation, regs_);
  1.1396 +    }
  1.1397 +#endif
  1.1398 +
  1.1399 +#ifdef JS_ION
  1.1400 +    // Look up a rematerialized frame keyed by the fp, rematerializing the
  1.1401 +    // frame if one doesn't already exist. A frame can only be rematerialized
  1.1402 +    // if an IonFrameIterator pointing to the nearest uninlined frame can be
  1.1403 +    // provided, as values need to be read out of snapshots.
  1.1404 +    //
  1.1405 +    // The inlineDepth must be within bounds of the frame pointed to by iter.
  1.1406 +    RematerializedFrame *getRematerializedFrame(JSContext *cx, JitFrameIterator &iter,
  1.1407 +                                                size_t inlineDepth = 0);
  1.1408 +
  1.1409 +    // Look up a rematerialized frame by the fp. If inlineDepth is out of
  1.1410 +    // bounds of what has been rematerialized, nullptr is returned.
  1.1411 +    RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
  1.1412 +
  1.1413 +    bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
  1.1414 +        return !!lookupRematerializedFrame(top, inlineDepth);
  1.1415 +    }
  1.1416 +
  1.1417 +    // Remove a previous rematerialization by fp.
  1.1418 +    void removeRematerializedFrame(uint8_t *top);
  1.1419 +
  1.1420 +    void markRematerializedFrames(JSTracer *trc);
  1.1421 +#endif
  1.1422 +};
  1.1423 +
  1.1424 +// A filtering of the ActivationIterator to only stop at JitActivations.
  1.1425 +class JitActivationIterator : public ActivationIterator
  1.1426 +{
  1.1427 +    void settle() {
  1.1428 +        while (!done() && !activation_->isJit())
  1.1429 +            ActivationIterator::operator++();
  1.1430 +    }
  1.1431 +
  1.1432 +  public:
  1.1433 +    explicit JitActivationIterator(JSRuntime *rt)
  1.1434 +      : ActivationIterator(rt)
  1.1435 +    {
  1.1436 +        settle();
  1.1437 +    }
  1.1438 +
  1.1439 +    JitActivationIterator &operator++() {
  1.1440 +        ActivationIterator::operator++();
  1.1441 +        settle();
  1.1442 +        return *this;
  1.1443 +    }
  1.1444 +
  1.1445 +    // Returns the bottom and top addresses of the current JitActivation.
  1.1446 +    void jitStackRange(uintptr_t *&min, uintptr_t *&end);
  1.1447 +};
  1.1448 +
  1.1449 +} // namespace jit
  1.1450 +
  1.1451 +// Iterates over the frames of a single InterpreterActivation.
  1.1452 +class InterpreterFrameIterator
  1.1453 +{
  1.1454 +    InterpreterActivation *activation_;
  1.1455 +    InterpreterFrame *fp_;
  1.1456 +    jsbytecode *pc_;
  1.1457 +    Value *sp_;
  1.1458 +
  1.1459 +  public:
  1.1460 +    explicit InterpreterFrameIterator(InterpreterActivation *activation)
  1.1461 +      : activation_(activation),
  1.1462 +        fp_(nullptr),
  1.1463 +        pc_(nullptr),
  1.1464 +        sp_(nullptr)
  1.1465 +    {
  1.1466 +        if (activation) {
  1.1467 +            fp_ = activation->current();
  1.1468 +            pc_ = activation->regs().pc;
  1.1469 +            sp_ = activation->regs().sp;
  1.1470 +        }
  1.1471 +    }
  1.1472 +
  1.1473 +    InterpreterFrame *frame() const {
  1.1474 +        JS_ASSERT(!done());
  1.1475 +        return fp_;
  1.1476 +    }
  1.1477 +    jsbytecode *pc() const {
  1.1478 +        JS_ASSERT(!done());
  1.1479 +        return pc_;
  1.1480 +    }
  1.1481 +    Value *sp() const {
  1.1482 +        JS_ASSERT(!done());
  1.1483 +        return sp_;
  1.1484 +    }
  1.1485 +
  1.1486 +    InterpreterFrameIterator &operator++();
  1.1487 +
  1.1488 +    bool done() const {
  1.1489 +        return fp_ == nullptr;
  1.1490 +    }
  1.1491 +};
  1.1492 +
  1.1493 +// An AsmJSActivation is part of two activation linked lists:
  1.1494 +//  - the normal Activation list used by FrameIter
  1.1495 +//  - a list of only AsmJSActivations that is signal-safe since it is accessed
  1.1496 +//    from the profiler at arbitrary points
  1.1497 +//
  1.1498 +// An eventual goal is to remove AsmJSActivation and to run asm.js code in a
  1.1499 +// JitActivation interleaved with Ion/Baseline jit code. This would allow
  1.1500 +// efficient calls back and forth but requires that we can walk the stack for
  1.1501 +// all kinds of jit code.
  1.1502 +class AsmJSActivation : public Activation
  1.1503 +{
  1.1504 +    AsmJSModule &module_;
  1.1505 +    AsmJSActivation *prevAsmJS_;
  1.1506 +    void *errorRejoinSP_;
  1.1507 +    SPSProfiler *profiler_;
  1.1508 +    void *resumePC_;
  1.1509 +    uint8_t *exitSP_;
  1.1510 +
  1.1511 +    static const intptr_t InterruptedSP = -1;
  1.1512 +
  1.1513 +  public:
  1.1514 +    AsmJSActivation(JSContext *cx, AsmJSModule &module);
  1.1515 +    ~AsmJSActivation();
  1.1516 +
  1.1517 +    JSContext *cx() { return cx_; }
  1.1518 +    AsmJSModule &module() const { return module_; }
  1.1519 +    AsmJSActivation *prevAsmJS() const { return prevAsmJS_; }
  1.1520 +
  1.1521 +    // Read by JIT code:
  1.1522 +    static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); }
  1.1523 +    static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); }
  1.1524 +
  1.1525 +    // Initialized by JIT code:
  1.1526 +    static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
  1.1527 +    static unsigned offsetOfExitSP() { return offsetof(AsmJSActivation, exitSP_); }
  1.1528 +
  1.1529 +    // Set from SIGSEGV handler:
  1.1530 +    void setInterrupted(void *pc) { resumePC_ = pc; exitSP_ = (uint8_t*)InterruptedSP; }
  1.1531 +    bool isInterruptedSP() const { return exitSP_ == (uint8_t*)InterruptedSP; }
  1.1532 +
  1.1533 +    // Note: exitSP is the sp right before the call instruction. On x86, this
  1.1534 +    // means before the return address is pushed on the stack, on ARM, this
  1.1535 +    // means after.
  1.1536 +    uint8_t *exitSP() const { JS_ASSERT(!isInterruptedSP()); return exitSP_; }
  1.1537 +};
  1.1538 +
  1.1539 +// A FrameIter walks over the runtime's stack of JS script activations,
  1.1540 +// abstracting over whether the JS scripts were running in the interpreter or
  1.1541 +// different modes of compiled code.
  1.1542 +//
  1.1543 +// FrameIter is parameterized by what it includes in the stack iteration:
  1.1544 +//  - The SavedOption controls whether FrameIter stops when it finds an
  1.1545 +//    activation that was set aside via JS_SaveFrameChain (and not yet retored
  1.1546 +//    by JS_RestoreFrameChain). (Hopefully this will go away.)
  1.1547 +//  - The ContextOption determines whether the iteration will view frames from
  1.1548 +//    all JSContexts or just the given JSContext. (Hopefully this will go away.)
  1.1549 +//  - When provided, the optional JSPrincipal argument will cause FrameIter to
  1.1550 +//    only show frames in globals whose JSPrincipals are subsumed (via
  1.1551 +//    JSSecurityCallbacks::subsume) by the given JSPrincipal.
  1.1552 +//
  1.1553 +// Additionally, there are derived FrameIter types that automatically skip
  1.1554 +// certain frames:
  1.1555 +//  - ScriptFrameIter only shows frames that have an associated JSScript
  1.1556 +//    (currently everything other than asm.js stack frames). When !hasScript(),
  1.1557 +//    clients must stick to the portion of the
  1.1558 +//    interface marked below.
  1.1559 +//  - NonBuiltinScriptFrameIter additionally filters out builtin (self-hosted)
  1.1560 +//    scripts.
  1.1561 +class FrameIter
  1.1562 +{
  1.1563 +  public:
  1.1564 +    enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
  1.1565 +    enum ContextOption { CURRENT_CONTEXT, ALL_CONTEXTS };
  1.1566 +    enum State { DONE, INTERP, JIT, ASMJS };
  1.1567 +
  1.1568 +    // Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
  1.1569 +    // the heap, so this structure should not contain any GC things.
  1.1570 +    struct Data
  1.1571 +    {
  1.1572 +        JSContext *     cx_;
  1.1573 +        SavedOption     savedOption_;
  1.1574 +        ContextOption   contextOption_;
  1.1575 +        JSPrincipals *  principals_;
  1.1576 +
  1.1577 +        State           state_;
  1.1578 +
  1.1579 +        jsbytecode *    pc_;
  1.1580 +
  1.1581 +        InterpreterFrameIterator interpFrames_;
  1.1582 +        ActivationIterator activations_;
  1.1583 +
  1.1584 +#ifdef JS_ION
  1.1585 +        jit::JitFrameIterator jitFrames_;
  1.1586 +        unsigned ionInlineFrameNo_;
  1.1587 +        AsmJSFrameIterator asmJSFrames_;
  1.1588 +#endif
  1.1589 +
  1.1590 +        Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption,
  1.1591 +             JSPrincipals *principals);
  1.1592 +        Data(const Data &other);
  1.1593 +    };
  1.1594 +
  1.1595 +    FrameIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
  1.1596 +    FrameIter(JSContext *cx, ContextOption, SavedOption, JSPrincipals* = nullptr);
  1.1597 +    FrameIter(const FrameIter &iter);
  1.1598 +    FrameIter(const Data &data);
  1.1599 +    FrameIter(AbstractFramePtr frame);
  1.1600 +
  1.1601 +    bool done() const { return data_.state_ == DONE; }
  1.1602 +
  1.1603 +    // -------------------------------------------------------
  1.1604 +    // The following functions can only be called when !done()
  1.1605 +    // -------------------------------------------------------
  1.1606 +
  1.1607 +    FrameIter &operator++();
  1.1608 +
  1.1609 +    JSCompartment *compartment() const;
  1.1610 +    Activation *activation() const { return data_.activations_.activation(); }
  1.1611 +
  1.1612 +    bool isInterp() const { JS_ASSERT(!done()); return data_.state_ == INTERP;  }
  1.1613 +    bool isJit() const { JS_ASSERT(!done()); return data_.state_ == JIT; }
  1.1614 +    bool isAsmJS() const { JS_ASSERT(!done()); return data_.state_ == ASMJS; }
  1.1615 +    inline bool isIon() const;
  1.1616 +    inline bool isBaseline() const;
  1.1617 +
  1.1618 +    bool isFunctionFrame() const;
  1.1619 +    bool isGlobalFrame() const;
  1.1620 +    bool isEvalFrame() const;
  1.1621 +    bool isNonEvalFunctionFrame() const;
  1.1622 +    bool isGeneratorFrame() const;
  1.1623 +    bool hasArgs() const { return isNonEvalFunctionFrame(); }
  1.1624 +
  1.1625 +    /*
  1.1626 +     * Get an abstract frame pointer dispatching to either an interpreter,
  1.1627 +     * baseline, or rematerialized optimized frame.
  1.1628 +     */
  1.1629 +    ScriptSource *scriptSource() const;
  1.1630 +    const char *scriptFilename() const;
  1.1631 +    unsigned computeLine(uint32_t *column = nullptr) const;
  1.1632 +    JSAtom *functionDisplayAtom() const;
  1.1633 +    JSPrincipals *originPrincipals() const;
  1.1634 +
  1.1635 +    bool hasScript() const { return !isAsmJS(); }
  1.1636 +
  1.1637 +    // -----------------------------------------------------------
  1.1638 +    // The following functions can only be called when hasScript()
  1.1639 +    // -----------------------------------------------------------
  1.1640 +
  1.1641 +    inline JSScript *script() const;
  1.1642 +
  1.1643 +    bool        isConstructing() const;
  1.1644 +    jsbytecode *pc() const { JS_ASSERT(!done()); return data_.pc_; }
  1.1645 +    void        updatePcQuadratic();
  1.1646 +    JSFunction *callee() const;
  1.1647 +    Value       calleev() const;
  1.1648 +    unsigned    numActualArgs() const;
  1.1649 +    unsigned    numFormalArgs() const;
  1.1650 +    Value       unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
  1.1651 +    template <class Op> inline void unaliasedForEachActual(JSContext *cx, Op op);
  1.1652 +
  1.1653 +    JSObject   *scopeChain() const;
  1.1654 +    CallObject &callObj() const;
  1.1655 +
  1.1656 +    bool        hasArgsObj() const;
  1.1657 +    ArgumentsObject &argsObj() const;
  1.1658 +
  1.1659 +    // Ensure that computedThisValue is correct, see ComputeThis.
  1.1660 +    bool        computeThis(JSContext *cx) const;
  1.1661 +    // thisv() may not always be correct, even after computeThis. In case when
  1.1662 +    // the frame is an Ion frame, the computed this value cannot be saved to
  1.1663 +    // the Ion frame but is instead saved in the RematerializedFrame for use
  1.1664 +    // by Debugger.
  1.1665 +    //
  1.1666 +    // Both methods exist because of speed. thisv() will never rematerialize
  1.1667 +    // an Ion frame, whereas computedThisValue() will.
  1.1668 +    Value       computedThisValue() const;
  1.1669 +    Value       thisv() const;
  1.1670 +
  1.1671 +    Value       returnValue() const;
  1.1672 +    void        setReturnValue(const Value &v);
  1.1673 +
  1.1674 +    JSFunction *maybeCallee() const {
  1.1675 +        return isFunctionFrame() ? callee() : nullptr;
  1.1676 +    }
  1.1677 +
  1.1678 +    // These are only valid for the top frame.
  1.1679 +    size_t      numFrameSlots() const;
  1.1680 +    Value       frameSlotValue(size_t index) const;
  1.1681 +
  1.1682 +    // Ensures that we have rematerialized the top frame and its associated
  1.1683 +    // inline frames. Can only be called when isIon().
  1.1684 +    bool ensureHasRematerializedFrame();
  1.1685 +
  1.1686 +    // True when isInterp() or isBaseline(). True when isIon() if it
  1.1687 +    // has a rematerialized frame. False otherwise false otherwise.
  1.1688 +    bool hasUsableAbstractFramePtr() const;
  1.1689 +
  1.1690 +    // -----------------------------------------------------------
  1.1691 +    // The following functions can only be called when isInterp(),
  1.1692 +    // isBaseline(), or isIon(). Further, abstractFramePtr() can
  1.1693 +    // only be called when hasUsableAbstractFramePtr().
  1.1694 +    // -----------------------------------------------------------
  1.1695 +
  1.1696 +    AbstractFramePtr abstractFramePtr() const;
  1.1697 +    AbstractFramePtr copyDataAsAbstractFramePtr() const;
  1.1698 +    Data *copyData() const;
  1.1699 +
  1.1700 +    // This can only be called when isInterp():
  1.1701 +    inline InterpreterFrame *interpFrame() const;
  1.1702 +
  1.1703 +  private:
  1.1704 +    Data data_;
  1.1705 +#ifdef JS_ION
  1.1706 +    jit::InlineFrameIterator ionInlineFrames_;
  1.1707 +#endif
  1.1708 +
  1.1709 +    void popActivation();
  1.1710 +    void popInterpreterFrame();
  1.1711 +#ifdef JS_ION
  1.1712 +    void nextJitFrame();
  1.1713 +    void popJitFrame();
  1.1714 +    void popAsmJSFrame();
  1.1715 +#endif
  1.1716 +    void settleOnActivation();
  1.1717 +
  1.1718 +    friend class ::JSBrokenFrameIterator;
  1.1719 +};
  1.1720 +
  1.1721 +class ScriptFrameIter : public FrameIter
  1.1722 +{
  1.1723 +    void settle() {
  1.1724 +        while (!done() && !hasScript())
  1.1725 +            FrameIter::operator++();
  1.1726 +    }
  1.1727 +
  1.1728 +  public:
  1.1729 +    ScriptFrameIter(JSContext *cx, SavedOption savedOption = STOP_AT_SAVED)
  1.1730 +      : FrameIter(cx, savedOption)
  1.1731 +    {
  1.1732 +        settle();
  1.1733 +    }
  1.1734 +
  1.1735 +    ScriptFrameIter(JSContext *cx,
  1.1736 +                    ContextOption cxOption,
  1.1737 +                    SavedOption savedOption,
  1.1738 +                    JSPrincipals *prin = nullptr)
  1.1739 +      : FrameIter(cx, cxOption, savedOption, prin)
  1.1740 +    {
  1.1741 +        settle();
  1.1742 +    }
  1.1743 +
  1.1744 +    ScriptFrameIter(const ScriptFrameIter &iter) : FrameIter(iter) { settle(); }
  1.1745 +    ScriptFrameIter(const FrameIter::Data &data) : FrameIter(data) { settle(); }
  1.1746 +    ScriptFrameIter(AbstractFramePtr frame) : FrameIter(frame) { settle(); }
  1.1747 +
  1.1748 +    ScriptFrameIter &operator++() {
  1.1749 +        FrameIter::operator++();
  1.1750 +        settle();
  1.1751 +        return *this;
  1.1752 +    }
  1.1753 +};
  1.1754 +
  1.1755 +#ifdef DEBUG
  1.1756 +bool SelfHostedFramesVisible();
  1.1757 +#else
  1.1758 +static inline bool
  1.1759 +SelfHostedFramesVisible()
  1.1760 +{
  1.1761 +    return false;
  1.1762 +}
  1.1763 +#endif
  1.1764 +
  1.1765 +/* A filtering of the FrameIter to only stop at non-self-hosted scripts. */
  1.1766 +class NonBuiltinFrameIter : public FrameIter
  1.1767 +{
  1.1768 +    void settle();
  1.1769 +
  1.1770 +  public:
  1.1771 +    NonBuiltinFrameIter(JSContext *cx,
  1.1772 +                        FrameIter::SavedOption opt = FrameIter::STOP_AT_SAVED)
  1.1773 +      : FrameIter(cx, opt)
  1.1774 +    {
  1.1775 +        settle();
  1.1776 +    }
  1.1777 +
  1.1778 +    NonBuiltinFrameIter(JSContext *cx,
  1.1779 +                        FrameIter::ContextOption contextOption,
  1.1780 +                        FrameIter::SavedOption savedOption,
  1.1781 +                        JSPrincipals *principals = nullptr)
  1.1782 +      : FrameIter(cx, contextOption, savedOption, principals)
  1.1783 +    {
  1.1784 +        settle();
  1.1785 +    }
  1.1786 +
  1.1787 +    NonBuiltinFrameIter(const FrameIter::Data &data)
  1.1788 +      : FrameIter(data)
  1.1789 +    {}
  1.1790 +
  1.1791 +    NonBuiltinFrameIter &operator++() {
  1.1792 +        FrameIter::operator++();
  1.1793 +        settle();
  1.1794 +        return *this;
  1.1795 +    }
  1.1796 +};
  1.1797 +
  1.1798 +/* A filtering of the ScriptFrameIter to only stop at non-self-hosted scripts. */
  1.1799 +class NonBuiltinScriptFrameIter : public ScriptFrameIter
  1.1800 +{
  1.1801 +    void settle();
  1.1802 +
  1.1803 +  public:
  1.1804 +    NonBuiltinScriptFrameIter(JSContext *cx,
  1.1805 +                              ScriptFrameIter::SavedOption opt = ScriptFrameIter::STOP_AT_SAVED)
  1.1806 +      : ScriptFrameIter(cx, opt)
  1.1807 +    {
  1.1808 +        settle();
  1.1809 +    }
  1.1810 +
  1.1811 +    NonBuiltinScriptFrameIter(JSContext *cx,
  1.1812 +                              ScriptFrameIter::ContextOption contextOption,
  1.1813 +                              ScriptFrameIter::SavedOption savedOption,
  1.1814 +                              JSPrincipals *principals = nullptr)
  1.1815 +      : ScriptFrameIter(cx, contextOption, savedOption, principals)
  1.1816 +    {
  1.1817 +        settle();
  1.1818 +    }
  1.1819 +
  1.1820 +    NonBuiltinScriptFrameIter(const ScriptFrameIter::Data &data)
  1.1821 +      : ScriptFrameIter(data)
  1.1822 +    {}
  1.1823 +
  1.1824 +    NonBuiltinScriptFrameIter &operator++() {
  1.1825 +        ScriptFrameIter::operator++();
  1.1826 +        settle();
  1.1827 +        return *this;
  1.1828 +    }
  1.1829 +};
  1.1830 +
  1.1831 +/*
  1.1832 + * Blindly iterate over all frames in the current thread's stack. These frames
  1.1833 + * can be from different contexts and compartments, so beware.
  1.1834 + */
  1.1835 +class AllFramesIter : public ScriptFrameIter
  1.1836 +{
  1.1837 +  public:
  1.1838 +    AllFramesIter(JSContext *cx)
  1.1839 +      : ScriptFrameIter(cx, ScriptFrameIter::ALL_CONTEXTS, ScriptFrameIter::GO_THROUGH_SAVED)
  1.1840 +    {}
  1.1841 +};
  1.1842 +
  1.1843 +/* Popular inline definitions. */
  1.1844 +
  1.1845 +inline JSScript *
  1.1846 +FrameIter::script() const
  1.1847 +{
  1.1848 +    JS_ASSERT(!done());
  1.1849 +    if (data_.state_ == INTERP)
  1.1850 +        return interpFrame()->script();
  1.1851 +#ifdef JS_ION
  1.1852 +    JS_ASSERT(data_.state_ == JIT);
  1.1853 +    if (data_.jitFrames_.isIonJS())
  1.1854 +        return ionInlineFrames_.script();
  1.1855 +    return data_.jitFrames_.script();
  1.1856 +#else
  1.1857 +    return nullptr;
  1.1858 +#endif
  1.1859 +}
  1.1860 +
  1.1861 +inline bool
  1.1862 +FrameIter::isIon() const
  1.1863 +{
  1.1864 +#ifdef JS_ION
  1.1865 +    return isJit() && data_.jitFrames_.isIonJS();
  1.1866 +#else
  1.1867 +    return false;
  1.1868 +#endif
  1.1869 +}
  1.1870 +
  1.1871 +inline bool
  1.1872 +FrameIter::isBaseline() const
  1.1873 +{
  1.1874 +#ifdef JS_ION
  1.1875 +    return isJit() && data_.jitFrames_.isBaselineJS();
  1.1876 +#else
  1.1877 +    return false;
  1.1878 +#endif
  1.1879 +}
  1.1880 +
  1.1881 +inline InterpreterFrame *
  1.1882 +FrameIter::interpFrame() const
  1.1883 +{
  1.1884 +    JS_ASSERT(data_.state_ == INTERP);
  1.1885 +    return data_.interpFrames_.frame();
  1.1886 +}
  1.1887 +
  1.1888 +}  /* namespace js */
  1.1889 +#endif /* vm_Stack_h */

mercurial