~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/vm/Stack.h

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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:
 
3
 *
 
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/. */
 
7
 
 
8
#ifndef Stack_h__
 
9
#define Stack_h__
 
10
 
 
11
#include "jsapi.h"
 
12
#include "jsfun.h"
 
13
#include "jsautooplen.h"
 
14
 
 
15
struct JSContext;
 
16
struct JSCompartment;
 
17
 
 
18
namespace js {
 
19
 
 
20
class StackFrame;
 
21
class FrameRegs;
 
22
class StackSegment;
 
23
class StackSpace;
 
24
class ContextStack;
 
25
 
 
26
class InvokeArgsGuard;
 
27
class InvokeFrameGuard;
 
28
class FrameGuard;
 
29
class ExecuteFrameGuard;
 
30
class GeneratorFrameGuard;
 
31
 
 
32
class CallIter;
 
33
class ScriptFrameIter;
 
34
class AllFramesIter;
 
35
 
 
36
class ArgumentsObject;
 
37
class ScopeObject;
 
38
class StaticBlockObject;
 
39
 
 
40
struct ScopeCoordinate;
 
41
 
 
42
#ifdef JS_METHODJIT
 
43
namespace mjit {
 
44
    class CallCompiler;
 
45
    class GetPropCompiler;
 
46
    struct CallSite;
 
47
    struct JITScript;
 
48
    jsbytecode *NativeToPC(JITScript *jit, void *ncode, CallSite **pinline);
 
49
    namespace ic { struct GetElementIC; }
 
50
}
 
51
typedef mjit::CallSite InlinedSite;
 
52
#else
 
53
struct InlinedSite {};
 
54
#endif
 
55
typedef size_t FrameRejoinState;
 
56
 
 
57
/*****************************************************************************/
 
58
 
 
59
/*
 
60
 * VM stack layout
 
61
 *
 
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.
 
65
 *
 
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++.
 
72
 *
 
73
 * A sample memory layout of a segment looks like:
 
74
 *
 
75
 *                          regs
 
76
 *       .------------------------------------------------.
 
77
 *       |                                                V
 
78
 *       |                                      fp .--FrameRegs--. sp
 
79
 *       |                                         V             V
 
80
 * |StackSegment| values |StackFrame| values |StackFrame| values |
 
81
 *                         |      ^            |
 
82
 *           ? <-----------'      `------------'
 
83
 *                 prev               prev
 
84
 *
 
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
 
87
 * end of the stack.
 
88
 *
 
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
 
92
 * the previous frame.
 
93
 *
 
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.
 
101
 *
 
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.
 
109
 *
 
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
 
114
 * looks like:
 
115
 *
 
116
 *                          regs
 
117
 *       .------------------------------------------.
 
118
 *       |                                          V
 
119
 *       |                                fp .--FrameRegs--. sp
 
120
 *       |                                   V             V
 
121
 * |StackSegment| native call | values |StackFrame| values | native call |
 
122
 *       |       vp <--argc--> end                        vp <--argc--> end
 
123
 *       |           CallArgs <------------------------------ CallArgs
 
124
 *       |                                 prev                  ^
 
125
 *       `-------------------------------------------------------'
 
126
 *                                    calls
 
127
 *
 
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.
 
134
 *
 
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'.
 
137
 *
 
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.
 
144
 *
 
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.
 
154
 */
 
155
 
 
156
/*****************************************************************************/
 
157
 
 
158
/*
 
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).
 
164
 */
 
165
class CallArgsList : public JS::CallArgs
 
166
{
 
167
    friend class StackSegment;
 
168
    CallArgsList *prev_;
 
169
    bool active_;
 
170
  public:
 
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; }
 
177
};
 
178
 
 
179
JS_ALWAYS_INLINE CallArgsList
 
180
CallArgsListFromArgv(unsigned argc, Value *argv, CallArgsList *prev)
 
181
{
 
182
    CallArgsList args;
 
183
#ifdef DEBUG
 
184
    args.usedRval_ = false;
 
185
#endif
 
186
    args.argv_ = argv;
 
187
    args.argc_ = argc;
 
188
    args.prev_ = prev;
 
189
    args.active_ = false;
 
190
    return args;
 
191
}
 
192
 
 
193
JS_ALWAYS_INLINE CallArgsList
 
194
CallArgsListFromVp(unsigned argc, Value *vp, CallArgsList *prev)
 
195
{
 
196
    return CallArgsListFromArgv(argc, vp + 2, prev);
 
197
}
 
198
 
 
199
/*****************************************************************************/
 
200
 
 
201
enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
 
202
 
 
203
/*****************************************************************************/
 
204
 
 
205
/* Flags specified for a frame as it is constructed. */
 
206
enum InitialFrameFlags {
 
207
    INITIAL_NONE           =          0,
 
208
    INITIAL_CONSTRUCT      =       0x20, /* == StackFrame::CONSTRUCTING, asserted below */
 
209
    INITIAL_LOWERED        =    0x80000  /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
 
210
};
 
211
 
 
212
enum ExecuteType {
 
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 */
 
217
};
 
218
 
 
219
/*****************************************************************************/
 
220
 
 
221
class StackFrame
 
222
{
 
223
  public:
 
224
    enum Flags {
 
225
        /* Primary frame type */
 
226
        GLOBAL             =        0x1,  /* frame pushed for a global script */
 
227
        FUNCTION           =        0x2,  /* frame pushed for a scripted call */
 
228
 
 
229
        /* Frame subtypes */
 
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 */
 
234
 
 
235
        /* Temporary frame states */
 
236
        YIELDING           =       0x40,  /* Interpret dispatched JSOP_YIELD */
 
237
        FINISHED_IN_INTERP =       0x80,  /* set if frame finished in Interpret() */
 
238
 
 
239
        /* Function arguments */
 
240
        OVERFLOW_ARGS      =      0x100,  /* numActualArgs > numFormalArgs */
 
241
        UNDERFLOW_ARGS     =      0x200,  /* numActualArgs < numFormalArgs */
 
242
 
 
243
        /* Function prologue state */
 
244
        HAS_CALL_OBJ       =      0x400,  /* CallObject created for heavyweight fun */
 
245
        HAS_ARGS_OBJ       =      0x800,  /* ArgumentsObject created for needsArgsObj script */
 
246
 
 
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 */
 
254
 
 
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 */
 
258
 
 
259
        /* Debugger state */
 
260
        PREV_UP_TO_DATE    =   0x100000,  /* see DebugScopes::updateLiveScopes */
 
261
 
 
262
        /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
 
263
        HAS_PUSHED_SPS_FRAME = 0x200000  /* SPS was notified of enty */
 
264
    };
 
265
 
 
266
  private:
 
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 */
 
271
    } exec;
 
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 */
 
