1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
* vim: set ts=4 sw=4 et tw=79 ft=cpp:
4
* This Source Code Form is subject to the terms of the Mozilla Public
5
* License, v. 2.0. If a copy of the MPL was not distributed with this
6
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13
#include "jsautooplen.h"
26
class InvokeArgsGuard;
27
class InvokeFrameGuard;
29
class ExecuteFrameGuard;
30
class GeneratorFrameGuard;
33
class ScriptFrameIter;
36
class ArgumentsObject;
38
class StaticBlockObject;
40
struct ScopeCoordinate;
45
class GetPropCompiler;
48
jsbytecode *NativeToPC(JITScript *jit, void *ncode, CallSite **pinline);
49
namespace ic { struct GetElementIC; }
51
typedef mjit::CallSite InlinedSite;
53
struct InlinedSite {};
55
typedef size_t FrameRejoinState;
57
/*****************************************************************************/
62
* SpiderMonkey uses a per-runtime stack to store the activation records,
63
* parameters, locals, and expression temporaries for the stack of actively
64
* executing scripts, functions and generators.
66
* The stack is subdivided into contiguous segments of memory which
67
* have a memory layout invariant that allows fixed offsets to be used for stack
68
* access (by jit code) as well as fast call/return. This memory layout is
69
* encapsulated by a set of types that describe different regions of memory.
70
* This encapsulation has holes: to avoid calling into C++ from generated code,
71
* JIT compilers generate code that simulates analogous operations in C++.
73
* A sample memory layout of a segment looks like:
76
* .------------------------------------------------.
78
* | fp .--FrameRegs--. sp
80
* |StackSegment| values |StackFrame| values |StackFrame| values |
82
* ? <-----------' `------------'
85
* A segment starts with a fixed-size header (js::StackSegment) which logically
86
* describes the segment, links it to the rest of the stack, and points to the
89
* Each script activation (global or function code) is given a fixed-size header
90
* (js::StackFrame) which is associated with the values before and after it.
91
* The frame contains bookkeeping information about the activation and links to
94
* The value preceding a (function) StackFrame in memory are the arguments of
95
* the call. The values after a StackFrame in memory are its locals followed by
96
* its expression stack. There is no clean line between the arguments of a
97
* frame and the expression stack of the previous frame since the top values of
98
* the expression become the arguments of a call. There are also layout
99
* invariants concerning the arguments and StackFrame; see "Arguments" comment
100
* in StackFrame for more details.
102
* The top of a segment's current frame's expression stack is pointed to by the
103
* segment's "current regs", which contains the stack pointer 'sp'. In the
104
* interpreter, sp is adjusted as individual values are pushed and popped from
105
* the stack and the FrameRegs struct (pointed by the StackSegment) is a local
106
* var of js::Interpret. JIT code simulates this by lazily updating FrameRegs
107
* when calling from JIT code into the VM. Ideally, we'd like to remove all
108
* dependence on FrameRegs outside the interpreter.
110
* A call to a native (C++) function does not push a frame. Instead, an array
111
* of values is passed to the native. The layout of this array is abstracted by
112
* JS::CallArgs. With respect to the StackSegment layout above, the args to a
113
* native call are inserted anywhere there can be values. A sample memory layout
117
* .------------------------------------------.
119
* | fp .--FrameRegs--. sp
121
* |StackSegment| native call | values |StackFrame| values | native call |
122
* | vp <--argc--> end vp <--argc--> end
123
* | CallArgs <------------------------------ CallArgs
125
* `-------------------------------------------------------'
128
* Here there are two native calls on the stack. The start of each native arg
129
* range is recorded by a CallArgs element which is prev-linked like stack
130
* frames. Note that, in full generality, native and scripted calls can
131
* interleave arbitrarily. Thus, the end of a segment is the maximum of its
132
* current frame and its current native call. Similarly, the top of the entire
133
* thread stack is the end of its current segment.
135
* Note that, between any two StackFrames there may be any number
136
* of native calls, so the meaning of 'prev' is not 'directly called by'.
138
* An additional feature (perhaps not for much longer: bug 650361) is that
139
* multiple independent "contexts" can interleave (LIFO) on a single contiguous
140
* stack. "Independent" here means that each context has its own callstack.
141
* Note, though, that eval-in-frame allows one context's callstack to join
142
* another context's callstack. Thus, in general, the structure of calls in a
143
* StackSpace is a forest.
145
* More concretely, an embedding may enter the JS engine on cx1 and then, from
146
* a native called by the JS engine, reenter the VM on cx2. Changing from cx1
147
* to cx2 causes a new segment to be started for cx2's stack on top of cx1's
148
* current segment. These two segments are linked from the perspective of
149
* StackSpace, since they are adjacent on the thread's stack, but not from the
150
* perspective of cx1 and cx2. Thus, each segment has two links: prevInMemory
151
* and prevInContext. Each independent stack is encapsulated and managed by
152
* the js::ContextStack object stored in JSContext. ContextStack is the primary
153
* interface to the rest of the engine for pushing and popping the stack.
156
/*****************************************************************************/
159
* For calls to natives, the InvokeArgsGuard object provides a record of the
160
* call for the debugger's callstack. For this to work, the InvokeArgsGuard
161
* record needs to know when the call is actually active (because the
162
* InvokeArgsGuard can be pushed long before and popped long after the actual
163
* call, during which time many stack-observing things can happen).
165
class CallArgsList : public JS::CallArgs
167
friend class StackSegment;
171
friend CallArgsList CallArgsListFromVp(unsigned, Value *, CallArgsList *);
172
friend CallArgsList CallArgsListFromArgv(unsigned, Value *, CallArgsList *);
173
CallArgsList *prev() const { return prev_; }
174
bool active() const { return active_; }
175
void setActive() { active_ = true; }
176
void setInactive() { active_ = false; }
179
JS_ALWAYS_INLINE CallArgsList
180
CallArgsListFromArgv(unsigned argc, Value *argv, CallArgsList *prev)
184
args.usedRval_ = false;
189
args.active_ = false;
193
JS_ALWAYS_INLINE CallArgsList
194
CallArgsListFromVp(unsigned argc, Value *vp, CallArgsList *prev)
196
return CallArgsListFromArgv(argc, vp + 2, prev);
199
/*****************************************************************************/
201
enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
203
/*****************************************************************************/
205
/* Flags specified for a frame as it is constructed. */
206
enum InitialFrameFlags {
208
INITIAL_CONSTRUCT = 0x20, /* == StackFrame::CONSTRUCTING, asserted below */
209
INITIAL_LOWERED = 0x80000 /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
213
EXECUTE_GLOBAL = 0x1, /* == StackFrame::GLOBAL */
214
EXECUTE_DIRECT_EVAL = 0x4, /* == StackFrame::EVAL */
215
EXECUTE_INDIRECT_EVAL = 0x5, /* == StackFrame::GLOBAL | EVAL */
216
EXECUTE_DEBUG = 0xc /* == StackFrame::EVAL | DEBUGGER */
219
/*****************************************************************************/
225
/* Primary frame type */
226
GLOBAL = 0x1, /* frame pushed for a global script */
227
FUNCTION = 0x2, /* frame pushed for a scripted call */
230
EVAL = 0x4, /* frame pushed for eval() or debugger eval */
231
DEBUGGER = 0x8, /* frame pushed for debugger eval */
232
GENERATOR = 0x10, /* frame is associated with a generator */
233
CONSTRUCTING = 0x20, /* frame is for a constructor invocation */
235
/* Temporary frame states */
236
YIELDING = 0x40, /* Interpret dispatched JSOP_YIELD */
237
FINISHED_IN_INTERP = 0x80, /* set if frame finished in Interpret() */
239
/* Function arguments */
240
OVERFLOW_ARGS = 0x100, /* numActualArgs > numFormalArgs */
241
UNDERFLOW_ARGS = 0x200, /* numActualArgs < numFormalArgs */
243
/* Function prologue state */
244
HAS_CALL_OBJ = 0x400, /* CallObject created for heavyweight fun */
245
HAS_ARGS_OBJ = 0x800, /* ArgumentsObject created for needsArgsObj script */
247
/* Lazy frame initialization */
248
HAS_HOOK_DATA = 0x1000, /* frame has hookData_ set */
249
HAS_ANNOTATION = 0x2000, /* frame has annotation_ set */
250
HAS_RVAL = 0x4000, /* frame has rval_ set */
251
HAS_SCOPECHAIN = 0x8000, /* frame has scopeChain_ set */
252
HAS_PREVPC = 0x10000, /* frame has prevpc_ and prevInline_ set */
253
HAS_BLOCKCHAIN = 0x20000, /* frame has blockChain_ set */
255
/* Method JIT state */
256
DOWN_FRAMES_EXPANDED = 0x40000, /* inlining in down frames has been expanded */
257
LOWERED_CALL_APPLY = 0x80000, /* Pushed by a lowered call/apply */
260
PREV_UP_TO_DATE = 0x100000, /* see DebugScopes::updateLiveScopes */
262
/* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
263
HAS_PUSHED_SPS_FRAME = 0x200000 /* SPS was notified of enty */
267
mutable uint32_t flags_; /* bits described by Flags */
268
union { /* describes what code is executing in a */
269
JSScript *script; /* global frame */
270
JSFunction *fun; /* function frame, pre GetScopeChain */
272
union { /* describes the arguments of a function */
273
unsigned nactual; /* for non-eval frames */
274
JSScript *evalScript; /* the script of an eval-in-function */
276
mutable JSObject *scopeChain_; /* if HAS_SCOPECHAIN, current scope chain */
277
StackFrame *prev_; /* if HAS_PREVPC, previous cx->regs->fp */
278
void *ncode_; /* for a jit frame, return address for method JIT */
279
Value rval_; /* if HAS_RVAL, return value of the frame */
280
StaticBlockObject *blockChain_; /* if HAS_BLOCKCHAIN, innermost let block */
281
ArgumentsObject *argsObj_; /* if HAS_ARGS_OBJ, the call's arguments object */
282
jsbytecode *prevpc_; /* if HAS_PREVPC, pc of previous frame*/
283
InlinedSite *prevInline_; /* for a jit frame, inlined site in previous frame */
284
void *hookData_; /* if HAS_HOOK_DATA, closure returned by call hook */
285
void *annotation_; /* if HAS_ANNOTATION, perhaps remove with bug 546848 */
286
FrameRejoinState rejoin_; /* for a jit frame rejoining the interpreter
287
* from JIT code, state at rejoin. */
289
static void staticAsserts() {
290
JS_STATIC_ASSERT(offsetof(StackFrame, rval_) % sizeof(Value) == 0);
291
JS_STATIC_ASSERT(sizeof(StackFrame) % sizeof(Value) == 0);
294
inline void initPrev(JSContext *cx);
295
jsbytecode *prevpcSlow(InlinedSite **pinlined);
296
void writeBarrierPost();
299
* These utilities provide raw access to the values associated with a
300
* StackFrame (see "VM stack layout" comment). The utilities are private
301
* since they are not able to assert that only unaliased vars/formals are
302
* accessed. Normal code should prefer the StackFrame::unaliased* members
303
* (or FrameRegs::stackDepth for the usual "depth is at least" assertions).
305
Value *slots() const { return (Value *)(this + 1); }
306
Value *base() const { return slots() + script()->nfixed; }
307
Value *formals() const { return (Value *)this - fun()->nargs; }
308
Value *actuals() const { return formals() - (flags_ & OVERFLOW_ARGS ? 2 + u.nactual : 0); }
310
friend class FrameRegs;
311
friend class ContextStack;
312
friend class StackSpace;
313
friend class StackIter;
314
friend class CallObject;
315
friend class ClonedBlockObject;
316
friend class ArgumentsObject;
318
friend class mjit::CallCompiler;
319
friend class mjit::GetPropCompiler;
320
friend struct mjit::ic::GetElementIC;
324
* Frame initialization, called by ContextStack operations after acquiring
325
* the raw memory for the frame:
328
/* Used for Invoke, Interpret, trace-jit LeaveTree, and method-jit stubs. */
329
void initCallFrame(JSContext *cx, JSFunction &callee,
330
JSScript *script, uint32_t nactual, StackFrame::Flags flags);
332
/* Used for getFixupFrame (for FixupArity). */
333
void initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncode, unsigned nactual);
336
void initExecuteFrame(JSScript *script, StackFrame *prev, FrameRegs *regs,
337
const Value &thisv, JSObject &scopeChain, ExecuteType type);
341
* Frame prologue/epilogue
343
* Every stack frame must have 'prologue' called before executing the
344
* first op and 'epilogue' called after executing the last op and before
345
* popping the frame (whether the exit is exceptional or not).
347
* For inline JS calls/returns, it is easy to call the prologue/epilogue
348
* exactly once. When calling JS from C++, Invoke/Execute push the stack
349
* frame but do *not* call the prologue/epilogue. That means Interpret
350
* must call the prologue/epilogue for the entry frame. This scheme
351
* simplifies jit compilation.
353
* An important corner case is what happens when an error occurs (OOM,
354
* over-recursed) after pushing the stack frame but before 'prologue' is
355
* called or completes fully. To simplify usage, 'epilogue' does not assume
356
* 'prologue' has completed and handles all the intermediate state details.
358
* The 'newType' option indicates whether the constructed 'this' value (if
359
* there is one) should be given a new singleton type.
362
bool prologue(JSContext *cx, bool newType);
363
void epilogue(JSContext *cx);
365
/* Subsets of 'prologue' called from jit code. */
366
inline bool jitHeavyweightFunctionPrologue(JSContext *cx);
367
bool jitStrictEvalPrologue(JSContext *cx);
369
/* Initialize local variables of newly-pushed frame. */
370
void initVarsToUndefined();
375
* A stack frame may have one of three types, which determines which
376
* members of the frame may be accessed and other invariants:
378
* global frame: execution of global code or an eval in global code
379
* function frame: execution of function code or an eval in a function
382
bool isFunctionFrame() const {
383
return !!(flags_ & FUNCTION);
386
bool isGlobalFrame() const {
387
return !!(flags_ & GLOBAL);
393
* As noted above, global and function frames may optionally be 'eval
394
* frames'. Eval code shares its parent's arguments which means that the
395
* arg-access members of StackFrame may not be used for eval frames.
396
* Search for 'hasArgs' below for more details.
398
* A further sub-classification of eval frames is whether the frame was
399
* pushed for an ES5 strict-mode eval().
402
bool isEvalFrame() const {
403
return flags_ & EVAL;
406
bool isEvalInFunction() const {
407
return (flags_ & (EVAL | FUNCTION)) == (EVAL | FUNCTION);
410
bool isNonEvalFunctionFrame() const {
411
return (flags_ & (FUNCTION | EVAL)) == FUNCTION;
414
inline bool isStrictEvalFrame() const {
415
return isEvalFrame() && script()->strictModeCode;
418
bool isNonStrictEvalFrame() const {
419
return isEvalFrame() && !script()->strictModeCode;
422
bool isDirectEvalFrame() const {
423
return isEvalFrame() && script()->staticLevel > 0;
426
bool isNonStrictDirectEvalFrame() const {
427
return isNonStrictEvalFrame() && isDirectEvalFrame();
433
* A frame's 'prev' frame is either null or the previous frame pointed to
434
* by cx->regs->fp when this frame was pushed. Often, given two prev-linked
435
* frames, the next-frame is a function or eval that was called by the
436
* prev-frame, but not always: the prev-frame may have called a native that
437
* reentered the VM through JS_CallFunctionValue on the same context
438
* (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
439
* 'prev' has little semantic meaning and basically just tells the VM what
440
* to set cx->regs->fp to when this frame is popped.
443
StackFrame *prev() const {
447
inline void resetGeneratorPrev(JSContext *cx);
450
* (Unaliased) locals and arguments
452
* Only non-eval function frames have arguments. The arguments pushed by
453
* the caller are the 'actual' arguments. The declared arguments of the
454
* callee are the 'formal' arguments. When the caller passes less or equal
455
* actual arguments, the actual and formal arguments are the same array
456
* (but with different extents). When the caller passes too many arguments,
457
* the formal subset of the actual arguments is copied onto the top of the
458
* stack. This allows the engine to maintain a jit-time constant offset of
459
* arguments from the frame pointer. Since the formal subset of the actual
460
* arguments is potentially on the stack twice, it is important for all
461
* reads/writes to refer to the same canonical memory location. This is
462
* abstracted by the unaliased{Formal,Actual} methods.
464
* When a local/formal variable is "aliased" (accessed by nested closures,
465
* dynamic scope operations, or 'arguments), the canonical location for
466
* that value is the slot of an activation object (scope or arguments).
467
* Currently, all variables are given slots in *both* the stack frame and
468
* heap objects, even though, as just described, only one should ever be
469
* accessed. Thus, it is up to the code performing an access to access the
470
* correct value. These functions assert that accesses to stack values are
471
* unaliased. For more about canonical values locations.
474
inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
475
inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
477
bool hasArgs() const { return isNonEvalFunctionFrame(); }
478
inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
479
inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
480
template <class Op> inline void forEachUnaliasedActual(Op op);
482
typedef Vector<Value, 16, SystemAllocPolicy> CopyVector;
483
bool copyRawFrameSlots(CopyVector *v);
485
inline unsigned numFormalArgs() const;
486
inline unsigned numActualArgs() const;
491
* If a non-eval function has script->needsArgsObj, an arguments object is
492
* created in the prologue and stored in the local variable for the
493
* 'arguments' binding (script->argumentsLocal). Since this local is
494
* mutable, the arguments object can be overwritten and we can "lose" the
495
* arguments object. Thus, StackFrame keeps an explicit argsObj_ field so
496
* that the original arguments object is always available.
499
ArgumentsObject &argsObj() const;
500
void initArgsObj(ArgumentsObject &argsobj);
502
inline JSObject *createRestParameter(JSContext *cx);
507
* In theory, the scope chain would contain an object for every lexical
508
* scope. However, only objects that are required for dynamic lookup are
511
* Given that a StackFrame corresponds roughly to a ES5 Execution Context
512
* (ES5 10.3), StackFrame::varObj corresponds to the VariableEnvironment
513
* component of a Exection Context. Intuitively, the variables object is
514
* where new bindings (variables and functions) are stored. One might
515
* expect that this is either the Call object or scopeChain.globalObj for
516
* function or global code, respectively, however the JSAPI allows calls of
517
* Execute to specify a variables object on the scope chain other than the
518
* call/global object. This allows embeddings to run multiple scripts under
519
* the same global, each time using a new variables object to collect and
520
* discard the script's global variables.
523
inline HandleObject scopeChain() const;
525
inline ScopeObject &aliasedVarScope(ScopeCoordinate sc) const;
526
inline GlobalObject &global() const;
527
inline CallObject &callObj() const;
528
inline JSObject &varObj();
530
inline void pushOnScopeChain(ScopeObject &scope);
531
inline void popOffScopeChain();
536
* Entering/leaving a let (or exception) block may do 1 or 2 things: First,
537
* a static block object (created at compiled time and stored in the
538
* script) is pushed on StackFrame::blockChain. Second, if the static block
539
* may be cloned to hold the dynamic values if this is needed for dynamic
540
* scope access. A clone is created for a static block iff
541
* StaticBlockObject::needsClone.
544
bool hasBlockChain() const {
545
return (flags_ & HAS_BLOCKCHAIN) && blockChain_;
548
StaticBlockObject *maybeBlockChain() {
549
return (flags_ & HAS_BLOCKCHAIN) ? blockChain_ : NULL;
552
StaticBlockObject &blockChain() const {
553
JS_ASSERT(hasBlockChain());
557
bool pushBlock(JSContext *cx, StaticBlockObject &block);
558
void popBlock(JSContext *cx);
563
* Entering/leaving a with (or E4X filter) block pushes/pops an object
564
* on the scope chain. Pushing uses pushOnScopeChain, popping should use
568
void popWith(JSContext *cx);
573
* All function and global frames have an associated JSScript which holds
574
* the bytecode being executed for the frame. This script/bytecode does
575
* not reflect any inlining that has been performed by the method JIT.
576
* If other frames were inlined into this one, the script/pc reflect the
577
* point of the outermost call. Inlined frame invariants:
579
* - Inlined frames have the same scope chain as the outer frame.
580
* - Inlined frames have the same strictness as the outer frame.
581
* - Inlined frames can only make calls to other JIT frames associated with
582
* the same VMFrame. Other calls force expansion of the inlined frames.
585
JSScript *script() const {
586
return isFunctionFrame()
587
? isEvalFrame() ? u.evalScript : fun()->script()
592
* Get the frame's current bytecode, assuming 'this' is in 'stack'. Beware,
593
* as the name implies, pcQuadratic can lead to quadratic behavior in loops
596
* for ( ...; fp; fp = fp->prev())
597
* ... fp->pcQuadratic(cx->stack);
599
* This can be avoided in three ways:
600
* - use ScriptFrameIter, it has O(1) iteration
601
* - if you know the next frame (i.e., next s.t. next->prev == fp
602
* - pcQuadratic will only iterate maxDepth frames (before giving up and
603
* returning fp->script->code), making it O(1), but incorrect.
606
jsbytecode *pcQuadratic(const ContextStack &stack, size_t maxDepth = SIZE_MAX);
608
/* Return the previous frame's pc. Unlike pcQuadratic, this is O(1). */
609
jsbytecode *prevpc(InlinedSite **pinlined = NULL) {
610
if (flags_ & HAS_PREVPC) {
612
*pinlined = prevInline_;
615
return prevpcSlow(pinlined);
618
InlinedSite *prevInline() {
619
JS_ASSERT(flags_ & HAS_PREVPC);
626
* All function frames have an associated interpreted JSFunction. The
627
* function returned by fun() and maybeFun() is not necessarily the
628
* original canonical function which the frame's script was compiled
629
* against. To get this function, use maybeScriptFunction().
632
JSFunction* fun() const {
633
JS_ASSERT(isFunctionFrame());
637
JSFunction* maybeFun() const {
638
return isFunctionFrame() ? fun() : NULL;
641
JSFunction* maybeScriptFunction() const {
642
if (!isFunctionFrame())
644
const StackFrame *fp = this;
645
while (fp->isEvalFrame())
647
return fp->script()->function();
653
* Every frame has a this value although, until 'this' is computed, the
654
* value may not be the semantically-correct 'this' value.
656
* The 'this' value is stored before the formal arguments for function
657
* frames and directly before the frame for global frames. The *Args
658
* members assert !isEvalFrame(), so we implement specialized inline
659
* methods for accessing 'this'. When the caller has static knowledge that
660
* a frame is a function, 'functionThis' allows more efficient access.
663
Value &functionThis() const {
664
JS_ASSERT(isFunctionFrame());
666
return ((Value *)this)[-1];
667
return formals()[-1];
670
JSObject &constructorThis() const {
671
JS_ASSERT(hasArgs());
672
return formals()[-1].toObject();
675
Value &thisValue() const {
676
if (flags_ & (EVAL | GLOBAL))
677
return ((Value *)this)[-1];
678
return formals()[-1];
684
* Only function frames have a callee. An eval frame in a function has the
685
* same callee as its containing function frame. maybeCalleev can be used
686
* to return a value that is either the callee object (for function frames) or
687
* null (for global frames).
690
JSFunction &callee() const {
691
JS_ASSERT(isFunctionFrame());
692
return *calleev().toObject().toFunction();
695
const Value &calleev() const {
696
JS_ASSERT(isFunctionFrame());
697
return mutableCalleev();
700
const Value &maybeCalleev() const {
701
Value &calleev = flags_ & (EVAL | GLOBAL)
702
? ((Value *)this)[-2]
704
JS_ASSERT(calleev.isObjectOrNull());
708
Value &mutableCalleev() const {
709
JS_ASSERT(isFunctionFrame());
711
return ((Value *)this)[-2];
712
return formals()[-2];
715
CallReceiver callReceiver() const {
716
return CallReceiverFromArgv(formals());
722
* A stack frame's compartment is the frame's containing context's
723
* compartment when the frame was pushed.
726
inline JSCompartment *compartment() const;
728
/* Annotation (will be removed after bug 546848) */
730
void* annotation() const {
731
return (flags_ & HAS_ANNOTATION) ? annotation_ : NULL;
734
void setAnnotation(void *annot) {
735
flags_ |= HAS_ANNOTATION;
739
/* JIT rejoin state */
741
FrameRejoinState rejoin() const {
745
void setRejoin(FrameRejoinState state) {
749
/* Down frame expansion state */
751
void setDownFramesExpanded() {
752
flags_ |= DOWN_FRAMES_EXPANDED;
755
bool downFramesExpanded() {
756
return !!(flags_ & DOWN_FRAMES_EXPANDED);
759
/* Debugger hook data */
761
bool hasHookData() const {
762
return !!(flags_ & HAS_HOOK_DATA);
765
void* hookData() const {
766
JS_ASSERT(hasHookData());
770
void* maybeHookData() const {
771
return hasHookData() ? hookData_ : NULL;
774
void setHookData(void *v) {
776
flags_ |= HAS_HOOK_DATA;
779
bool hasPushedSPSFrame() {
780
return !!(flags_ & HAS_PUSHED_SPS_FRAME);
783
void setPushedSPSFrame() {
784
flags_ |= HAS_PUSHED_SPS_FRAME;
789
bool hasReturnValue() const {
790
return !!(flags_ & HAS_RVAL);
793
Value &returnValue() {
794
if (!(flags_ & HAS_RVAL))
795
rval_.setUndefined();
799
void markReturnValue() {
803
void setReturnValue(const Value &v) {
808
void clearReturnValue() {
809
rval_.setUndefined();
813
/* Native-code return address */
815
void *nativeReturnAddress() const {
819
void setNativeReturnAddress(void *addr) {
823
void **addressOfNativeReturnAddress() {
828
* A "generator" frame is a function frame associated with a generator.
829
* Since generators are not executed LIFO, the VM copies a single abstract
830
* generator frame back and forth between the LIFO VM stack (when the
831
* generator is active) and a snapshot stored in JSGenerator (when the
832
* generator is inactive). A generator frame is comprised of a StackFrame
833
* structure and the values that make up the arguments, locals, and
834
* expression stack. The layout in the JSGenerator snapshot matches the
835
* layout on the stack (see the "VM stack layout" comment above).
838
bool isGeneratorFrame() const {
839
bool ret = flags_ & GENERATOR;
840
JS_ASSERT_IF(ret, isNonEvalFunctionFrame());
844
void initGeneratorFrame() const {
845
JS_ASSERT(!isGeneratorFrame());
846
JS_ASSERT(isNonEvalFunctionFrame());
850
Value *generatorArgsSnapshotBegin() const {
851
JS_ASSERT(isGeneratorFrame());
852
return actuals() - 2;
855
Value *generatorArgsSnapshotEnd() const {
856
JS_ASSERT(isGeneratorFrame());
857
return (Value *)this;
860
Value *generatorSlotsSnapshotBegin() const {
861
JS_ASSERT(isGeneratorFrame());
862
return (Value *)(this + 1);
865
enum TriggerPostBarriers {
866
DoPostBarrier = true,
867
NoPostBarrier = false
869
template <TriggerPostBarriers doPostBarrier>
870
void copyFrameAndValues(JSContext *cx, Value *vp, StackFrame *otherfp,
871
const Value *othervp, Value *othersp);
873
JSGenerator *maybeSuspendedGenerator(JSRuntime *rt);
876
* js::Execute pushes both global and function frames (since eval() in a
877
* function pushes a frame with isFunctionFrame() && isEvalFrame()). Most
878
* code should not care where a frame was pushed, but if it is necessary to
879
* pick out frames pushed by js::Execute, this is the right query:
882
bool isFramePushedByExecute() const {
883
return !!(flags_ & (GLOBAL | EVAL));
890
InitialFrameFlags initialFlags() const {
891
JS_STATIC_ASSERT((int)INITIAL_NONE == 0);
892
JS_STATIC_ASSERT((int)INITIAL_CONSTRUCT == (int)CONSTRUCTING);
893
JS_STATIC_ASSERT((int)INITIAL_LOWERED == (int)LOWERED_CALL_APPLY);
894
uint32_t mask = CONSTRUCTING | LOWERED_CALL_APPLY;
895
JS_ASSERT((flags_ & mask) != mask);
896
return InitialFrameFlags(flags_ & mask);
899
bool isConstructing() const {
900
return !!(flags_ & CONSTRUCTING);
904
* These two queries should not be used in general: the presence/absence of
905
* the call/args object is determined by the static(ish) properties of the
906
* JSFunction/JSScript. These queries should only be performed when probing
907
* a stack frame that may be in the middle of the prologue (during which
908
* time the call/args object are created).
911
bool hasCallObj() const {
912
JS_ASSERT(isStrictEvalFrame() || fun()->isHeavyweight());
913
return flags_ & HAS_CALL_OBJ;
916
bool hasArgsObj() const {
917
JS_ASSERT(script()->needsArgsObj());
918
return flags_ & HAS_ARGS_OBJ;
922
* The method JIT call/apply optimization can erase Function.{call,apply}
923
* invocations from the stack and push the callee frame directly. The base
924
* of these frames will be offset by one value, however, which the
925
* interpreter needs to account for if it ends up popping the frame.
927
bool loweredCallOrApply() const {
928
return !!(flags_ & LOWERED_CALL_APPLY);
931
bool isDebuggerFrame() const {
932
return !!(flags_ & DEBUGGER);
935
bool prevUpToDate() const {
936
return !!(flags_ & PREV_UP_TO_DATE);
939
void setPrevUpToDate() {
940
flags_ |= PREV_UP_TO_DATE;
944
return !!(flags_ & YIELDING);
951
void clearYielding() {
955
void setFinishedInInterpreter() {
956
flags_ |= FINISHED_IN_INTERP;
959
bool finishedInInterpreter() const {
960
return !!(flags_ & FINISHED_IN_INTERP);
964
/* Public, but only for JIT use: */
966
inline void resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc);
967
inline void initInlineFrame(JSFunction *fun, StackFrame *prevfp, jsbytecode *prevpc);
969
static size_t offsetOfFlags() {
970
return offsetof(StackFrame, flags_);
973
static size_t offsetOfExec() {
974
return offsetof(StackFrame, exec);
977
static size_t offsetOfNumActual() {
978
return offsetof(StackFrame, u.nactual);
981
static size_t offsetOfScopeChain() {
982
return offsetof(StackFrame, scopeChain_);
985
static size_t offsetOfPrev() {
986
return offsetof(StackFrame, prev_);
989
static size_t offsetOfReturnValue() {
990
return offsetof(StackFrame, rval_);
993
static ptrdiff_t offsetOfNcode() {
994
return offsetof(StackFrame, ncode_);
997
static ptrdiff_t offsetOfArgsObj() {
998
return offsetof(StackFrame, argsObj_);
1001
static ptrdiff_t offsetOfCallee(JSFunction *fun) {
1002
JS_ASSERT(fun != NULL);
1003
return -(fun->nargs + 2) * sizeof(Value);
1006
static ptrdiff_t offsetOfThis(JSFunction *fun) {
1008
? -1 * ptrdiff_t(sizeof(Value))
1009
: -(fun->nargs + 1) * ptrdiff_t(sizeof(Value));
1012
static ptrdiff_t offsetOfFormalArg(JSFunction *fun, unsigned i) {
1013
JS_ASSERT(i < fun->nargs);
1014
return (-(int)fun->nargs + i) * sizeof(Value);
1017
static size_t offsetOfFixed(unsigned i) {
1018
return sizeof(StackFrame) + i * sizeof(Value);
1022
inline mjit::JITScript *jit();
1025
void methodjitStaticAsserts();
1028
void mark(JSTracer *trc);
1031
static const size_t VALUES_PER_STACK_FRAME = sizeof(StackFrame) / sizeof(Value);
1033
static inline StackFrame::Flags
1034
ToFrameFlags(InitialFrameFlags initial)
1036
return StackFrame::Flags(initial);
1039
static inline InitialFrameFlags
1040
InitialFrameFlagsFromConstructing(bool b)
1042
return b ? INITIAL_CONSTRUCT : INITIAL_NONE;
1046
InitialFrameFlagsAreConstructing(InitialFrameFlags initial)
1048
return !!(initial & INITIAL_CONSTRUCT);
1052
InitialFrameFlagsAreLowered(InitialFrameFlags initial)
1054
return !!(initial & INITIAL_LOWERED);
1057
inline StackFrame * Valueify(JSStackFrame *fp) { return (StackFrame *)fp; }
1058
static inline JSStackFrame * Jsvalify(StackFrame *fp) { return (JSStackFrame *)fp; }
1060
/*****************************************************************************/
1068
InlinedSite *inlined_;
1071
StackFrame *fp() const { return fp_; }
1072
InlinedSite *inlined() const { return inlined_; }
1074
/* For jit use (need constant): */
1075
static const size_t offsetOfFp = 3 * sizeof(void *);
1076
static const size_t offsetOfInlined = 2 * sizeof(void *);
1077
static void staticAssert() {
1078
JS_STATIC_ASSERT(offsetOfFp == offsetof(FrameRegs, fp_));
1079
JS_STATIC_ASSERT(offsetOfInlined == offsetof(FrameRegs, inlined_));
1081
void clearInlined() { inlined_ = NULL; }
1083
unsigned stackDepth() const {
1084
JS_ASSERT(sp >= fp_->base());
1085
return sp - fp_->base();
1088
Value *spForStackDepth(unsigned depth) const {
1089
JS_ASSERT(fp_->script()->nfixed + depth <= fp_->script()->nslots);
1090
return fp_->base() + depth;
1093
/* For generator: */
1094
void rebaseFromTo(const FrameRegs &from, StackFrame &to) {
1096
sp = to.slots() + (from.sp - from.fp_->slots());
1098
inlined_ = from.inlined_;
1102
/* For ContextStack: */
1103
void popFrame(Value *newsp) {
1104
pc = fp_->prevpc(&inlined_);
1110
/* For FixupArity: */
1111
void popPartialFrame(Value *newsp) {
1117
/* For InternalInterpret: */
1118
void restorePartialFrame(Value *newfp) {
1119
fp_ = (StackFrame *) newfp;
1122
/* For EnterMethodJIT: */
1123
void refreshFramePointer(StackFrame *fp) {
1127
/* For stubs::CompileFunction, ContextStack: */
1128
void prepareToRun(StackFrame &fp, JSScript *script) {
1130
sp = fp.slots() + script->nfixed;
1135
void setToEndOfScript() {
1136
JSScript *script = fp()->script();
1138
pc = script->code + script->length - JSOP_STOP_LENGTH;
1139
JS_ASSERT(*pc == JSOP_STOP);
1142
/* For expandInlineFrames: */
1143
void expandInline(StackFrame *innerfp, jsbytecode *innerpc) {
1150
/* For LimitCheck: */
1151
void updateForNcode(mjit::JITScript *jit, void *ncode) {
1152
pc = mjit::NativeToPC(jit, ncode, &inlined_);
1157
/*****************************************************************************/
1161
/* Previous segment within same context stack. */
1162
StackSegment *const prevInContext_;
1164
/* Previous segment sequentially in memory. */
1165
StackSegment *const prevInMemory_;
1167
/* Execution registers for most recent script in this segment (or null). */
1170
/* Call args for most recent native call in this segment (or null). */
1171
CallArgsList *calls_;
1174
StackSegment(StackSegment *prevInContext,
1175
StackSegment *prevInMemory,
1177
CallArgsList *calls)
1178
: prevInContext_(prevInContext),
1179
prevInMemory_(prevInMemory),
1184
/* A segment is followed in memory by the arguments of the first call. */
1186
Value *slotsBegin() const {
1187
return (Value *)(this + 1);
1192
FrameRegs ®s() const {
1197
FrameRegs *maybeRegs() const {
1201
StackFrame *fp() const {
1205
StackFrame *maybefp() const {
1206
return regs_ ? regs_->fp() : NULL;
1209
jsbytecode *maybepc() const {
1210
return regs_ ? regs_->pc : NULL;
1213
CallArgsList &calls() const {
1218
CallArgsList *maybeCalls() const {
1222
Value *callArgv() const {
1223
return calls_->array();
1226
Value *maybeCallArgv() const {
1227
return calls_ ? calls_->array() : NULL;
1230
StackSegment *prevInContext() const {
1231
return prevInContext_;
1234
StackSegment *prevInMemory() const {
1235
return prevInMemory_;
1238
void repointRegs(FrameRegs *regs) {
1239
JS_ASSERT_IF(regs, regs->fp());
1243
bool isEmpty() const {
1244
return !calls_ && !regs_;
1247
bool contains(const StackFrame *fp) const;
1248
bool contains(const FrameRegs *regs) const;
1249
bool contains(const CallArgsList *call) const;
1251
StackFrame *computeNextFrame(const StackFrame *fp, size_t maxDepth) const;
1255
FrameRegs *pushRegs(FrameRegs ®s);
1256
void popRegs(FrameRegs *regs);
1257
void pushCall(CallArgsList &callList);
1258
void pointAtCall(CallArgsList &callList);
1261
/* For jit access: */
1263
static const size_t offsetOfRegs() { return offsetof(StackSegment, regs_); }
1266
static const size_t VALUES_PER_STACK_SEGMENT = sizeof(StackSegment) / sizeof(Value);
1267
JS_STATIC_ASSERT(sizeof(StackSegment) % sizeof(Value) == 0);
1269
/*****************************************************************************/
1275
mutable Value *conservativeEnd_;
1277
mutable Value *commitEnd_;
1282
void assertInvariants() const {
1283
JS_ASSERT(base_ <= conservativeEnd_);
1285
JS_ASSERT(conservativeEnd_ <= commitEnd_);
1286
JS_ASSERT(commitEnd_ <= trustedEnd_);
1288
JS_ASSERT(conservativeEnd_ <= defaultEnd_);
1289
JS_ASSERT(defaultEnd_ <= trustedEnd_);
1292
/* The total number of values/bytes reserved for the stack. */
1293
static const size_t CAPACITY_VALS = 512 * 1024;
1294
static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(Value);
1296
/* How much of the stack is initially committed. */
1297
static const size_t COMMIT_VALS = 16 * 1024;
1298
static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value);
1300
/* How much space is reserved at the top of the stack for trusted JS. */
1301
static const size_t BUFFER_VALS = 16 * 1024;
1302
static const size_t BUFFER_BYTES = BUFFER_VALS * sizeof(Value);
1304
static void staticAsserts() {
1305
JS_STATIC_ASSERT(CAPACITY_VALS % COMMIT_VALS == 0);
1308
friend class AllFramesIter;
1309
friend class ContextStack;
1310
friend class StackFrame;
1312
inline bool ensureSpace(JSContext *cx, MaybeReportError report,
1313
Value *from, ptrdiff_t nvals) const;
1314
JS_FRIEND_API(bool) ensureSpaceSlow(JSContext *cx, MaybeReportError report,
1315
Value *from, ptrdiff_t nvals) const;
1317
StackSegment &findContainingSegment(const StackFrame *target) const;
1319
bool containsFast(StackFrame *fp) {
1320
return (Value *)fp >= base_ && (Value *)fp <= trustedEnd_;
1323
void markAndClobberFrame(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc);
1331
* Maximum supported value of arguments.length. This bounds the maximum
1332
* number of arguments that can be supplied to Function.prototype.apply.
1333
* This value also bounds the number of elements parsed in an array
1336
* Since arguments are copied onto the stack, the stack size is the
1337
* limiting factor for this constant. Use the max stack size (available to
1338
* untrusted code) with an extra buffer so that, after such an apply, the
1339
* callee can do a little work without OOMing.
1341
static const unsigned ARGS_LENGTH_MAX = CAPACITY_VALS - (2 * BUFFER_VALS);
1343
/* See stack layout comment in Stack.h. */
1344
inline Value *firstUnused() const { return seg_ ? seg_->end() : base_; }
1346
StackSegment &containingSegment(const StackFrame *target) const;
1349
* Extra space to reserve on the stack for method JIT frames, beyond the
1350
* frame's nslots. This may be used for inlined stack frames, slots storing
1351
* loop invariant code, or to reserve space for pushed callee frames. Note
1352
* that this space should be reserved when pushing interpreter frames as
1353
* well, so that we don't need to check the stack when entering the method
1354
* JIT at loop heads or safe points.
1356
static const size_t STACK_JIT_EXTRA = (/*~VALUES_PER_STACK_FRAME*/ 8 + 18) * 10;
1359
* Return a limit against which jit code can check for. This limit is not
1360
* necessarily the end of the stack since we lazily commit stack memory on
1361
* some platforms. Thus, when the stack limit is exceeded, the caller should
1362
* use tryBumpLimit to attempt to increase the stack limit by committing
1363
* more memory. If the stack is truly exhausted, tryBumpLimit will report an
1364
* error and return NULL.
1366
* An invariant of the methodjit is that there is always space to push a
1367
* frame on top of the current frame's expression stack (which can be at
1368
* most script->nslots deep). getStackLimit ensures that the returned limit
1369
* does indeed have this required space and reports an error and returns
1370
* NULL if this reserve space cannot be allocated.
1372
inline Value *getStackLimit(JSContext *cx, MaybeReportError report);
1373
bool tryBumpLimit(JSContext *cx, Value *from, unsigned nvals, Value **limit);
1375
/* Called during GC: mark segments, frames, and slots under firstUnused. */
1376
void markAndClobber(JSTracer *trc);
1378
/* Called during GC: sets active flag on compartments with active frames. */
1379
void markActiveCompartments();
1381
/* We only report the committed size; uncommitted size is uninteresting. */
1382
JS_FRIEND_API(size_t) sizeOfCommitted();
1385
bool containsSlow(StackFrame *fp);
1389
/*****************************************************************************/
1394
StackSpace *const space_;
1398
* Return whether this ContextStack is at the top of the contiguous stack.
1399
* This is a precondition for extending the current segment by pushing
1400
* stack frames or overrides etc.
1402
* NB: Just because a stack is onTop() doesn't mean there is necessarily
1403
* a frame pushed on the stack. For this, use hasfp().
1408
void assertSpaceInSync() const;
1410
void assertSpaceInSync() const {}
1413
/* Implementation details of push* public interface. */
1414
StackSegment *pushSegment(JSContext *cx);
1415
enum MaybeExtend { CAN_EXTEND = true, CANT_EXTEND = false };
1416
Value *ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars,
1417
MaybeExtend extend, bool *pushedSeg);
1420
getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
1421
JSFunction *fun, JSScript *script, StackFrame::Flags *pflags) const;
1423
/* Make pop* functions private since only called by guard classes. */
1425
friend class InvokeArgsGuard;
1426
void popInvokeArgs(const InvokeArgsGuard &iag);
1427
friend class FrameGuard;
1428
void popFrame(const FrameGuard &fg);
1429
friend class GeneratorFrameGuard;
1430
void popGeneratorFrame(const GeneratorFrameGuard &gfg);
1432
friend class StackIter;
1435
ContextStack(JSContext *cx);
1438
/*** Stack accessors ***/
1441
* A context's stack is "empty" if there are no scripts or natives
1442
* executing. Note that JS_SaveFrameChain does not factor into this definition.
1444
bool empty() const { return !seg_; }
1447
* Return whether there has been at least one frame pushed since the most
1448
* recent call to JS_SaveFrameChain. Note that natives do not have frames
1449
* hence this query has little semantic meaning past "you can call fp()".
1451
inline bool hasfp() const { return seg_ && seg_->maybeRegs(); }
1454
* Return the spindex value for 'vp' which can be used to call
1455
* DecompileValueGenerator. (The spindex is either the negative offset of
1456
* 'vp' from 'sp', if 'vp' points to a value in the innermost scripted
1457
* stack frame, otherwise it is JSDVG_SEARCH_STACK.)
1459
ptrdiff_t spIndexOf(const Value *vp);
1462
* Return the most recent script activation's registers with the same
1463
* caveat as hasfp regarding JS_SaveFrameChain.
1465
inline FrameRegs *maybeRegs() const { return seg_ ? seg_->maybeRegs() : NULL; }
1466
inline StackFrame *maybefp() const { return seg_ ? seg_->maybefp() : NULL; }
1468
/* Faster alternatives to maybe* functions. */
1469
inline FrameRegs ®s() const { JS_ASSERT(hasfp()); return seg_->regs(); }
1470
inline StackFrame *fp() const { JS_ASSERT(hasfp()); return seg_->fp(); }
1472
/* The StackSpace currently hosting this ContextStack. */
1473
StackSpace &space() const { return *space_; }
1475
/* Return whether the given frame is in this context's stack. */
1476
bool containsSlow(const StackFrame *target) const;
1478
/*** Stack manipulation ***/
1481
* pushInvokeArgs allocates |argc + 2| rooted values that will be passed as
1482
* the arguments to Invoke. A single allocation can be used for multiple
1483
* Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
1484
* an immediately-enclosing (stack-wise) call to pushInvokeArgs.
1486
bool pushInvokeArgs(JSContext *cx, unsigned argc, InvokeArgsGuard *ag);
1488
/* Called by Invoke for a scripted function call. */
1489
bool pushInvokeFrame(JSContext *cx, const CallArgs &args,
1490
InitialFrameFlags initial, InvokeFrameGuard *ifg);
1492
/* Called by Execute for execution of eval or global code. */
1493
bool pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thisv,
1494
JSObject &scopeChain, ExecuteType type,
1495
StackFrame *evalInFrame, ExecuteFrameGuard *efg);
1498
* Called by SendToGenerator to resume a yielded generator. In addition to
1499
* pushing a frame onto the VM stack, this function copies over the
1500
* floating frame stored in 'gen'. When 'gfg' is destroyed, the destructor
1501
* will copy the frame back to the floating frame.
1503
bool pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg);
1506
* An "inline frame" may only be pushed from within the top, active
1507
* segment. This is the case for calls made inside mjit code and Interpret.
1508
* The 'stackLimit' overload updates 'stackLimit' if it changes.
1510
bool pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
1511
JSFunction &callee, JSScript *script,
1512
InitialFrameFlags initial);
1513
bool pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
1514
JSFunction &callee, JSScript *script,
1515
InitialFrameFlags initial, Value **stackLimit);
1516
void popInlineFrame(FrameRegs ®s);
1518
/* Pop a partially-pushed frame after hitting the limit before throwing. */
1519
void popFrameAfterOverflow();
1522
* Get the topmost script and optional pc on the stack. By default, this
1523
* function only returns a JSScript in the current compartment, returning
1524
* NULL if the current script is in a different compartment. This behavior
1525
* can be overridden by passing ALLOW_CROSS_COMPARTMENT.
1527
enum MaybeAllowCrossCompartment {
1528
DONT_ALLOW_CROSS_COMPARTMENT = false,
1529
ALLOW_CROSS_COMPARTMENT = true
1531
inline JSScript *currentScript(jsbytecode **pc = NULL,
1532
MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
1534
/* Get the scope chain for the topmost scripted call on the stack. */
1535
inline HandleObject currentScriptedScopeChain() const;
1538
* Called by the methodjit for an arity mismatch. Arity mismatch can be
1539
* hot, so getFixupFrame avoids doing call setup performed by jit code when
1540
* FixupArity returns.
1542
StackFrame *getFixupFrame(JSContext *cx, MaybeReportError report,
1543
const CallArgs &args, JSFunction *fun, JSScript *script,
1544
void *ncode, InitialFrameFlags initial, Value **stackLimit);
1546
bool saveFrameChain();
1547
void restoreFrameChain();
1550
* As an optimization, the interpreter/mjit can operate on a local
1551
* FrameRegs instance repoint the ContextStack to this local instance.
1553
inline void repointRegs(FrameRegs *regs) { JS_ASSERT(hasfp()); seg_->repointRegs(regs); }
1556
/*****************************************************************************/
1558
class InvokeArgsGuard : public CallArgsList
1560
friend class ContextStack;
1561
ContextStack *stack_;
1563
void setPushed(ContextStack &stack) { JS_ASSERT(!pushed()); stack_ = &stack; }
1565
InvokeArgsGuard() : CallArgsList(), stack_(NULL), pushedSeg_(false) {}
1566
~InvokeArgsGuard() { if (pushed()) stack_->popInvokeArgs(*this); }
1567
bool pushed() const { return !!stack_; }
1568
void pop() { stack_->popInvokeArgs(*this); stack_ = NULL; }
1574
friend class ContextStack;
1575
ContextStack *stack_;
1578
FrameRegs *prevRegs_;
1579
void setPushed(ContextStack &stack) { stack_ = &stack; }
1581
FrameGuard() : stack_(NULL), pushedSeg_(false) {}
1582
~FrameGuard() { if (pushed()) stack_->popFrame(*this); }
1583
bool pushed() const { return !!stack_; }
1584
void pop() { stack_->popFrame(*this); stack_ = NULL; }
1586
StackFrame *fp() const { return regs_.fp(); }
1589
class InvokeFrameGuard : public FrameGuard
1592
class ExecuteFrameGuard : public FrameGuard
1595
class GeneratorFrameGuard : public FrameGuard
1597
friend class ContextStack;
1601
~GeneratorFrameGuard() { if (pushed()) stack_->popGeneratorFrame(*this); }
1604
/*****************************************************************************/
1607
* Iterate through the callstack (following fp->prev) of the given context.
1608
* Each element of said callstack can either be the execution of a script
1609
* (scripted function call, global code, eval code, debugger code) or the
1610
* invocation of a (C++) native. Example usage:
1612
* for (Stackiter i(cx); !i.done(); ++i) {
1613
* if (i.isScript()) {
1614
* ... i.fp() ... i.sp() ... i.pc()
1616
* JS_ASSERT(i.isNativeCall());
1621
* The SavedOption parameter additionally lets the iterator continue through
1622
* breaks in the callstack (from JS_SaveFrameChain). The default is to stop.
1626
friend class ContextStack;
1627
JSContext *maybecx_;
1629
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
1631
SavedOption savedOption_;
1633
enum State { DONE, SCRIPTED, NATIVE };
1637
CallArgsList *calls_;
1647
void settleOnNewSegment();
1648
void settleOnNewState();
1649
void startOnSegment(StackSegment *seg);
1652
StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
1653
StackIter(JSRuntime *rt, StackSegment &seg);
1655
bool done() const { return state_ == DONE; }
1656
StackIter &operator++();
1658
bool operator==(const StackIter &rhs) const;
1659
bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
1661
bool isScript() const { JS_ASSERT(!done()); return state_ == SCRIPTED; }
1662
bool isNativeCall() const {
1664
return state_ == NATIVE;
1667
bool isFunctionFrame() const;
1668
bool isEvalFrame() const;
1669
bool isNonEvalFunctionFrame() const;
1670
bool isConstructing() const;
1672
StackFrame *fp() const { JS_ASSERT(isScript()); return fp_; }
1673
jsbytecode *pc() const { JS_ASSERT(isScript()); return pc_; }
1674
JSScript *script() const { JS_ASSERT(isScript()); return script_; }
1675
JSFunction *callee() const;
1676
Value calleev() const;
1677
Value thisv() const;
1679
CallArgs nativeArgs() const { JS_ASSERT(isNativeCall()); return args_; }
1682
/* A filtering of the StackIter to only stop at scripts. */
1683
class ScriptFrameIter : public StackIter
1686
while (!done() && !isScript())
1687
StackIter::operator++();
1691
ScriptFrameIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
1692
: StackIter(cx, opt) { settle(); }
1694
ScriptFrameIter &operator++() { StackIter::operator++(); settle(); return *this; }
1697
/* A filtering of the StackIter to only stop at non-self-hosted scripts. */
1698
class NonBuiltinScriptFrameIter : public StackIter
1701
while (!done() && (!isScript() || (isFunctionFrame() && fp()->fun()->isSelfHostedBuiltin())))
1702
StackIter::operator++();
1706
NonBuiltinScriptFrameIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
1707
: StackIter(cx, opt) { settle(); }
1709
NonBuiltinScriptFrameIter &operator++() { StackIter::operator++(); settle(); return *this; }
1712
/*****************************************************************************/
1715
* Blindly iterate over all frames in the current thread's stack. These frames
1716
* can be from different contexts and compartments, so beware.
1721
AllFramesIter(StackSpace &space);
1723
bool done() const { return fp_ == NULL; }
1724
AllFramesIter& operator++();
1726
StackFrame *fp() const { return fp_; }
1734
} /* namespace js */
1735
#endif /* Stack_h__ */