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 ®s, const CallArgs &args, 1.1088 + HandleScript script, InitialFrameFlags initial); 1.1089 + 1.1090 + void popInlineFrame(InterpreterRegs ®s); 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 ®s() { 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 */