275
    } u;
 
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. */
 
288
 
 
289
    static void staticAsserts() {
 
290
        JS_STATIC_ASSERT(offsetof(StackFrame, rval_) % sizeof(Value) == 0);
 
291
        JS_STATIC_ASSERT(sizeof(StackFrame) % sizeof(Value) == 0);
 
292
    }
 
293
 
 
294
    inline void initPrev(JSContext *cx);
 
295
    jsbytecode *prevpcSlow(InlinedSite **pinlined);
 
296
    void writeBarrierPost();
 
297
 
 
298
    /*
 
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).
 
304
     */
 
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); }
 
309
 
 
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;
 
317
#ifdef JS_METHODJIT
 
318
    friend class mjit::CallCompiler;
 
319
    friend class mjit::GetPropCompiler;
 
320
    friend struct mjit::ic::GetElementIC;
 
321
#endif
 
322
 
 
323
    /*
 
324
     * Frame initialization, called by ContextStack operations after acquiring
 
325
     * the raw memory for the frame:
 
326
     */
 
327
 
 
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);
 
331
 
 
332
    /* Used for getFixupFrame (for FixupArity). */
 
333
    void initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncode, unsigned nactual);
 
334
 
 
335
    /* Used for eval. */
 
336
    void initExecuteFrame(JSScript *script, StackFrame *prev, FrameRegs *regs,
 
337
                          const Value &thisv, JSObject &scopeChain, ExecuteType type);
 
338
 
 
339
  public:
 
340
    /*
 
341
     * Frame prologue/epilogue
 
342
     *
 
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).
 
346
     *
 
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.
 
352
     *
 
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.
 
357
     *
 
358
     * The 'newType' option indicates whether the constructed 'this' value (if
 
359
     * there is one) should be given a new singleton type.
 
360
     */
 
361
 
 
362
    bool prologue(JSContext *cx, bool newType);
 
363
    void epilogue(JSContext *cx);
 
364
 
 
365
    /* Subsets of 'prologue' called from jit code. */
 
366
    inline bool jitHeavyweightFunctionPrologue(JSContext *cx);
 
367
    bool jitStrictEvalPrologue(JSContext *cx);
 
368
 
 
369
    /* Initialize local variables of newly-pushed frame. */
 
370
    void initVarsToUndefined();
 
371
 
 
372
    /*
 
373
     * Stack frame type
 
374
     *
 
375
     * A stack frame may have one of three types, which determines which
 
376
     * members of the frame may be accessed and other invariants:
 
377
     *
 
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
 
380
     */
 
381
 
 
382
    bool isFunctionFrame() const {
 
383
        return !!(flags_ & FUNCTION);
 
384
    }
 
385
 
 
386
    bool isGlobalFrame() const {
 
387
        return !!(flags_ & GLOBAL);
 
388
    }
 
389
 
 
390
    /*
 
391
     * Eval frames
 
392
     *
 
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.
 
397
     *
 
398
     * A further sub-classification of eval frames is whether the frame was
 
399
     * pushed for an ES5 strict-mode eval().
 
400
     */
 
401
 
 
402
    bool isEvalFrame() const {
 
403
        return flags_ & EVAL;
 
404
    }
 
405
 
 
406
    bool isEvalInFunction() const {
 
407
        return (flags_ & (EVAL | FUNCTION)) == (EVAL | FUNCTION);
 
408
    }
 
409
 
 
410
    bool isNonEvalFunctionFrame() const {
 
411
        return (flags_ & (FUNCTION | EVAL)) == FUNCTION;
 
412
    }
 
413
 
 
414
    inline bool isStrictEvalFrame() const {
 
415
        return isEvalFrame() && script()->strictModeCode;
 
416
    }
 
417
 
 
418
    bool isNonStrictEvalFrame() const {
 
419
        return isEvalFrame() && !script()->strictModeCode;
 
420
    }
 
421
 
 
422
    bool isDirectEvalFrame() const {
 
423
        return isEvalFrame() && script()->staticLevel > 0;
 
424
    }
 
425
 
 
426
    bool isNonStrictDirectEvalFrame() const {
 
427
        return isNonStrictEvalFrame() && isDirectEvalFrame();
 
428
    }
 
429
 
 
430
    /*
 
431
     * Previous frame
 
432
     *
 
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.
 
441
     */
 
442
 
 
443
    StackFrame *prev() const {
 
444
        return prev_;
 
445
    }
 
446
 
 
447
    inline void resetGeneratorPrev(JSContext *cx);
 
448
 
 
449
    /*
 
450
     * (Unaliased) locals and arguments
 
451
     *
 
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.
 
463
     *
 
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.
 
472
     */
 
473
 
 
474
    inline Value &unaliasedVar(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
 
475
    inline Value &unaliasedLocal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);
 
476
 
 
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);
 
481
 
 
482
    typedef Vector<Value, 16, SystemAllocPolicy> CopyVector;
 
483
    bool copyRawFrameSlots(CopyVector *v);
 
484
 
 
485
    inline unsigned numFormalArgs() const;
 
486
    inline unsigned numActualArgs() const;
 
487
 
 
488
    /*
 
489
     * Arguments object
 
490
     *
 
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.
 
497
     */
 
498
 
 
499
    ArgumentsObject &argsObj() const;
 
500
    void initArgsObj(ArgumentsObject &argsobj);
 
501
 
 
502
    inline JSObject *createRestParameter(JSContext *cx);
 
503
 
 
504
    /*
 
505
     * Scope chain
 
506
     *
 
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
 
509
     * actually created.
 
510
     *
 
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.
 
521
     */
 
522
 
 
523
    inline HandleObject scopeChain() const;
 
524
 
 
525
    inline ScopeObject &aliasedVarScope(ScopeCoordinate sc) const;
 
526
    inline GlobalObject &global() const;
 
527
    inline CallObject &callObj() const;
 
528
    inline JSObject &varObj();
 
529
 
 
530
    inline void pushOnScopeChain(ScopeObject &scope);
 
531
    inline void popOffScopeChain();
 
532
 
 
533
    /*
 
534
     * Block chain
 
535
     *
 
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.
 
542
     */
 
543
 
 
544
    bool hasBlockChain() const {
 
545
        return (flags_ & HAS_BLOCKCHAIN) && blockChain_;
 
546
    }
 
547
 
 
548
    StaticBlockObject *maybeBlockChain() {
 
549
        return (flags_ & HAS_BLOCKCHAIN) ? blockChain_ : NULL;
 
550
    }
 
551
 
 
552
    StaticBlockObject &blockChain() const {
 
553
        JS_ASSERT(hasBlockChain());
 
554
        return *blockChain_;
 
555
    }
 
556
 
 
557
    bool pushBlock(JSContext *cx, StaticBlockObject &block);
 
558
    void popBlock(JSContext *cx);
 
559
 
 
560
    /*
 
561
     * With 
 
562
     *
 
563
     * Entering/leaving a with (or E4X filter) block pushes/pops an object 
 
564
     * on the scope chain. Pushing uses pushOnScopeChain, popping should use
 
565
     * popWith.
 
566
     */
 
567
 
 
568
    void popWith(JSContext *cx);
 
569
 
 
570
    /*
 
571
     * Script
 
572
     *
 
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:
 
578
     *
 
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.
 
583
     */
 
584
 
 
585
    JSScript *script() const {
 
586
        return isFunctionFrame()
 
587
               ? isEvalFrame() ? u.evalScript : fun()->script()
 
588
               : exec.script;
 
589
    }
 
590
 
 
591
    /*
 
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
 
594
     * such as:
 
595
     *
 
596
     *   for ( ...; fp; fp = fp->prev())
 
597
     *     ... fp->pcQuadratic(cx->stack);
 
598
     *
 
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.
 
604
     */
 
605
 
 
606
    jsbytecode *pcQuadratic(const ContextStack &stack, size_t maxDepth = SIZE_MAX);
 
607
 
 
608
    /* Return the previous frame's pc. Unlike pcQuadratic, this is O(1). */
 
609
    jsbytecode *prevpc(InlinedSite **pinlined = NULL) {
 
610
        if (flags_ & HAS_PREVPC) {
 
611
            if (pinlined)
 
612
                *pinlined = prevInline_;
 
613
            return prevpc_;
 
614
        }
 
615
        return prevpcSlow(pinlined);
 
616
    }
 
617
 
 
618
    InlinedSite *prevInline() {
 
619
        JS_ASSERT(flags_ & HAS_PREVPC);
 
620
        return prevInline_;
 
621
    }
 
622
 
 
623
    /*
 
624
     * Function
 
625
     *
 
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().
 
630
     */
 
631
 
 
632
    JSFunction* fun() const {
 
633
        JS_ASSERT(isFunctionFrame());
 
634
        return exec.fun;
 
635
    }
 
636
 
 
637
    JSFunction* maybeFun() const {
 
638
        return isFunctionFrame() ? fun() : NULL;
 
639
    }
 
640
 
 
641
    JSFunction* maybeScriptFunction() const {
 
642
        if (!isFunctionFrame())
 
643
            return NULL;
 
644
        const StackFrame *fp = this;
 
645
        while (fp->isEvalFrame())
 
646
            fp = fp->prev();
 
647
        return fp->script()->function();
 
648
    }
 
649
 
 
650
    /*
 
651
     * This value
 
652
     *
 
653
     * Every frame has a this value although, until 'this' is computed, the
 
654
     * value may not be the semantically-correct 'this' value.
 
655
     *
 
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.
 
661
     */
 
662
 
 
663
    Value &functionThis() const {
 
664
        JS_ASSERT(isFunctionFrame());
 
665
        if (isEvalFrame())
 
666
            return ((Value *)this)[-1];
 
667
        return formals()[-1];
 
668
    }
 
669
 
 
670
    JSObject &constructorThis() const {
 
671
        JS_ASSERT(hasArgs());
 
672
        return formals()[-1].toObject();
 
673
    }
 
674
 
 
675
    Value &thisValue() const {
 
676
        if (flags_ & (EVAL | GLOBAL))
 
677
            return ((Value *)this)[-1];
 
678
        return formals()[-1];
 
679
    }
 
680
 
 
681
    /*
 
682
     * Callee
 
683
     *
 
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).
 
688
     */
 
689
 
 
690
    JSFunction &callee() const {
 
691
        JS_ASSERT(isFunctionFrame());
 
692
        return *calleev().toObject().toFunction();
 
693
    }
 
694
 
 
695
    const Value &calleev() const {
 
696
        JS_ASSERT(isFunctionFrame());
 
697
        return mutableCalleev();
 
698
    }
 
699
 
 
700
    const Value &maybeCalleev() const {
 
701
        Value &calleev = flags_ & (EVAL | GLOBAL)
 
702
                         ? ((Value *)this)[-2]
 
703
                         : formals()[-2];
 
704
        JS_ASSERT(calleev.isObjectOrNull());
 
705
        return calleev;
 
706
    }
 
707
 
 
708
    Value &mutableCalleev() const {
 
709
        JS_ASSERT(isFunctionFrame());
 
710
        if (isEvalFrame())
 
711
            return ((Value *)this)[-2];
 
712
        return formals()[-2];
 
713
    }
 
714
 
 
715
    CallReceiver callReceiver() const {
 
716
        return CallReceiverFromArgv(formals());
 
717
    }
 
718
 
 
719
    /*
 
720
     * Frame compartment
 
721
     *
 
722
     * A stack frame's compartment is the frame's containing context's
 
723
     * compartment when the frame was pushed.
 
724
     */
 
725
 
 
726
    inline JSCompartment *compartment() const;
 
727
 
 
728
    /* Annotation (will be removed after bug 546848) */
 
729
 
 
730
    void* annotation() const {
 
731
        return (flags_ & HAS_ANNOTATION) ? annotation_ : NULL;
 
732
    }
 
733
 
 
734
    void setAnnotation(void *annot) {
 
735
        flags_ |= HAS_ANNOTATION;
 
736
        annotation_ = annot;
 
737
    }
 
738
 
 
739
    /* JIT rejoin state */
 
740
 
 
741
    FrameRejoinState rejoin() const {
 
742
        return rejoin_;
 
743
    }
 
744
 
 
745
    void setRejoin(FrameRejoinState state) {
 
746
        rejoin_ = state;
 
747
    }
 
748
 
 
749
    /* Down frame expansion state */
 
750
 
 
751
    void setDownFramesExpanded() {
 
752
        flags_ |= DOWN_FRAMES_EXPANDED;
 
753
    }
 
754
 
 
755
    bool downFramesExpanded() {
 
756
        return !!(flags_ & DOWN_FRAMES_EXPANDED);
 
757
    }
 
758
 
 
759
    /* Debugger hook data */
 
760
 
 
761
    bool hasHookData() const {
 
762
        return !!(flags_ & HAS_HOOK_DATA);
 
763
    }
 
764
 
 
765
    void* hookData() const {
 
766
        JS_ASSERT(hasHookData());
 
767
        return hookData_;
 
768
    }
 
769
 
 
770
    void* maybeHookData() const {
 
771
        return hasHookData() ? hookData_ : NULL;
 
772
    }
 
773
 
 
774
    void setHookData(void *v) {
 
775
        hookData_ = v;
 
776
        flags_ |= HAS_HOOK_DATA;
 
777
    }
 
778
 
 
779
    bool hasPushedSPSFrame() {
 
780
        return !!(flags_ & HAS_PUSHED_SPS_FRAME);
 
781
    }
 
782
 
 
783
    void setPushedSPSFrame() {
 
784
        flags_ |= HAS_PUSHED_SPS_FRAME;
 
785
    }
 
786
 
 
787
    /* Return value */
 
788
 
 
789
    bool hasReturnValue() const {
 
790
        return !!(flags_ & HAS_RVAL);
 
791
    }
 
792
 
 
793
    Value &returnValue() {
 
794
        if (!(flags_ & HAS_RVAL))
 
795
            rval_.setUndefined();
 
796
        return rval_;
 
797
    }
 
798
 
 
799
    void markReturnValue() {
 
800
        flags_ |= HAS_RVAL;
 
801
    }
 
802
 
 
803
    void setReturnValue(const Value &v) {
 
804
        rval_ = v;
 
805
        markReturnValue();
 
806
    }
 
807
 
 
808
    void clearReturnValue() {
 
809
        rval_.setUndefined();
 
810
        markReturnValue();
 
811
    }
 
812
 
 
813
    /* Native-code return address */
 
814
 
 
815
    void *nativeReturnAddress() const {
 
816
        return ncode_;
 
817
    }
 
818
 
 
819
    void setNativeReturnAddress(void *addr) {
 
820
        ncode_ = addr;
 
821
    }
 
822
 
 
823
    void **addressOfNativeReturnAddress() {
 
824
        return &ncode_;
 
825
    }
 
826
 
 
827
    /*
 
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).
 
836
     */
 
837
 
 
838
    bool isGeneratorFrame() const {
 
839
        bool ret = flags_ & GENERATOR;
 
840
        JS_ASSERT_IF(ret, isNonEvalFunctionFrame());
 
841
        return ret;
 
842
    }
 
843
 
 
844
    void initGeneratorFrame() const {
 
845
        JS_ASSERT(!isGeneratorFrame());
 
846
        JS_ASSERT(isNonEvalFunctionFrame());
 
847
        flags_ |= GENERATOR;
 
848
    }
 
849
 
 
850
    Value *generatorArgsSnapshotBegin() const {
 
851
        JS_ASSERT(isGeneratorFrame());
 
852
        return actuals() - 2;
 
853
    }
 
854
 
 
855
    Value *generatorArgsSnapshotEnd() const {
 
856
        JS_ASSERT(isGeneratorFrame());
 
857
        return (Value *)this;
 
858
    }
 
859
 
 
860
    Value *generatorSlotsSnapshotBegin() const {
 
861
        JS_ASSERT(isGeneratorFrame());
 
862
        return (Value *)(this + 1);
 
863
    }
 
864
 
 
865
    enum TriggerPostBarriers {
 
866
        DoPostBarrier = true,
 
867
        NoPostBarrier = false
 
868
    };
 
869
    template <TriggerPostBarriers doPostBarrier>
 
870
    void copyFrameAndValues(JSContext *cx, Value *vp, StackFrame *otherfp,
 
871
                            const Value *othervp, Value *othersp);
 
872
 
 
873
    JSGenerator *maybeSuspendedGenerator(JSRuntime *rt);
 
874
 
 
875
    /*
 
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:
 
880
     */
 
881
 
 
882
    bool isFramePushedByExecute() const {
 
883
        return !!(flags_ & (GLOBAL | EVAL));
 
884
    }
 
885
 
 
886
    /*
 
887
     * Other flags
 
888
     */
 
889
 
 
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);
 
897
    }
 
898
 
 
899
    bool isConstructing() const {
 
900
        return !!(flags_ & CONSTRUCTING);
 
901
    }
 
902
 
 
903
    /*
 
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).
 
909
     */
 
910
 
 
911
    bool hasCallObj() const {
 
912
        JS_ASSERT(isStrictEvalFrame() || fun()->isHeavyweight());
 
913
        return flags_ & HAS_CALL_OBJ;
 
914
    }
 
915
 
 
916
    bool hasArgsObj() const {
 
917
        JS_ASSERT(script()->needsArgsObj());
 
918
        return flags_ & HAS_ARGS_OBJ;
 
919
    }
 
920
 
 
921
    /*
 
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.
 
926
     */
 
927
    bool loweredCallOrApply() const {
 
928
        return !!(flags_ & LOWERED_CALL_APPLY);
 
929
    }
 
930
 
 
931
    bool isDebuggerFrame() const {
 
932
        return !!(flags_ & DEBUGGER);
 
933
    }
 
934
 
 
935
    bool prevUpToDate() const {
 
936
        return !!(flags_ & PREV_UP_TO_DATE);
 
937
    }
 
938
 
 
939
    void setPrevUpToDate() {
 
940
        flags_ |= PREV_UP_TO_DATE;
 
941
    }
 
942
 
 
943
    bool isYielding() {
 
944
        return !!(flags_ & YIELDING);
 
945
    }
 
946
 
 
947
    void setYielding() {
 
948
        flags_ |= YIELDING;
 
949
    }
 
950
 
 
951
    void clearYielding() {
 
952
        flags_ &= ~YIELDING;
 
953
    }
 
954
 
 
955
    void setFinishedInInterpreter() {
 
956
        flags_ |= FINISHED_IN_INTERP;
 
957
    }
 
958
 
 
959
    bool finishedInInterpreter() const {
 
960
        return !!(flags_ & FINISHED_IN_INTERP);
 
961
    }
 
962
 
 
963
  public:
 
964
    /* Public, but only for JIT use: */
 
965
 
 
966
    inline void resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc);
 
967
    inline void initInlineFrame(JSFunction *fun, StackFrame *prevfp, jsbytecode *prevpc);
 
968
 
 
969
    static size_t offsetOfFlags() {
 
970
        return offsetof(StackFrame, flags_);
 
971
    }
 
972
 
 
973
    static size_t offsetOfExec() {
 
974
        return offsetof(StackFrame, exec);
 
975
    }
 
976
 
 
977
    static size_t offsetOfNumActual() {
 
978
        return offsetof(StackFrame, u.nactual);
 
979
    }
 
980
 
 
981
    static size_t offsetOfScopeChain() {
 
982
        return offsetof(StackFrame, scopeChain_);
 
983
    }
 
984
 
 
985
    static size_t offsetOfPrev() {
 
986
        return offsetof(StackFrame, prev_);
 
987
    }
 
988
 
 
989
    static size_t offsetOfReturnValue() {
 
990
        return offsetof(StackFrame, rval_);
 
991
    }
 
992
 
 
993
    static ptrdiff_t offsetOfNcode() {
 
994
        return offsetof(StackFrame, ncode_);
 
995
    }
 
996
 
 
997
    static ptrdiff_t offsetOfArgsObj() {
 
998
        return offsetof(StackFrame, argsObj_);
 
999
    }
 
1000
 
 
1001
    static ptrdiff_t offsetOfCallee(JSFunction *fun) {
 
1002
        JS_ASSERT(fun != NULL);
 
1003
        return -(fun->nargs + 2) * sizeof(Value);
 
1004
    }
 
1005
 
 
1006
    static ptrdiff_t offsetOfThis(JSFunction *fun) {
 
1007
        return fun == NULL
 
1008
               ? -1 * ptrdiff_t(sizeof(Value))
 
1009
               : -(fun->nargs + 1) * ptrdiff_t(sizeof(Value));
 
1010
    }
 
1011
 
 
1012
    static ptrdiff_t offsetOfFormalArg(JSFunction *fun, unsigned i) {
 
1013
        JS_ASSERT(i < fun->nargs);
 
1014
        return (-(int)fun->nargs + i) * sizeof(Value);
 
1015
    }
 
1016
 
 
1017
    static size_t offsetOfFixed(unsigned i) {
 
1018
        return sizeof(StackFrame) + i * sizeof(Value);
 
1019
    }
 
1020
 
 
1021
#ifdef JS_METHODJIT
 
1022
    inline mjit::JITScript *jit();
 
1023
#endif
 
1024
 
 
1025
    void methodjitStaticAsserts();
 
1026
 
 
1027
  public:
 
1028
    void mark(JSTracer *trc);
 
1029
};
 
1030
 
 
1031
static const size_t VALUES_PER_STACK_FRAME = sizeof(StackFrame) / sizeof(Value);
 
1032
 
 
1033
static inline StackFrame::Flags
 
1034
ToFrameFlags(InitialFrameFlags initial)
 
1035
{
 
1036
    return StackFrame::Flags(initial);
 
1037
}
 
1038
 
 
1039
static inline InitialFrameFlags
 
1040
InitialFrameFlagsFromConstructing(bool b)
 
1041
{
 
1042
    return b ? INITIAL_CONSTRUCT : INITIAL_NONE;
 
1043
}
 
1044
 
 
1045
static inline bool
 
1046
InitialFrameFlagsAreConstructing(InitialFrameFlags initial)
 
1047
{
 
1048
    return !!(initial & INITIAL_CONSTRUCT);
 
1049
}
 
1050
 
 
1051
static inline bool
 
1052
InitialFrameFlagsAreLowered(InitialFrameFlags initial)
 
1053
{
 
1054
    return !!(initial & INITIAL_LOWERED);
 
1055
}
 
1056
 
 
1057
inline StackFrame *          Valueify(JSStackFrame *fp) { return (StackFrame *)fp; }
 
1058
static inline JSStackFrame * Jsvalify(StackFrame *fp)   { return (JSStackFrame *)fp; }
 
1059
 
 
1060
/*****************************************************************************/
 
1061
 
 
1062
class FrameRegs
 
1063
{
 
1064
  public:
 
1065
    Value *sp;
 
1066
    jsbytecode *pc;
 
1067
  private:
 
1068
    InlinedSite *inlined_;
 
1069
    StackFrame *fp_;
 
1070
  public:
 
1071
    StackFrame *fp() const { return fp_; }
 
1072
    InlinedSite *inlined() const { return inlined_; }
 
1073
 
 
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_));
 
1080
    }
 
1081
    void clearInlined() { inlined_ = NULL; }
 
1082
 
 
1083
    unsigned stackDepth() const {
 
1084
        JS_ASSERT(sp >= fp_->base());
 
1085
        return sp - fp_->base();
 
1086
    }
 
1087
 
 
1088
    Value *spForStackDepth(unsigned depth) const {
 
1089
        JS_ASSERT(fp_->script()->nfixed + depth <= fp_->script()->nslots);
 
1090
        return fp_->base() + depth;
 
1091
    }
 
1092
 
 
1093
    /* For generator: */
 
1094
    void rebaseFromTo(const FrameRegs &from, StackFrame &to) {
 
1095
        fp_ = &to;
 
1096
        sp = to.slots() + (from.sp - from.fp_->slots());
 
1097
        pc = from.pc;
 
1098
        inlined_ = from.inlined_;
 
1099
        JS_ASSERT(fp_);
 
1100
    }
 
1101
 
 
1102
    /* For ContextStack: */
 
1103
    void popFrame(Value *newsp) {
 
1104
        pc = fp_->prevpc(&inlined_);
 
1105
        sp = newsp;
 
1106
        fp_ = fp_->prev();
 
1107
        JS_ASSERT(fp_);
 
1108
    }
 
1109
 
 
1110
    /* For FixupArity: */
 
1111
    void popPartialFrame(Value *newsp) {
 
1112
        sp = newsp;
 
1113
        fp_ = fp_->prev();
 
1114
        JS_ASSERT(fp_);
 
1115
    }
 
1116
 
 
1117
    /* For InternalInterpret: */
 
1118
    void restorePartialFrame(Value *newfp) {
 
1119
        fp_ = (StackFrame *) newfp;
 
1120
    }
 
1121
 
 
1122
    /* For EnterMethodJIT: */
 
1123
    void refreshFramePointer(StackFrame *fp) {
 
1124
        fp_ = fp;
 
1125
    }
 
1126
 
 
1127
    /* For stubs::CompileFunction, ContextStack: */
 
1128
    void prepareToRun(StackFrame &fp, JSScript *script) {
 
1129
        pc = script->code;
 
1130
        sp = fp.slots() + script->nfixed;
 
1131
        fp_ = &fp;
 
1132
        inlined_ = NULL;
 
1133
    }
 
1134
 
 
1135
    void setToEndOfScript() {
 
1136
        JSScript *script = fp()->script();
 
1137
        sp = fp()->base();
 
1138
        pc = script->code + script->length - JSOP_STOP_LENGTH;
 
1139
        JS_ASSERT(*pc == JSOP_STOP);
 
1140
    }
 
1141
 
 
1142
    /* For expandInlineFrames: */
 
1143
    void expandInline(StackFrame *innerfp, jsbytecode *innerpc) {
 
1144
        pc = innerpc;
 
1145
        fp_ = innerfp;
 
1146
        inlined_ = NULL;
 
1147
    }
 
1148
 
 
1149
#ifdef JS_METHODJIT
 
1150
    /* For LimitCheck: */
 
1151
    void updateForNcode(mjit::JITScript *jit, void *ncode) {
 
1152
        pc = mjit::NativeToPC(jit, ncode, &inlined_);
 
1153
    }
 
1154
#endif
 
1155
};
 
1156
 
 
1157
/*****************************************************************************/
 
1158
 
 
1159
class StackSegment
 
1160
{
 
1161
    /* Previous segment within same context stack. */
 
1162
    StackSegment *const prevInContext_;
 
1163
 
 
1164
    /* Previous segment sequentially in memory. */
 
1165
    StackSegment *const prevInMemory_;
 
1166
 
 
1167
    /* Execution registers for most recent script in this segment (or null). */
 
1168
    FrameRegs *regs_;
 
1169
 
 
1170
    /* Call args for most recent native call in this segment (or null). */
 
1171
    CallArgsList *calls_;
 
1172
 
 
1173
  public:
 
1174
    StackSegment(StackSegment *prevInContext,
 
1175
                 StackSegment *prevInMemory,
 
1176
                 FrameRegs *regs,
 
1177
                 CallArgsList *calls)
 
1178
      : prevInContext_(prevInContext),
 
1179
        prevInMemory_(prevInMemory),
 
1180
        regs_(regs),
 
1181
        calls_(calls)
 
1182
    {}
 
1183
 
 
1184
    /* A segment is followed in memory by the arguments of the first call. */
 
1185
 
 
1186
    Value *slotsBegin() const {
 
1187
        return (Value *)(this + 1);
 
1188
    }
 
1189
 
 
1190
    /* Accessors. */
 
1191
 
 
1192
    FrameRegs &regs() const {
 
1193
        JS_ASSERT(regs_);
 
1194
        return *regs_;
 
1195
    }
 
1196
 
 
1197
    FrameRegs *maybeRegs() const {
 
1198
        return regs_;
 
1199
    }
 
1200
 
 
1201
    StackFrame *fp() const {
 
1202
        return regs_->fp();
 
1203
    }
 
1204
 
 
1205
    StackFrame *maybefp() const {
 
1206
        return regs_ ? regs_->fp() : NULL;
 
1207
    }
 
1208
 
 
1209
    jsbytecode *maybepc() const {
 
1210
        return regs_ ? regs_->pc : NULL;
 
1211
    }
 
1212
 
 
1213
    CallArgsList &calls() const {
 
1214
        JS_ASSERT(calls_);
 
1215
        return *calls_;
 
1216
    }
 
1217
 
 
1218
    CallArgsList *maybeCalls() const {
 
1219
        return calls_;
 
1220
    }
 
1221
 
 
1222
    Value *callArgv() const {
 
1223
        return calls_->array();
 
1224
    }
 
1225
 
 
1226
    Value *maybeCallArgv() const {
 
1227
        return calls_ ? calls_->array() : NULL;
 
1228
    }
 
1229
 
 
1230
    StackSegment *prevInContext() const {
 
1231
        return prevInContext_;
 
1232
    }
 
1233
 
 
1234
    StackSegment *prevInMemory() const {
 
1235
        return prevInMemory_;
 
1236
    }
 
1237
 
 
1238
    void repointRegs(FrameRegs *regs) {
 
1239
        JS_ASSERT_IF(regs, regs->fp());
 
1240
        regs_ = regs;
 
1241
    }
 
1242
 
 
1243
    bool isEmpty() const {
 
1244
        return !calls_ && !regs_;
 
1245
    }
 
1246
 
 
1247
    bool contains(const StackFrame *fp) const;
 
1248
    bool contains(const FrameRegs *regs) const;
 
1249
    bool contains(const CallArgsList *call) const;
 
1250
 
 
1251
    StackFrame *computeNextFrame(const StackFrame *fp, size_t maxDepth) const;
 
1252
 
 
1253
    Value *end() const;
 
1254
 
 
1255
    FrameRegs *pushRegs(FrameRegs &regs);
 
1256
    void popRegs(FrameRegs *regs);
 
1257
    void pushCall(CallArgsList &callList);
 
1258
    void pointAtCall(CallArgsList &callList);
 
1259
    void popCall();
 
1260
 
 
1261
    /* For jit access: */
 
1262
 
 
1263
    static const size_t offsetOfRegs() { return offsetof(StackSegment, regs_); }
 
1264
};
 
1265
 
 
1266
static const size_t VALUES_PER_STACK_SEGMENT = sizeof(StackSegment) / sizeof(Value);
 
1267
JS_STATIC_ASSERT(sizeof(StackSegment) % sizeof(Value) == 0);
 
1268
 
 
1269
/*****************************************************************************/
 
1270
 
 
1271
class StackSpace
 
1272
{
 
1273
    StackSegment  *seg_;
 
1274
    Value         *base_;
 
1275
    mutable Value *conservativeEnd_;
 
1276
#ifdef XP_WIN
 
1277
    mutable Value *commitEnd_;
 
1278
#endif
 
1279
    Value         *defaultEnd_;
 
1280
    Value         *trustedEnd_;
 
1281
 
 
1282
    void assertInvariants() const {
 
1283
        JS_ASSERT(base_ <= conservativeEnd_);
 
1284
#ifdef XP_WIN
 
1285
        JS_ASSERT(conservativeEnd_ <= commitEnd_);
 
1286
        JS_ASSERT(commitEnd_ <= trustedEnd_);
 
1287
#endif
 
1288
        JS_ASSERT(conservativeEnd_ <= defaultEnd_);
 
1289
        JS_ASSERT(defaultEnd_ <= trustedEnd_);
 
1290
    }
 
1291
 
 
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);
 
1295
 
 
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);
 
1299
 
 
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);
 
1303
 
 
1304
    static void staticAsserts() {
 
1305
        JS_STATIC_ASSERT(CAPACITY_VALS % COMMIT_VALS == 0);
 
1306
    }
 
1307
 
 
1308
    friend class AllFramesIter;
 
1309
    friend class ContextStack;
 
1310
    friend class StackFrame;
 
1311
 
 
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;
 
1316
 
 
1317
    StackSegment &findContainingSegment(const StackFrame *target) const;
 
1318
 
 
1319
    bool containsFast(StackFrame *fp) {
 
1320
        return (Value *)fp >= base_ && (Value *)fp <= trustedEnd_;
 
1321
    }
 
1322
 
 
1323
    void markAndClobberFrame(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc);
 
1324
 
 
1325
  public:
 
1326
    StackSpace();
 
1327
    bool init();
 
1328
    ~StackSpace();
 
1329
 
 
1330
    /*
 
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
 
1334
     * initialiser.
 
1335
     *
 
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.
 
1340
     */
 
1341
    static const unsigned ARGS_LENGTH_MAX = CAPACITY_VALS - (2 * BUFFER_VALS);
 
1342
 
 
1343
    /* See stack layout comment in Stack.h. */
 
1344
    inline Value *firstUnused() const { return seg_ ? seg_->end() : base_; }
 
1345
 
 
1346
    StackSegment &containingSegment(const StackFrame *target) const;
 
1347
 
 
1348
    /*
 
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.
 
1355
     */
 
1356
    static const size_t STACK_JIT_EXTRA = (/*~VALUES_PER_STACK_FRAME*/ 8 + 18) * 10;
 
1357
 
 
1358
    /*
 
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.
 
1365
     *
 
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.
 
1371
     */
 
1372
    inline Value *getStackLimit(JSContext *cx, MaybeReportError report);
 
1373
    bool tryBumpLimit(JSContext *cx, Value *from, unsigned nvals, Value **limit);
 
1374
 
 
1375
    /* Called during GC: mark segments, frames, and slots under firstUnused. */
 
1376
    void markAndClobber(JSTracer *trc);
 
1377
 
 
1378
    /* Called during GC: sets active flag on compartments with active frames. */
 
1379
    void markActiveCompartments();
 
1380
 
 
1381
    /* We only report the committed size;  uncommitted size is uninteresting. */
 
1382
    JS_FRIEND_API(size_t) sizeOfCommitted();
 
1383
 
 
1384
#ifdef DEBUG
 
1385
    bool containsSlow(StackFrame *fp);
 
1386
#endif
 
1387
};
 
1388
 
 
1389
/*****************************************************************************/
 
1390
 
 
1391
class ContextStack
 
1392
{
 
1393
    StackSegment *seg_;
 
1394
    StackSpace *const space_;
 
1395
    JSContext *cx_;
 
1396
 
 
1397
    /*
 
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.
 
1401
     *
 
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().
 
1404
     */
 
1405
    bool onTop() const;
 
1406
 
 
1407
#ifdef DEBUG
 
1408
    void assertSpaceInSync() const;
 
1409
#else
 
1410
    void assertSpaceInSync() const {}
 
1411
#endif
 
1412
 
 
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);
 
1418
 
 
1419
    inline StackFrame *
 
1420
    getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
 
1421
                 JSFunction *fun, JSScript *script, StackFrame::Flags *pflags) const;
 
1422
 
 
1423
    /* Make pop* functions private since only called by guard classes. */
 
1424
    void popSegment();
 
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);
 
1431
 
 
1432
    friend class StackIter;
 
1433
 
 
1434
  public:
 
1435
    ContextStack(JSContext *cx);
 
1436
    ~ContextStack();
 
1437
 
 
1438
    /*** Stack accessors ***/
 
1439
 
 
1440
    /*
 
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.
 
1443
     */
 
1444
    bool empty() const                { return !seg_; }
 
1445
 
 
1446
    /*
 
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()".
 
1450
     */
 
1451
    inline bool hasfp() const { return seg_ && seg_->maybeRegs(); }
 
1452
 
 
1453
    /*
 
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.)
 
1458
     */
 
1459
    ptrdiff_t spIndexOf(const Value *vp);
 
1460
 
 
1461
    /*
 
1462
     * Return the most recent script activation's registers with the same
 
1463
     * caveat as hasfp regarding JS_SaveFrameChain.
 
1464
     */
 
1465
    inline FrameRegs *maybeRegs() const { return seg_ ? seg_->maybeRegs() : NULL; }
 
1466
    inline StackFrame *maybefp() const { return seg_ ? seg_->maybefp() : NULL; }
 
1467
 
 
1468
    /* Faster alternatives to maybe* functions. */
 
1469
    inline FrameRegs &regs() const { JS_ASSERT(hasfp()); return seg_->regs(); }
 
1470
    inline StackFrame *fp() const { JS_ASSERT(hasfp()); return seg_->fp(); }
 
1471
 
 
1472
    /* The StackSpace currently hosting this ContextStack. */
 
1473
    StackSpace &space() const { return *space_; }
 
1474
 
 
1475
    /* Return whether the given frame is in this context's stack. */
 
1476
    bool containsSlow(const StackFrame *target) const;
 
1477
 
 
1478
    /*** Stack manipulation ***/
 
1479
 
 
1480
    /*
 
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.
 
1485
     */
 
1486
    bool pushInvokeArgs(JSContext *cx, unsigned argc, InvokeArgsGuard *ag);
 
1487
 
 
1488
    /* Called by Invoke for a scripted function call. */
 
1489
    bool pushInvokeFrame(JSContext *cx, const CallArgs &args,
 
1490
                         InitialFrameFlags initial, InvokeFrameGuard *ifg);
 
1491
 
 
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);
 
1496
 
 
1497
    /*
 
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.
 
1502
     */
 
1503
    bool pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg);
 
1504
 
 
1505
    /*
 
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.
 
1509
     */
 
1510
    bool pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
 
1511
                         JSFunction &callee, JSScript *script,
 
1512
                         InitialFrameFlags initial);
 
1513
    bool pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
 
1514
                         JSFunction &callee, JSScript *script,
 
1515
                         InitialFrameFlags initial, Value **stackLimit);
 
1516
    void popInlineFrame(FrameRegs &regs);
 
1517
 
 
1518
    /* Pop a partially-pushed frame after hitting the limit before throwing. */
 
1519
    void popFrameAfterOverflow();
 
1520
 
 
1521
    /*
 
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.
 
1526
     */
 
1527
    enum MaybeAllowCrossCompartment {
 
1528
        DONT_ALLOW_CROSS_COMPARTMENT = false,
 
1529
        ALLOW_CROSS_COMPARTMENT = true
 
1530
    };
 
1531
    inline JSScript *currentScript(jsbytecode **pc = NULL,
 
1532
                                   MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
 
1533
 
 
1534
    /* Get the scope chain for the topmost scripted call on the stack. */
 
1535
    inline HandleObject currentScriptedScopeChain() const;
 
1536
 
 
1537
    /*
 
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.
 
1541
     */
 
1542
    StackFrame *getFixupFrame(JSContext *cx, MaybeReportError report,
 
1543
                              const CallArgs &args, JSFunction *fun, JSScript *script,
 
1544
                              void *ncode, InitialFrameFlags initial, Value **stackLimit);
 
1545
 
 
1546
    bool saveFrameChain();
 
1547
    void restoreFrameChain();
 
1548
 
 
1549
    /*
 
1550
     * As an optimization, the interpreter/mjit can operate on a local
 
1551
     * FrameRegs instance repoint the ContextStack to this local instance.
 
1552
     */
 
1553
    inline void repointRegs(FrameRegs *regs) { JS_ASSERT(hasfp()); seg_->repointRegs(regs); }
 
1554
};
 
1555
 
 
1556
/*****************************************************************************/
 
1557
 
 
1558
class InvokeArgsGuard : public CallArgsList
 
1559
{
 
1560
    friend class ContextStack;
 
1561
    ContextStack *stack_;
 
1562
    bool pushedSeg_;
 
1563
    void setPushed(ContextStack &stack) { JS_ASSERT(!pushed()); stack_ = &stack; }
 
1564
  public:
 
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; }
 
1569
};
 
1570
 
 
1571
class FrameGuard
 
1572
{
 
1573
  protected:
 
1574
    friend class ContextStack;
 
1575
    ContextStack *stack_;
 
1576
    bool pushedSeg_;
 
1577
    FrameRegs regs_;
 
1578
    FrameRegs *prevRegs_;
 
1579
    void setPushed(ContextStack &stack) { stack_ = &stack; }
 
1580
  public:
 
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; }
 
1585
 
 
1586
    StackFrame *fp() const { return regs_.fp(); }
 
1587
};
 
1588
 
 
1589
class InvokeFrameGuard : public FrameGuard
 
1590
{};
 
1591
 
 
1592
class ExecuteFrameGuard : public FrameGuard
 
1593
{};
 
1594
 
 
1595
class GeneratorFrameGuard : public FrameGuard
 
1596
{
 
1597
    friend class ContextStack;
 
1598
    JSGenerator *gen_;
 
1599
    Value *stackvp_;
 
1600
  public:
 
1601
    ~GeneratorFrameGuard() { if (pushed()) stack_->popGeneratorFrame(*this); }
 
1602
};
 
1603
 
 
1604
/*****************************************************************************/
 
1605
 
 
1606
/*
 
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:
 
1611
 *
 
1612
 *   for (Stackiter i(cx); !i.done(); ++i) {
 
1613
 *     if (i.isScript()) {
 
1614
 *       ... i.fp() ... i.sp() ... i.pc()
 
1615
 *     } else {
 
1616
 *       JS_ASSERT(i.isNativeCall());
 
1617
 *       ... i.args();
 
1618
 *     }
 
1619
 *   }
 
1620
 *
 
1621
 * The SavedOption parameter additionally lets the iterator continue through
 
1622
 * breaks in the callstack (from JS_SaveFrameChain). The default is to stop.
 
1623
 */
 
1624
class StackIter
 
1625
{
 
1626
    friend class ContextStack;
 
1627
    JSContext    *maybecx_;
 
1628
  public:
 
1629
    enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
 
1630
  private:
 
1631
    SavedOption  savedOption_;
 
1632
 
 
1633
    enum State { DONE, SCRIPTED, NATIVE };
 
1634
    State        state_;
 
1635
 
 
1636
    StackFrame   *fp_;
 
1637
    CallArgsList *calls_;
 
1638
 
 
1639
    StackSegment *seg_;
 
1640
    jsbytecode   *pc_;
 
1641
    JSScript     *script_;
 
1642
    CallArgs     args_;
 
1643
 
 
1644
    void poisonRegs();
 
1645
    void popFrame();
 
1646
    void popCall();
 
1647
    void settleOnNewSegment();
 
1648
    void settleOnNewState();
 
1649
    void startOnSegment(StackSegment *seg);
 
1650
 
 
1651
  public:
 
1652
    StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
 
1653
    StackIter(JSRuntime *rt, StackSegment &seg);
 
1654
 
 
1655
    bool done() const { return state_ == DONE; }
 
1656
    StackIter &operator++();
 
1657
 
 
1658
    bool operator==(const StackIter &rhs) const;
 
1659
    bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
 
1660
 
 
1661
    bool isScript() const { JS_ASSERT(!done()); return state_ == SCRIPTED; }
 
1662
    bool isNativeCall() const {
 
1663
        JS_ASSERT(!done());
 
1664
        return state_ == NATIVE;
 
1665
    }
 
1666
 
 
1667
    bool isFunctionFrame() const;
 
1668
    bool isEvalFrame() const;
 
1669
    bool isNonEvalFunctionFrame() const;
 
1670
    bool isConstructing() const;
 
1671
 
 
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;
 
1678
 
 
1679
    CallArgs nativeArgs() const { JS_ASSERT(isNativeCall()); return args_; }
 
1680
};
 
1681
 
 
1682
/* A filtering of the StackIter to only stop at scripts. */
 
1683
class ScriptFrameIter : public StackIter
 
1684
{
 
1685
    void settle() {
 
1686
        while (!done() && !isScript())
 
1687
            StackIter::operator++();
 
1688
    }
 
1689
 
 
1690
  public:
 
1691
    ScriptFrameIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
 
1692
        : StackIter(cx, opt) { settle(); }
 
1693
 
 
1694
    ScriptFrameIter &operator++() { StackIter::operator++(); settle(); return *this; }
 
1695
};
 
1696
 
 
1697
/* A filtering of the StackIter to only stop at non-self-hosted scripts. */
 
1698
class NonBuiltinScriptFrameIter : public StackIter
 
1699
{
 
1700
    void settle() {
 
1701
        while (!done() && (!isScript() || (isFunctionFrame() && fp()->fun()->isSelfHostedBuiltin())))
 
1702
            StackIter::operator++();
 
1703
    }
 
1704
 
 
1705
  public:
 
1706
    NonBuiltinScriptFrameIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
 
1707
        : StackIter(cx, opt) { settle(); }
 
1708
 
 
1709
    NonBuiltinScriptFrameIter &operator++() { StackIter::operator++(); settle(); return *this; }
 
1710
};
 
1711
 
 
1712
/*****************************************************************************/
 
1713
 
 
1714
/*
 
1715
 * Blindly iterate over all frames in the current thread's stack. These frames
 
1716
 * can be from different contexts and compartments, so beware.
 
1717
 */
 
1718
class AllFramesIter
 
1719
{
 
1720
  public:
 
1721
    AllFramesIter(StackSpace &space);
 
1722
 
 
1723
    bool done() const { return fp_ == NULL; }
 
1724
    AllFramesIter& operator++();
 
1725
 
 
1726
    StackFrame *fp() const { return fp_; }
 
1727
 
 
1728
  private:
 
1729
    void settle();
 
1730
    StackSegment *seg_;
 
1731
    StackFrame *fp_;
 
1732
};
 
1733
 
 
1734
}  /* namespace js */
 
1735
#endif /* Stack_h__ */