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 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey JavaScript engine.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Mozilla Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 2009
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Luke Wagner <luke@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef Stack_h__
42 : #define Stack_h__
43 :
44 : #include "jsfun.h"
45 :
46 : struct JSContext;
47 : struct JSCompartment;
48 :
49 : #ifdef JS_METHODJIT
50 : namespace js { namespace mjit { struct CallSite; }}
51 : typedef js::mjit::CallSite JSInlinedSite;
52 : #else
53 : struct JSInlinedSite {};
54 : #endif
55 :
56 : typedef /* js::mjit::RejoinState */ size_t JSRejoinState;
57 :
58 : namespace js {
59 :
60 : class StackFrame;
61 : class FrameRegs;
62 : class StackSegment;
63 : class StackSpace;
64 : class ContextStack;
65 :
66 : class InvokeArgsGuard;
67 : class InvokeFrameGuard;
68 : class FrameGuard;
69 : class ExecuteFrameGuard;
70 : class DummyFrameGuard;
71 : class GeneratorFrameGuard;
72 :
73 : class CallIter;
74 : class FrameRegsIter;
75 : class AllFramesIter;
76 :
77 : class ArgumentsObject;
78 : class StaticBlockObject;
79 :
80 : #ifdef JS_METHODJIT
81 : namespace mjit {
82 : struct JITScript;
83 : jsbytecode *NativeToPC(JITScript *jit, void *ncode, CallSite **pinline);
84 : }
85 : #endif
86 :
87 : namespace detail {
88 : struct OOMCheck;
89 : }
90 :
91 : /*****************************************************************************/
92 :
93 : /*
94 : * VM stack layout
95 : *
96 : * SpiderMonkey uses a per-thread stack to store the activation records,
97 : * parameters, locals, and expression temporaries for the stack of actively
98 : * executing scripts, functions and generators. The stack is owned by the
99 : * StackSpace object stored in the runtime.
100 : *
101 : * The stack is subdivided into contiguous segments of memory which
102 : * have a memory layout invariant that allows fixed offsets to be used for stack
103 : * access (by jit code) as well as fast call/return. This memory layout is
104 : * encapsulated by a set of types that describe different regions of memory.
105 : * This encapsulation has holes: to avoid calling into C++ from generated code,
106 : * JIT compilers generate code that simulates analogous operations in C++.
107 : *
108 : * A sample memory layout of a segment looks like:
109 : *
110 : * regs
111 : * .---------------------------------------------.
112 : * | V
113 : * | fp .--FrameRegs--. sp
114 : * | V V
115 : * |StackSegment| slots |StackFrame| slots |StackFrame| slots |
116 : * | ^ |
117 : * ? <----------' `-----------'
118 : * prev prev
119 : *
120 : * A segment starts with a fixed-size header (js::StackSegment) which logically
121 : * describes the segment, links it to the rest of the stack, and points to the
122 : * end of the stack.
123 : *
124 : * Each script activation (global or function code) is given a fixed-size header
125 : * (js::StackFrame) which is associated with the values (called "slots") before
126 : * and after it. The frame contains bookkeeping information about the activation
127 : * and links to the previous frame.
128 : *
129 : * The slots preceding a (function) StackFrame in memory are the arguments of
130 : * the call. The slots after a StackFrame in memory are its locals followed by
131 : * its expression stack. There is no clean line between the arguments of a
132 : * frame and the expression stack of the previous frame since the top slots of
133 : * the expression become the arguments of a call. There are also layout
134 : * invariants concerning the arguments and StackFrame; see "Arguments" comment
135 : * in StackFrame for more details.
136 : *
137 : * The top of a segment's current frame's expression stack is pointed to by the
138 : * segment's "current regs", which contains the stack pointer 'sp'. In the
139 : * interpreter, sp is adjusted as individual values are pushed and popped from
140 : * the stack and the FrameRegs struct (pointed by the StackSegment) is a local
141 : * var of js::Interpret. JIT code simulates this by lazily updating FrameRegs
142 : * when calling from JIT code into the VM. Ideally, we'd like to remove all
143 : * dependence on FrameRegs outside the interpreter.
144 : *
145 : * A call to a native (C++) function does not push a frame. Instead, an array
146 : * of values is passed to the native. The layout of this array is abstracted by
147 : * js::CallArgs. With respect to the StackSegment layout above, the args to a
148 : * native call are inserted anywhere there can be slots. A sample memory layout
149 : * looks like:
150 : *
151 : * regs
152 : * .----------------------------------------.
153 : * | V
154 : * | fp .--FrameRegs--. sp
155 : * | V V
156 : * |StackSegment| native call | slots |StackFrame| slots | native call |
157 : * | vp <--argc--> end vp <--argc--> end
158 : * | CallArgs <------------------------------ CallArgs
159 : * | prev ^
160 : * `-----------------------------------------------------'
161 : * calls
162 : *
163 : * Here there are two native calls on the stack. The start of each native arg
164 : * range is recorded by a CallArgs element which is prev-linked like stack
165 : * frames. Note that, in full generality, native and scripted calls can
166 : * interleave arbitrarily. Thus, the end of a segment is the maximum of its
167 : * current frame and its current native call. Similarly, the top of the entire
168 : * thread stack is the end of its current segment.
169 : *
170 : * Note that, between any two StackFrames there may be any number
171 : * of native calls, so the meaning of 'prev' is not 'directly called by'.
172 : *
173 : * An additional feature (perhaps not for much longer: bug 650361) is that
174 : * multiple independent "contexts" can interleave (LIFO) on a single contiguous
175 : * stack. "Independent" here means that neither context sees the other's
176 : * frames. Concretely, an embedding may enter the JS engine on cx1 and then,
177 : * from a native called by the JS engine, reenter the VM on cx2. Changing from
178 : * cx1 to cx2 causes a new segment to be started for cx2's stack on top of
179 : * cx1's current segment. These two segments are linked from the perspective of
180 : * StackSpace, since they are adjacent on the thread's stack, but not from the
181 : * perspective of cx1 and cx2. Thus, each segment has two links: prevInMemory
182 : * and prevInContext. Each independent stack is encapsulated and managed by
183 : * the js::ContextStack object stored in JSContext. ContextStack is the primary
184 : * interface to the rest of the engine for pushing and popping the stack.
185 : */
186 :
187 : /*****************************************************************************/
188 :
189 : class CallReceiver
190 : {
191 : protected:
192 : #ifdef DEBUG
193 : mutable bool usedRval_;
194 45907627 : void setUsedRval() const { usedRval_ = true; }
195 61945528 : void clearUsedRval() const { usedRval_ = false; }
196 : #else
197 : void setUsedRval() const {}
198 : void clearUsedRval() const {}
199 : #endif
200 : Value *argv_;
201 : public:
202 : friend CallReceiver CallReceiverFromVp(Value *);
203 : friend CallReceiver CallReceiverFromArgv(Value *);
204 46828013 : Value *base() const { return argv_ - 2; }
205 45368357 : JSObject &callee() const { JS_ASSERT(!usedRval_); return argv_[-2].toObject(); }
206 45382195 : Value &calleev() const { JS_ASSERT(!usedRval_); return argv_[-2]; }
207 39715443 : Value &thisv() const { return argv_[-1]; }
208 :
209 39559647 : Value &rval() const {
210 39559647 : setUsedRval();
211 39559647 : return argv_[-2];
212 : }
213 :
214 6347980 : Value *spAfterCall() const {
215 6347980 : setUsedRval();
216 6347980 : return argv_ - 1;
217 : }
218 :
219 307685 : void setCallee(Value calleev) {
220 307685 : clearUsedRval();
221 307685 : this->calleev() = calleev;
222 307685 : }
223 : };
224 :
225 : JS_ALWAYS_INLINE CallReceiver
226 60525 : CallReceiverFromArgv(Value *argv)
227 : {
228 : CallReceiver receiver;
229 60525 : receiver.clearUsedRval();
230 60525 : receiver.argv_ = argv;
231 : return receiver;
232 : }
233 :
234 : JS_ALWAYS_INLINE CallReceiver
235 1178 : CallReceiverFromVp(Value *vp)
236 : {
237 1178 : return CallReceiverFromArgv(vp + 2);
238 : }
239 :
240 : /*****************************************************************************/
241 :
242 : class CallArgs : public CallReceiver
243 : {
244 : protected:
245 : unsigned argc_;
246 : public:
247 : friend CallArgs CallArgsFromVp(unsigned, Value *);
248 : friend CallArgs CallArgsFromArgv(unsigned, Value *);
249 : friend CallArgs CallArgsFromSp(unsigned, Value *);
250 40252411 : Value &operator[](unsigned i) const { JS_ASSERT(i < argc_); return argv_[i]; }
251 32604031 : Value *array() const { return argv_; }
252 132826100 : unsigned length() const { return argc_; }
253 122658109 : Value *end() const { return argv_ + argc_; }
254 1171028 : bool hasDefined(unsigned i) const { return i < argc_ && !argv_[i].isUndefined(); }
255 : };
256 :
257 : JS_ALWAYS_INLINE CallArgs
258 61577318 : CallArgsFromArgv(unsigned argc, Value *argv)
259 : {
260 : CallArgs args;
261 61577318 : args.clearUsedRval();
262 61577318 : args.argv_ = argv;
263 61577318 : args.argc_ = argc;
264 : return args;
265 : }
266 :
267 : JS_ALWAYS_INLINE CallArgs
268 15605133 : CallArgsFromVp(unsigned argc, Value *vp)
269 : {
270 15605133 : return CallArgsFromArgv(argc, vp + 2);
271 : }
272 :
273 : JS_ALWAYS_INLINE CallArgs
274 45972185 : CallArgsFromSp(unsigned argc, Value *sp)
275 : {
276 45972185 : return CallArgsFromArgv(argc, sp - argc);
277 : }
278 :
279 : /*****************************************************************************/
280 :
281 : /*
282 : * For calls to natives, the InvokeArgsGuard object provides a record of the
283 : * call for the debugger's callstack. For this to work, the InvokeArgsGuard
284 : * record needs to know when the call is actually active (because the
285 : * InvokeArgsGuard can be pushed long before and popped long after the actual
286 : * call, during which time many stack-observing things can happen).
287 : */
288 : class CallArgsList : public CallArgs
289 : {
290 : friend class StackSegment;
291 : CallArgsList *prev_;
292 : bool active_;
293 : public:
294 : friend CallArgsList CallArgsListFromVp(unsigned, Value *, CallArgsList *);
295 : friend CallArgsList CallArgsListFromArgv(unsigned, Value *, CallArgsList *);
296 108888 : CallArgsList *prev() const { return prev_; }
297 108888 : bool active() const { return active_; }
298 2413167 : void setActive() { active_ = true; }
299 2413167 : void setInactive() { active_ = false; }
300 : };
301 :
302 : JS_ALWAYS_INLINE CallArgsList
303 : CallArgsListFromArgv(unsigned argc, Value *argv, CallArgsList *prev)
304 : {
305 : CallArgsList args;
306 : #ifdef DEBUG
307 : args.usedRval_ = false;
308 : #endif
309 : args.argv_ = argv;
310 : args.argc_ = argc;
311 : args.prev_ = prev;
312 : args.active_ = false;
313 : return args;
314 : }
315 :
316 : JS_ALWAYS_INLINE CallArgsList
317 : CallArgsListFromVp(unsigned argc, Value *vp, CallArgsList *prev)
318 : {
319 : return CallArgsListFromArgv(argc, vp + 2, prev);
320 : }
321 :
322 : /*****************************************************************************/
323 :
324 : /* Flags specified for a frame as it is constructed. */
325 : enum InitialFrameFlags {
326 : INITIAL_NONE = 0,
327 : INITIAL_CONSTRUCT = 0x80, /* == StackFrame::CONSTRUCTING, asserted below */
328 : INITIAL_LOWERED = 0x200000 /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
329 : };
330 :
331 : enum ExecuteType {
332 : EXECUTE_GLOBAL = 0x1, /* == StackFrame::GLOBAL */
333 : EXECUTE_DIRECT_EVAL = 0x8, /* == StackFrame::EVAL */
334 : EXECUTE_INDIRECT_EVAL = 0x9, /* == StackFrame::GLOBAL | EVAL */
335 : EXECUTE_DEBUG = 0x18 /* == StackFrame::EVAL | DEBUGGER */
336 : };
337 :
338 : /*****************************************************************************/
339 :
340 : class StackFrame
341 : {
342 : public:
343 : enum Flags {
344 : /* Primary frame type */
345 : GLOBAL = 0x1, /* frame pushed for a global script */
346 : FUNCTION = 0x2, /* frame pushed for a scripted call */
347 : DUMMY = 0x4, /* frame pushed for bookkeeping */
348 :
349 : /* Frame subtypes */
350 : EVAL = 0x8, /* frame pushed for eval() or debugger eval */
351 : DEBUGGER = 0x10, /* frame pushed for debugger eval */
352 : GENERATOR = 0x20, /* frame is associated with a generator */
353 : FLOATING_GENERATOR = 0x40, /* frame is is in generator obj, not on stack */
354 : CONSTRUCTING = 0x80, /* frame is for a constructor invocation */
355 :
356 : /* Temporary frame states */
357 : YIELDING = 0x100, /* js::Interpret dispatched JSOP_YIELD */
358 : FINISHED_IN_INTERP = 0x200, /* set if frame finished in Interpret() */
359 :
360 : /* Function arguments */
361 : OVERFLOW_ARGS = 0x400, /* numActualArgs > numFormalArgs */
362 : UNDERFLOW_ARGS = 0x800, /* numActualArgs < numFormalArgs */
363 :
364 : /* Lazy frame initialization */
365 : HAS_CALL_OBJ = 0x1000, /* frame has a callobj reachable from scopeChain_ */
366 : HAS_ARGS_OBJ = 0x2000, /* frame has an argsobj in StackFrame::args */
367 : HAS_HOOK_DATA = 0x4000, /* frame has hookData_ set */
368 : HAS_ANNOTATION = 0x8000, /* frame has annotation_ set */
369 : HAS_RVAL = 0x10000, /* frame has rval_ set */
370 : HAS_SCOPECHAIN = 0x20000, /* frame has scopeChain_ set */
371 : HAS_PREVPC = 0x40000, /* frame has prevpc_ and prevInline_ set */
372 : HAS_BLOCKCHAIN = 0x80000, /* frame has blockChain_ set */
373 :
374 : /* Method JIT state */
375 : DOWN_FRAMES_EXPANDED = 0x100000, /* inlining in down frames has been expanded */
376 : LOWERED_CALL_APPLY = 0x200000 /* Pushed by a lowered call/apply */
377 : };
378 :
379 : private:
380 : mutable uint32_t flags_; /* bits described by Flags */
381 : union { /* describes what code is executing in a */
382 : JSScript *script; /* global frame */
383 : JSFunction *fun; /* function frame, pre GetScopeChain */
384 : } exec;
385 : union { /* describes the arguments of a function */
386 : unsigned nactual; /* for non-eval frames */
387 : JSScript *evalScript; /* the script of an eval-in-function */
388 : } u;
389 : mutable JSObject *scopeChain_; /* current scope chain */
390 : StackFrame *prev_; /* previous cx->regs->fp */
391 : void *ncode_; /* return address for method JIT */
392 :
393 : /* Lazily initialized */
394 : Value rval_; /* return value of the frame */
395 : StaticBlockObject *blockChain_; /* innermost let block */
396 : ArgumentsObject *argsObj_; /* if has HAS_ARGS_OBJ */
397 : jsbytecode *prevpc_; /* pc of previous frame*/
398 : JSInlinedSite *prevInline_; /* inlined site in previous frame */
399 : void *hookData_; /* closure returned by call hook */
400 : void *annotation_; /* perhaps remove with bug 546848 */
401 : JSRejoinState rejoin_; /* If rejoining into the interpreter
402 : * from JIT code, state at rejoin. */
403 :
404 : static void staticAsserts() {
405 : JS_STATIC_ASSERT(offsetof(StackFrame, rval_) % sizeof(Value) == 0);
406 : JS_STATIC_ASSERT(sizeof(StackFrame) % sizeof(Value) == 0);
407 : }
408 :
409 : inline void initPrev(JSContext *cx);
410 : jsbytecode *prevpcSlow(JSInlinedSite **pinlined);
411 :
412 : public:
413 : /*
414 : * Frame initialization
415 : *
416 : * After acquiring a pointer to an uninitialized stack frame on the VM
417 : * stack from StackSpace, these members are used to initialize the stack
418 : * frame before officially pushing the frame into the context.
419 : */
420 :
421 : /* Used for Invoke, Interpret, trace-jit LeaveTree, and method-jit stubs. */
422 : void initCallFrame(JSContext *cx, JSFunction &callee,
423 : JSScript *script, uint32_t nactual, StackFrame::Flags flags);
424 :
425 : /* Used for getFixupFrame (for FixupArity). */
426 : void initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncode, unsigned nactual);
427 :
428 : /* Used for eval. */
429 : void initExecuteFrame(JSScript *script, StackFrame *prev, FrameRegs *regs,
430 : const Value &thisv, JSObject &scopeChain, ExecuteType type);
431 :
432 : /* Used when activating generators. */
433 : enum TriggerPostBarriers {
434 : DoPostBarrier = true,
435 : NoPostBarrier = false
436 : };
437 : template <class T, class U, TriggerPostBarriers doPostBarrier>
438 : void stealFrameAndSlots(StackFrame *fp, T *vp, StackFrame *otherfp, U *othervp,
439 : Value *othersp);
440 : void writeBarrierPost();
441 :
442 : /* Perhaps one fine day we will remove dummy frames. */
443 : void initDummyFrame(JSContext *cx, JSObject &chain);
444 :
445 : /*
446 : * Stack frame type
447 : *
448 : * A stack frame may have one of three types, which determines which
449 : * members of the frame may be accessed and other invariants:
450 : *
451 : * global frame: execution of global code or an eval in global code
452 : * function frame: execution of function code or an eval in a function
453 : * dummy frame: bookkeeping frame (to be removed in bug 625199)
454 : */
455 :
456 -1643736557 : bool isFunctionFrame() const {
457 -1643736557 : return !!(flags_ & FUNCTION);
458 : }
459 :
460 99919 : bool isGlobalFrame() const {
461 99919 : return !!(flags_ & GLOBAL);
462 : }
463 :
464 1163403984 : bool isDummyFrame() const {
465 1163403984 : return !!(flags_ & DUMMY);
466 : }
467 :
468 1117913507 : bool isScriptFrame() const {
469 1117913507 : bool retval = !!(flags_ & (FUNCTION | GLOBAL));
470 1117913507 : JS_ASSERT(retval == !isDummyFrame());
471 1117913507 : return retval;
472 : }
473 :
474 : /*
475 : * Eval frames
476 : *
477 : * As noted above, global and function frames may optionally be 'eval
478 : * frames'. Eval code shares its parent's arguments which means that the
479 : * arg-access members of StackFrame may not be used for eval frames.
480 : * Search for 'hasArgs' below for more details.
481 : *
482 : * A further sub-classification of eval frames is whether the frame was
483 : * pushed for an ES5 strict-mode eval().
484 : */
485 :
486 1088538349 : bool isEvalFrame() const {
487 1088538349 : JS_ASSERT_IF(flags_ & EVAL, isScriptFrame());
488 1088538349 : return flags_ & EVAL;
489 : }
490 :
491 : bool isEvalInFunction() const {
492 : return (flags_ & (EVAL | FUNCTION)) == (EVAL | FUNCTION);
493 : }
494 :
495 589055068 : bool isNonEvalFunctionFrame() const {
496 589055068 : return (flags_ & (FUNCTION | EVAL)) == FUNCTION;
497 : }
498 :
499 309981 : inline bool isStrictEvalFrame() const {
500 309981 : return isEvalFrame() && script()->strictModeCode;
501 : }
502 :
503 2855266 : bool isNonStrictEvalFrame() const {
504 2855266 : return isEvalFrame() && !script()->strictModeCode;
505 : }
506 :
507 : /*
508 : * Previous frame
509 : *
510 : * A frame's 'prev' frame is either null or the previous frame pointed to
511 : * by cx->regs->fp when this frame was pushed. Often, given two prev-linked
512 : * frames, the next-frame is a function or eval that was called by the
513 : * prev-frame, but not always: the prev-frame may have called a native that
514 : * reentered the VM through JS_CallFunctionValue on the same context
515 : * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus,
516 : * 'prev' has little semantic meaning and basically just tells the VM what
517 : * to set cx->regs->fp to when this frame is popped.
518 : */
519 :
520 137129032 : StackFrame *prev() const {
521 137129032 : return prev_;
522 : }
523 :
524 : inline void resetGeneratorPrev(JSContext *cx);
525 : inline void resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc);
526 :
527 : inline void initInlineFrame(JSFunction *fun, StackFrame *prevfp, jsbytecode *prevpc);
528 :
529 : /*
530 : * Frame slots
531 : *
532 : * A frame's 'slots' are the fixed slots associated with the frame (like
533 : * local variables) followed by an expression stack holding temporary
534 : * values. A frame's 'base' is the base of the expression stack.
535 : */
536 :
537 938484342 : Value *slots() const {
538 938484342 : return (Value *)(this + 1);
539 : }
540 :
541 98860570 : Value *base() const {
542 98860570 : return slots() + script()->nfixed;
543 : }
544 :
545 518226 : Value &varSlot(unsigned i) {
546 518226 : JS_ASSERT(i < script()->nfixed);
547 518226 : JS_ASSERT_IF(maybeFun(), i < script()->bindings.countVars());
548 518226 : return slots()[i];
549 : }
550 :
551 775664200 : Value &localSlot(unsigned i) {
552 : /* Let variables can be above script->nfixed. */
553 775664200 : JS_ASSERT(i < script()->nslots);
554 775664200 : return slots()[i];
555 : }
556 :
557 : /*
558 : * Script
559 : *
560 : * All function and global frames have an associated JSScript which holds
561 : * the bytecode being executed for the frame. This script/bytecode does
562 : * not reflect any inlining that has been performed by the method JIT.
563 : * If other frames were inlined into this one, the script/pc reflect the
564 : * point of the outermost call. Inlined frame invariants:
565 : *
566 : * - Inlined frames have the same scope chain as the outer frame.
567 : * - Inlined frames have the same strictness as the outer frame.
568 : * - Inlined frames can only make calls to other JIT frames associated with
569 : * the same VMFrame. Other calls force expansion of the inlined frames.
570 : */
571 :
572 : /*
573 : * Get the frame's current bytecode, assuming |this| is in |cx|. next is
574 : * frame whose prev == this, NULL if not known or if this == cx->fp().
575 : * If the frame is inside an inline call made within the pc, the pc will
576 : * be that of the outermost call and the state of any inlined frame(s) is
577 : * returned through pinlined.
578 : *
579 : * Beware, as the name implies, pcQuadratic can lead to quadratic behavior
580 : * in loops such as:
581 : *
582 : * for ( ...; fp; fp = fp->prev())
583 : * ... fp->pcQuadratic(cx->stack);
584 : *
585 : * Using next can avoid this, but in most cases prefer FrameRegsIter;
586 : * it is amortized O(1).
587 : *
588 : * When I get to the bottom I go back to the top of the stack
589 : * Where I stop and I turn and I go right back
590 : * Till I get to the bottom and I see you again...
591 : */
592 : jsbytecode *pcQuadratic(const ContextStack &stack, StackFrame *next = NULL,
593 : JSInlinedSite **pinlined = NULL);
594 :
595 64763421 : jsbytecode *prevpc(JSInlinedSite **pinlined) {
596 64763421 : if (flags_ & HAS_PREVPC) {
597 63595171 : if (pinlined)
598 63593858 : *pinlined = prevInline_;
599 63595171 : return prevpc_;
600 : }
601 1168250 : return prevpcSlow(pinlined);
602 : }
603 :
604 55 : JSInlinedSite *prevInline() {
605 55 : JS_ASSERT(flags_ & HAS_PREVPC);
606 55 : return prevInline_;
607 : }
608 :
609 1103013924 : JSScript *script() const {
610 1103013924 : JS_ASSERT(isScriptFrame());
611 1103013924 : return isFunctionFrame()
612 2113993719 : ? isEvalFrame() ? u.evalScript : fun()->script()
613 -1077959653 : : exec.script;
614 : }
615 :
616 468 : JSScript *functionScript() const {
617 468 : JS_ASSERT(isFunctionFrame());
618 468 : return isEvalFrame() ? u.evalScript : fun()->script();
619 : }
620 :
621 : JSScript *globalScript() const {
622 : JS_ASSERT(isGlobalFrame());
623 : return exec.script;
624 : }
625 :
626 6340951 : JSScript *maybeScript() const {
627 6340951 : return isScriptFrame() ? script() : NULL;
628 : }
629 :
630 2475 : size_t numFixed() const {
631 2475 : return script()->nfixed;
632 : }
633 :
634 1268257 : size_t numSlots() const {
635 1268257 : return script()->nslots;
636 : }
637 :
638 : size_t numGlobalVars() const {
639 : JS_ASSERT(isGlobalFrame());
640 : return exec.script->nfixed;
641 : }
642 :
643 : /*
644 : * Function
645 : *
646 : * All function frames have an associated interpreted JSFunction. The
647 : * function returned by fun() and maybeFun() is not necessarily the
648 : * original canonical function which the frame's script was compiled
649 : * against. To get this function, use maybeScriptFunction().
650 : */
651 :
652 1458256847 : JSFunction* fun() const {
653 1458256847 : JS_ASSERT(isFunctionFrame());
654 1458256847 : return exec.fun;
655 : }
656 :
657 44676285 : JSFunction* maybeFun() const {
658 44676285 : return isFunctionFrame() ? fun() : NULL;
659 : }
660 :
661 0 : JSFunction* maybeScriptFunction() const {
662 0 : if (!isFunctionFrame())
663 0 : return NULL;
664 0 : const StackFrame *fp = this;
665 0 : while (fp->isEvalFrame())
666 0 : fp = fp->prev();
667 0 : return fp->script()->function();
668 : }
669 :
670 : /*
671 : * Arguments
672 : *
673 : * Only non-eval function frames have arguments. A frame follows its
674 : * arguments contiguously in memory. The arguments pushed by the caller are
675 : * the 'actual' arguments. The declared arguments of the callee are the
676 : * 'formal' arguments. When the caller passes less or equal actual
677 : * arguments, the actual and formal arguments are the same array (but with
678 : * different extents). When the caller passes too many arguments, the
679 : * formal subset of the actual arguments is copied onto the top of the
680 : * stack. This allows the engine to maintain a jit-time constant offset of
681 : * arguments from the frame pointer. Since the formal subset of the actual
682 : * arguments is potentially on the stack twice, it is important for all
683 : * reads/writes to refer to the same canonical memory location.
684 : *
685 : * An arguments object (the object returned by the 'arguments' keyword) is
686 : * lazily created, so a given function frame may or may not have one.
687 : */
688 :
689 : /* True if this frame has arguments. Contrast with hasArgsObj. */
690 505249130 : bool hasArgs() const {
691 505249130 : return isNonEvalFunctionFrame();
692 : }
693 :
694 285932394 : unsigned numFormalArgs() const {
695 285932394 : JS_ASSERT(hasArgs());
696 285932394 : return fun()->nargs;
697 : }
698 :
699 94704268 : Value &formalArg(unsigned i) const {
700 94704268 : JS_ASSERT(i < numFormalArgs());
701 94704268 : return formalArgs()[i];
702 : }
703 :
704 175647234 : Value *formalArgs() const {
705 175647234 : JS_ASSERT(hasArgs());
706 175647234 : return (Value *)this - numFormalArgs();
707 : }
708 :
709 6821729 : Value *formalArgsEnd() const {
710 6821729 : JS_ASSERT(hasArgs());
711 6821729 : return (Value *)this;
712 : }
713 :
714 19945930 : Value *maybeFormalArgs() const {
715 : return (flags_ & (FUNCTION | EVAL)) == FUNCTION
716 : ? formalArgs()
717 19945930 : : NULL;
718 : }
719 :
720 : inline unsigned numActualArgs() const;
721 : inline Value *actualArgs() const;
722 : inline Value *actualArgsEnd() const;
723 :
724 : inline Value &canonicalActualArg(unsigned i) const;
725 : template <class Op>
726 212847 : inline bool forEachCanonicalActualArg(Op op, unsigned start = 0, unsigned count = unsigned(-1));
727 : template <class Op> inline bool forEachFormalArg(Op op);
728 :
729 4006024 : bool hasArgsObj() const {
730 : /*
731 : * HAS_ARGS_OBJ is still technically not equivalent to
732 : * script()->needsArgsObj() during functionPrologue (where GC can
733 : * observe a frame that needsArgsObj but has not yet been given the
734 : * args). This can be fixed by creating and rooting the args/call
735 : * object before pushing the frame, which should be done eventually.
736 : */
737 4006024 : return !!(flags_ & HAS_ARGS_OBJ);
738 : }
739 :
740 735011 : ArgumentsObject &argsObj() const {
741 735011 : JS_ASSERT(hasArgsObj());
742 735011 : return *argsObj_;
743 : }
744 :
745 0 : ArgumentsObject *maybeArgsObj() const {
746 0 : return hasArgsObj() ? &argsObj() : NULL;
747 : }
748 :
749 361882 : void initArgsObj(ArgumentsObject &argsObj) {
750 361882 : JS_ASSERT(script()->needsArgsObj());
751 361882 : JS_ASSERT(!hasArgsObj());
752 361882 : argsObj_ = &argsObj;
753 361882 : flags_ |= HAS_ARGS_OBJ;
754 361882 : }
755 :
756 : /*
757 : * This value
758 : *
759 : * Every frame has a this value although, until 'this' is computed, the
760 : * value may not be the semantically-correct 'this' value.
761 : *
762 : * The 'this' value is stored before the formal arguments for function
763 : * frames and directly before the frame for global frames. The *Args
764 : * members assert !isEvalFrame(), so we implement specialized inline
765 : * methods for accessing 'this'. When the caller has static knowledge that
766 : * a frame is a function or global frame, 'functionThis' and 'globalThis',
767 : * respectively, allow more efficient access.
768 : */
769 :
770 872149 : Value &functionThis() const {
771 872149 : JS_ASSERT(isFunctionFrame());
772 872149 : if (isEvalFrame())
773 0 : return ((Value *)this)[-1];
774 872149 : return formalArgs()[-1];
775 : }
776 :
777 808789 : JSObject &constructorThis() const {
778 808789 : JS_ASSERT(hasArgs());
779 808789 : return formalArgs()[-1].toObject();
780 : }
781 :
782 : Value &globalThis() const {
783 : JS_ASSERT(isGlobalFrame());
784 : return ((Value *)this)[-1];
785 : }
786 :
787 27839614 : Value &thisValue() const {
788 27839614 : if (flags_ & (EVAL | GLOBAL))
789 347484 : return ((Value *)this)[-1];
790 27492130 : return formalArgs()[-1];
791 : }
792 :
793 : /*
794 : * Callee
795 : *
796 : * Only function frames have a callee. An eval frame in a function has the
797 : * same caller as its containing function frame. maybeCalleev can be used
798 : * to return a value that is either caller object (for function frames) or
799 : * null (for global frames).
800 : */
801 :
802 12252379 : JSObject &callee() const {
803 12252379 : JS_ASSERT(isFunctionFrame());
804 12252379 : return calleev().toObject();
805 : }
806 :
807 12332659 : const Value &calleev() const {
808 12332659 : JS_ASSERT(isFunctionFrame());
809 12332659 : return mutableCalleev();
810 : }
811 :
812 0 : const Value &maybeCalleev() const {
813 0 : JS_ASSERT(isScriptFrame());
814 : Value &calleev = flags_ & (EVAL | GLOBAL)
815 0 : ? ((Value *)this)[-2]
816 0 : : formalArgs()[-2];
817 0 : JS_ASSERT(calleev.isObjectOrNull());
818 0 : return calleev;
819 : }
820 :
821 12332659 : Value &mutableCalleev() const {
822 12332659 : JS_ASSERT(isFunctionFrame());
823 12332659 : if (isEvalFrame())
824 153 : return ((Value *)this)[-2];
825 12332506 : return formalArgs()[-2];
826 : }
827 :
828 59347 : CallReceiver callReceiver() const {
829 59347 : return CallReceiverFromArgv(formalArgs());
830 : }
831 :
832 : /*
833 : * Scope chain
834 : *
835 : * Every frame has a scopeChain which, when traversed via the 'parent' link
836 : * to the root, indicates the current global object. A 'call object' is a
837 : * node on a scope chain representing a function's activation record. A
838 : * call object is used for dynamically-scoped name lookup and lexically-
839 : * scoped upvar access. The call object holds the values of locals and
840 : * arguments when a function returns (and its stack frame is popped). For
841 : * performance reasons, call objects are created lazily for 'lightweight'
842 : * functions, i.e., functions which are not statically known to require a
843 : * call object. Thus, a given function frame may or may not have a call
844 : * object. When a function does have a call object, it is found by walking
845 : * up the scope chain until the first call object. Thus, it is important,
846 : * when setting the scope chain, to indicate whether the new scope chain
847 : * contains a new call object and thus changes the 'hasCallObj' state.
848 : *
849 : * The method JIT requires that HAS_SCOPECHAIN be set for all frames which
850 : * use NAME or related opcodes that can access the scope chain (so it does
851 : * not have to test the bit). To ensure this, we always initialize the
852 : * scope chain when pushing frames in the VM, and only initialize it when
853 : * pushing frames in JIT code when the above situation applies.
854 : *
855 : * NB: 'fp->hasCallObj()' implies that fp->callObj() needs to be 'put' when
856 : * the frame is popped. Since the scope chain of a non-strict eval frame
857 : * contains the call object of the parent (function) frame, it is possible
858 : * to have:
859 : * !fp->hasCall() && fp->scopeChain().isCall()
860 : */
861 :
862 : inline JSObject &scopeChain() const;
863 :
864 27174308 : bool hasCallObj() const {
865 27174308 : bool ret = !!(flags_ & HAS_CALL_OBJ);
866 27174308 : JS_ASSERT_IF(ret, !isNonStrictEvalFrame());
867 27174308 : return ret;
868 : }
869 :
870 : inline CallObject &callObj() const;
871 : inline void setScopeChainNoCallObj(JSObject &obj);
872 : inline void setScopeChainWithOwnCallObj(CallObject &obj);
873 :
874 : /* Block chain */
875 :
876 33687400 : bool hasBlockChain() const {
877 33687400 : return (flags_ & HAS_BLOCKCHAIN) && blockChain_;
878 : }
879 :
880 4159929 : StaticBlockObject *maybeBlockChain() {
881 4159929 : return (flags_ & HAS_BLOCKCHAIN) ? blockChain_ : NULL;
882 : }
883 :
884 59912 : StaticBlockObject &blockChain() const {
885 59912 : JS_ASSERT(hasBlockChain());
886 59912 : return *blockChain_;
887 : }
888 :
889 3412026 : void setBlockChain(StaticBlockObject *obj) {
890 3412026 : flags_ |= HAS_BLOCKCHAIN;
891 3412026 : blockChain_ = obj;
892 3412026 : }
893 :
894 : /*
895 : * Prologue for function frames: make a call object for heavyweight
896 : * functions, and maintain type nesting invariants.
897 : */
898 : inline bool functionPrologue(JSContext *cx);
899 :
900 : /*
901 : * Epilogue for function frames: put any args or call object for the frame
902 : * which may still be live, and maintain type nesting invariants. Note:
903 : * this does mark the epilogue as having been completed, since the frame is
904 : * about to be popped. Use updateEpilogueFlags for this.
905 : */
906 : inline void functionEpilogue();
907 :
908 : /*
909 : * If callObj() or argsObj() have already been put, update our flags
910 : * accordingly. This call must be followed by a later functionEpilogue.
911 : */
912 : inline void updateEpilogueFlags();
913 :
914 : inline bool maintainNestingState() const;
915 :
916 : /*
917 : * Variables object
918 : *
919 : * Given that a (non-dummy) StackFrame corresponds roughly to a ES5
920 : * Execution Context (ES5 10.3), StackFrame::varObj corresponds to the
921 : * VariableEnvironment component of a Exection Context. Intuitively, the
922 : * variables object is where new bindings (variables and functions) are
923 : * stored. One might expect that this is either the callObj or
924 : * scopeChain.globalObj for function or global code, respectively, however
925 : * the JSAPI allows calls of Execute to specify a variables object on the
926 : * scope chain other than the call/global object. This allows embeddings to
927 : * run multiple scripts under the same global, each time using a new
928 : * variables object to collect and discard the script's global variables.
929 : */
930 :
931 : inline JSObject &varObj();
932 :
933 : /*
934 : * Frame compartment
935 : *
936 : * A stack frame's compartment is the frame's containing context's
937 : * compartment when the frame was pushed.
938 : */
939 :
940 : inline JSCompartment *compartment() const;
941 :
942 : /* Annotation (will be removed after bug 546848) */
943 :
944 21969678 : void* annotation() const {
945 21969678 : return (flags_ & HAS_ANNOTATION) ? annotation_ : NULL;
946 : }
947 :
948 0 : void setAnnotation(void *annot) {
949 0 : flags_ |= HAS_ANNOTATION;
950 0 : annotation_ = annot;
951 0 : }
952 :
953 : /* JIT rejoin state */
954 :
955 44126 : JSRejoinState rejoin() const {
956 44126 : return rejoin_;
957 : }
958 :
959 116822 : void setRejoin(JSRejoinState state) {
960 116822 : rejoin_ = state;
961 116822 : }
962 :
963 : /* Down frame expansion state */
964 :
965 2051214 : void setDownFramesExpanded() {
966 2051214 : flags_ |= DOWN_FRAMES_EXPANDED;
967 2051214 : }
968 :
969 35800333 : bool downFramesExpanded() {
970 35800333 : return !!(flags_ & DOWN_FRAMES_EXPANDED);
971 : }
972 :
973 : /* Debugger hook data */
974 :
975 34267816 : bool hasHookData() const {
976 34267816 : return !!(flags_ & HAS_HOOK_DATA);
977 : }
978 :
979 : void* hookData() const {
980 : JS_ASSERT(hasHookData());
981 : return hookData_;
982 : }
983 :
984 12394644 : void* maybeHookData() const {
985 12394644 : return hasHookData() ? hookData_ : NULL;
986 : }
987 :
988 38 : void setHookData(void *v) {
989 38 : hookData_ = v;
990 38 : flags_ |= HAS_HOOK_DATA;
991 38 : }
992 :
993 : /* Return value */
994 :
995 27325 : bool hasReturnValue() const {
996 27325 : return !!(flags_ & HAS_RVAL);
997 : }
998 :
999 14319302 : Value &returnValue() {
1000 14319302 : if (!(flags_ & HAS_RVAL))
1001 6122866 : rval_.setUndefined();
1002 14319302 : return rval_;
1003 : }
1004 :
1005 8118392 : void markReturnValue() {
1006 8118392 : flags_ |= HAS_RVAL;
1007 8118392 : }
1008 :
1009 6985273 : void setReturnValue(const Value &v) {
1010 6985273 : rval_ = v;
1011 6985273 : markReturnValue();
1012 6985273 : }
1013 :
1014 5129 : void clearReturnValue() {
1015 5129 : rval_.setUndefined();
1016 5129 : markReturnValue();
1017 5129 : }
1018 :
1019 : /* Native-code return address */
1020 :
1021 935060 : void *nativeReturnAddress() const {
1022 935060 : return ncode_;
1023 : }
1024 :
1025 1244986 : void setNativeReturnAddress(void *addr) {
1026 1244986 : ncode_ = addr;
1027 1244986 : }
1028 :
1029 71077 : void **addressOfNativeReturnAddress() {
1030 71077 : return &ncode_;
1031 : }
1032 :
1033 : /*
1034 : * Generator-specific members
1035 : *
1036 : * A non-eval function frame may optionally be the activation of a
1037 : * generator. For the most part, generator frames act like ordinary frames.
1038 : * For exceptions, see js_FloatingFrameIfGenerator.
1039 : */
1040 :
1041 48570551 : bool isGeneratorFrame() const {
1042 48570551 : return !!(flags_ & GENERATOR);
1043 : }
1044 :
1045 154538 : bool isFloatingGenerator() const {
1046 154538 : JS_ASSERT_IF(flags_ & FLOATING_GENERATOR, isGeneratorFrame());
1047 154538 : return !!(flags_ & FLOATING_GENERATOR);
1048 : }
1049 :
1050 8222 : void initFloatingGenerator() {
1051 8222 : JS_ASSERT(!(flags_ & GENERATOR));
1052 8222 : flags_ |= (GENERATOR | FLOATING_GENERATOR);
1053 8222 : }
1054 :
1055 19103 : void unsetFloatingGenerator() {
1056 19103 : flags_ &= ~FLOATING_GENERATOR;
1057 19103 : }
1058 :
1059 19103 : void setFloatingGenerator() {
1060 19103 : flags_ |= FLOATING_GENERATOR;
1061 19103 : }
1062 :
1063 : /*
1064 : * js::Execute pushes both global and function frames (since eval() in a
1065 : * function pushes a frame with isFunctionFrame() && isEvalFrame()). Most
1066 : * code should not care where a frame was pushed, but if it is necessary to
1067 : * pick out frames pushed by js::Execute, this is the right query:
1068 : */
1069 :
1070 12431599 : bool isFramePushedByExecute() const {
1071 12431599 : return !!(flags_ & (GLOBAL | EVAL));
1072 : }
1073 :
1074 : /*
1075 : * Other flags
1076 : */
1077 :
1078 938452 : InitialFrameFlags initialFlags() const {
1079 : JS_STATIC_ASSERT((int)INITIAL_NONE == 0);
1080 : JS_STATIC_ASSERT((int)INITIAL_CONSTRUCT == (int)CONSTRUCTING);
1081 : JS_STATIC_ASSERT((int)INITIAL_LOWERED == (int)LOWERED_CALL_APPLY);
1082 938452 : uint32_t mask = CONSTRUCTING | LOWERED_CALL_APPLY;
1083 938452 : JS_ASSERT((flags_ & mask) != mask);
1084 938452 : return InitialFrameFlags(flags_ & mask);
1085 : }
1086 :
1087 52024307 : bool isConstructing() const {
1088 52024307 : return !!(flags_ & CONSTRUCTING);
1089 : }
1090 :
1091 : /*
1092 : * The method JIT call/apply optimization can erase Function.{call,apply}
1093 : * invocations from the stack and push the callee frame directly. The base
1094 : * of these frames will be offset by one value, however, which the
1095 : * interpreter needs to account for if it ends up popping the frame.
1096 : */
1097 10093872 : bool loweredCallOrApply() const {
1098 10093872 : return !!(flags_ & LOWERED_CALL_APPLY);
1099 : }
1100 :
1101 0 : bool isDebuggerFrame() const {
1102 0 : return !!(flags_ & DEBUGGER);
1103 : }
1104 :
1105 : bool hasOverflowArgs() const {
1106 : return !!(flags_ & OVERFLOW_ARGS);
1107 : }
1108 :
1109 536172 : bool isYielding() {
1110 536172 : return !!(flags_ & YIELDING);
1111 : }
1112 :
1113 15426 : void setYielding() {
1114 15426 : flags_ |= YIELDING;
1115 15426 : }
1116 :
1117 15426 : void clearYielding() {
1118 15426 : flags_ &= ~YIELDING;
1119 15426 : }
1120 :
1121 517775 : void setFinishedInInterpreter() {
1122 517775 : flags_ |= FINISHED_IN_INTERP;
1123 517775 : }
1124 :
1125 1288618 : bool finishedInInterpreter() const {
1126 1288618 : return !!(flags_ & FINISHED_IN_INTERP);
1127 : }
1128 :
1129 : #ifdef DEBUG
1130 : /* Poison scopeChain value set before a frame is flushed. */
1131 : static JSObject *const sInvalidScopeChain;
1132 : #endif
1133 :
1134 : public:
1135 : /* Public, but only for JIT use: */
1136 :
1137 300447 : static size_t offsetOfFlags() {
1138 300447 : return offsetof(StackFrame, flags_);
1139 : }
1140 :
1141 123219 : static size_t offsetOfExec() {
1142 123219 : return offsetof(StackFrame, exec);
1143 : }
1144 :
1145 5267 : static size_t offsetOfNumActual() {
1146 5267 : return offsetof(StackFrame, u.nactual);
1147 : }
1148 :
1149 42875 : static size_t offsetOfScopeChain() {
1150 42875 : return offsetof(StackFrame, scopeChain_);
1151 : }
1152 :
1153 266055 : static size_t offsetOfPrev() {
1154 266055 : return offsetof(StackFrame, prev_);
1155 : }
1156 :
1157 118793 : static size_t offsetOfReturnValue() {
1158 118793 : return offsetof(StackFrame, rval_);
1159 : }
1160 :
1161 : static size_t offsetOfArgsObj() {
1162 : return offsetof(StackFrame, argsObj_);
1163 : }
1164 :
1165 418527 : static ptrdiff_t offsetOfNcode() {
1166 418527 : return offsetof(StackFrame, ncode_);
1167 : }
1168 :
1169 35158 : static ptrdiff_t offsetOfCallee(JSFunction *fun) {
1170 35158 : JS_ASSERT(fun != NULL);
1171 35158 : return -(fun->nargs + 2) * sizeof(Value);
1172 : }
1173 :
1174 161307 : static ptrdiff_t offsetOfThis(JSFunction *fun) {
1175 : return fun == NULL
1176 : ? -1 * ptrdiff_t(sizeof(Value))
1177 161307 : : -(fun->nargs + 1) * ptrdiff_t(sizeof(Value));
1178 : }
1179 :
1180 379363 : static ptrdiff_t offsetOfFormalArg(JSFunction *fun, unsigned i) {
1181 379363 : JS_ASSERT(i < fun->nargs);
1182 379363 : return (-(int)fun->nargs + i) * sizeof(Value);
1183 : }
1184 :
1185 13481624 : static size_t offsetOfFixed(unsigned i) {
1186 13481624 : return sizeof(StackFrame) + i * sizeof(Value);
1187 : }
1188 :
1189 : #ifdef JS_METHODJIT
1190 651006 : mjit::JITScript *jit() {
1191 651006 : return script()->getJIT(isConstructing());
1192 : }
1193 : #endif
1194 :
1195 : void methodjitStaticAsserts();
1196 :
1197 : public:
1198 : void mark(JSTracer *trc);
1199 : };
1200 :
1201 : static const size_t VALUES_PER_STACK_FRAME = sizeof(StackFrame) / sizeof(Value);
1202 :
1203 : static inline unsigned
1204 478 : ToReportFlags(InitialFrameFlags initial)
1205 : {
1206 478 : return unsigned(initial & StackFrame::CONSTRUCTING);
1207 : }
1208 :
1209 : static inline StackFrame::Flags
1210 22808333 : ToFrameFlags(InitialFrameFlags initial)
1211 : {
1212 22808333 : return StackFrame::Flags(initial);
1213 : }
1214 :
1215 : static inline InitialFrameFlags
1216 : InitialFrameFlagsFromConstructing(bool b)
1217 : {
1218 : return b ? INITIAL_CONSTRUCT : INITIAL_NONE;
1219 : }
1220 :
1221 : static inline bool
1222 11198564 : InitialFrameFlagsAreConstructing(InitialFrameFlags initial)
1223 : {
1224 11198564 : return !!(initial & INITIAL_CONSTRUCT);
1225 : }
1226 :
1227 : static inline bool
1228 3391 : InitialFrameFlagsAreLowered(InitialFrameFlags initial)
1229 : {
1230 3391 : return !!(initial & INITIAL_LOWERED);
1231 : }
1232 :
1233 6934 : inline StackFrame * Valueify(JSStackFrame *fp) { return (StackFrame *)fp; }
1234 5962 : static inline JSStackFrame * Jsvalify(StackFrame *fp) { return (JSStackFrame *)fp; }
1235 :
1236 : /*****************************************************************************/
1237 :
1238 : class FrameRegs
1239 : {
1240 : public:
1241 : Value *sp;
1242 : jsbytecode *pc;
1243 : private:
1244 : JSInlinedSite *inlined_;
1245 : StackFrame *fp_;
1246 : public:
1247 -1765378763 : StackFrame *fp() const { return fp_; }
1248 122156754 : JSInlinedSite *inlined() const { return inlined_; }
1249 :
1250 : /* For jit use (need constant): */
1251 : static const size_t offsetOfFp = 3 * sizeof(void *);
1252 : static const size_t offsetOfInlined = 2 * sizeof(void *);
1253 : static void staticAssert() {
1254 : JS_STATIC_ASSERT(offsetOfFp == offsetof(FrameRegs, fp_));
1255 : JS_STATIC_ASSERT(offsetOfInlined == offsetof(FrameRegs, inlined_));
1256 : }
1257 1189444 : void clearInlined() { inlined_ = NULL; }
1258 :
1259 : /* For generator: */
1260 46428 : void rebaseFromTo(const FrameRegs &from, StackFrame &to) {
1261 46428 : fp_ = &to;
1262 46428 : sp = to.slots() + (from.sp - from.fp_->slots());
1263 46428 : pc = from.pc;
1264 46428 : inlined_ = from.inlined_;
1265 46428 : JS_ASSERT(fp_);
1266 46428 : }
1267 :
1268 : /* For ContextStack: */
1269 22544625 : void popFrame(Value *newsp) {
1270 22544625 : pc = fp_->prevpc(&inlined_);
1271 22544625 : sp = newsp;
1272 22544625 : fp_ = fp_->prev();
1273 22544625 : JS_ASSERT(fp_);
1274 22544625 : }
1275 :
1276 : /* For FixupArity: */
1277 938452 : void popPartialFrame(Value *newsp) {
1278 938452 : sp = newsp;
1279 938452 : fp_ = fp_->prev();
1280 938452 : JS_ASSERT(fp_);
1281 938452 : }
1282 :
1283 : /* For InternalInterpret: */
1284 869 : void restorePartialFrame(Value *newfp) {
1285 869 : fp_ = (StackFrame *) newfp;
1286 869 : }
1287 :
1288 : /* For stubs::CompileFunction, ContextStack: */
1289 22025819 : void prepareToRun(StackFrame &fp, JSScript *script) {
1290 22025819 : pc = script->code;
1291 22025819 : sp = fp.slots() + script->nfixed;
1292 22025819 : fp_ = &fp;
1293 22025819 : inlined_ = NULL;
1294 22025819 : }
1295 :
1296 : /* For pushDummyFrame: */
1297 210004 : void initDummyFrame(StackFrame &fp) {
1298 210004 : pc = NULL;
1299 210004 : sp = fp.slots();
1300 210004 : fp_ = &fp;
1301 210004 : inlined_ = NULL;
1302 210004 : }
1303 :
1304 : /* For expandInlineFrames: */
1305 74 : void expandInline(StackFrame *innerfp, jsbytecode *innerpc) {
1306 74 : pc = innerpc;
1307 74 : fp_ = innerfp;
1308 74 : inlined_ = NULL;
1309 74 : }
1310 :
1311 : #ifdef JS_METHODJIT
1312 : /* For LimitCheck: */
1313 12 : void updateForNcode(mjit::JITScript *jit, void *ncode) {
1314 12 : pc = mjit::NativeToPC(jit, ncode, &inlined_);
1315 12 : }
1316 : #endif
1317 : };
1318 :
1319 : /*****************************************************************************/
1320 :
1321 : class StackSegment
1322 : {
1323 : /* Previous segment within same context stack. */
1324 : StackSegment *const prevInContext_;
1325 :
1326 : /* Previous segment sequentially in memory. */
1327 : StackSegment *const prevInMemory_;
1328 :
1329 : /* Execution registers for most recent script in this segment (or null). */
1330 : FrameRegs *regs_;
1331 :
1332 : /* Call args for most recent native call in this segment (or null). */
1333 : CallArgsList *calls_;
1334 :
1335 : public:
1336 78789 : StackSegment(StackSegment *prevInContext,
1337 : StackSegment *prevInMemory,
1338 : FrameRegs *regs,
1339 : CallArgsList *calls)
1340 : : prevInContext_(prevInContext),
1341 : prevInMemory_(prevInMemory),
1342 : regs_(regs),
1343 78789 : calls_(calls)
1344 78789 : {}
1345 :
1346 : /* A segment is followed in memory by the arguments of the first call. */
1347 :
1348 148409295 : Value *slotsBegin() const {
1349 148409295 : return (Value *)(this + 1);
1350 : }
1351 :
1352 : /* Accessors. */
1353 :
1354 54890171 : FrameRegs ®s() const {
1355 54890171 : JS_ASSERT(regs_);
1356 54890171 : return *regs_;
1357 : }
1358 :
1359 -1288504883 : FrameRegs *maybeRegs() const {
1360 -1288504883 : return regs_;
1361 : }
1362 :
1363 1034592360 : StackFrame *fp() const {
1364 1034592360 : return regs_->fp();
1365 : }
1366 :
1367 73672193 : StackFrame *maybefp() const {
1368 73672193 : return regs_ ? regs_->fp() : NULL;
1369 : }
1370 :
1371 22851 : jsbytecode *maybepc() const {
1372 22851 : return regs_ ? regs_->pc : NULL;
1373 : }
1374 :
1375 2142483 : CallArgsList &calls() const {
1376 2142483 : JS_ASSERT(calls_);
1377 2142483 : return *calls_;
1378 : }
1379 :
1380 523476 : CallArgsList *maybeCalls() const {
1381 523476 : return calls_;
1382 : }
1383 :
1384 : Value *callArgv() const {
1385 : return calls_->array();
1386 : }
1387 :
1388 : Value *maybeCallArgv() const {
1389 : return calls_ ? calls_->array() : NULL;
1390 : }
1391 :
1392 80067 : StackSegment *prevInContext() const {
1393 80067 : return prevInContext_;
1394 : }
1395 :
1396 106110 : StackSegment *prevInMemory() const {
1397 106110 : return prevInMemory_;
1398 : }
1399 :
1400 25804200 : void repointRegs(FrameRegs *regs) {
1401 25804200 : JS_ASSERT_IF(regs, regs->fp());
1402 25804200 : regs_ = regs;
1403 25804200 : }
1404 :
1405 290 : bool isEmpty() const {
1406 290 : return !calls_ && !regs_;
1407 : }
1408 :
1409 : bool contains(const StackFrame *fp) const;
1410 : bool contains(const FrameRegs *regs) const;
1411 : bool contains(const CallArgsList *call) const;
1412 :
1413 : StackFrame *computeNextFrame(const StackFrame *fp) const;
1414 :
1415 : Value *end() const;
1416 :
1417 : FrameRegs *pushRegs(FrameRegs ®s);
1418 : void popRegs(FrameRegs *regs);
1419 : void pushCall(CallArgsList &callList);
1420 : void pointAtCall(CallArgsList &callList);
1421 : void popCall();
1422 :
1423 : /* For jit access: */
1424 :
1425 : static const size_t offsetOfRegs() { return offsetof(StackSegment, regs_); }
1426 : };
1427 :
1428 : static const size_t VALUES_PER_STACK_SEGMENT = sizeof(StackSegment) / sizeof(Value);
1429 : JS_STATIC_ASSERT(sizeof(StackSegment) % sizeof(Value) == 0);
1430 :
1431 : /*****************************************************************************/
1432 :
1433 : class StackSpace
1434 : {
1435 : StackSegment *seg_;
1436 : Value *base_;
1437 : mutable Value *conservativeEnd_;
1438 : #ifdef XP_WIN
1439 : mutable Value *commitEnd_;
1440 : #endif
1441 : Value *defaultEnd_;
1442 : Value *trustedEnd_;
1443 :
1444 26578443 : void assertInvariants() const {
1445 26578443 : JS_ASSERT(base_ <= conservativeEnd_);
1446 : #ifdef XP_WIN
1447 : JS_ASSERT(conservativeEnd_ <= commitEnd_);
1448 : JS_ASSERT(commitEnd_ <= trustedEnd_);
1449 : #endif
1450 26578443 : JS_ASSERT(conservativeEnd_ <= defaultEnd_);
1451 26578443 : JS_ASSERT(defaultEnd_ <= trustedEnd_);
1452 26578443 : }
1453 :
1454 : /* The total number of values/bytes reserved for the stack. */
1455 : static const size_t CAPACITY_VALS = 512 * 1024;
1456 : static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(Value);
1457 :
1458 : /* How much of the stack is initially committed. */
1459 : static const size_t COMMIT_VALS = 16 * 1024;
1460 : static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value);
1461 :
1462 : /* How much space is reserved at the top of the stack for trusted JS. */
1463 : static const size_t BUFFER_VALS = 16 * 1024;
1464 : static const size_t BUFFER_BYTES = BUFFER_VALS * sizeof(Value);
1465 :
1466 : static void staticAsserts() {
1467 : JS_STATIC_ASSERT(CAPACITY_VALS % COMMIT_VALS == 0);
1468 : }
1469 :
1470 : friend class AllFramesIter;
1471 : friend class ContextStack;
1472 : friend class StackFrame;
1473 :
1474 : /*
1475 : * Except when changing compartment (see pushDummyFrame), the 'dest'
1476 : * parameter of ensureSpace is cx->compartment. Ideally, we'd just pass
1477 : * this directly (and introduce a helper that supplies cx->compartment when
1478 : * no 'dest' is given). For some compilers, this really hurts performance,
1479 : * so, instead, a trivially sinkable magic constant is used to indicate
1480 : * that dest should be cx->compartment.
1481 : */
1482 : static const size_t CX_COMPARTMENT = 0xc;
1483 :
1484 : inline bool ensureSpace(JSContext *cx, MaybeReportError report,
1485 : Value *from, ptrdiff_t nvals,
1486 : JSCompartment *dest = (JSCompartment *)CX_COMPARTMENT) const;
1487 : JS_FRIEND_API(bool) ensureSpaceSlow(JSContext *cx, MaybeReportError report,
1488 : Value *from, ptrdiff_t nvals,
1489 : JSCompartment *dest) const;
1490 :
1491 : StackSegment &findContainingSegment(const StackFrame *target) const;
1492 :
1493 : public:
1494 : StackSpace();
1495 : bool init();
1496 : ~StackSpace();
1497 :
1498 : /*
1499 : * Maximum supported value of arguments.length. This bounds the maximum
1500 : * number of arguments that can be supplied to Function.prototype.apply.
1501 : * This value also bounds the number of elements parsed in an array
1502 : * initialiser.
1503 : *
1504 : * Since arguments are copied onto the stack, the stack size is the
1505 : * limiting factor for this constant. Use the max stack size (available to
1506 : * untrusted code) with an extra buffer so that, after such an apply, the
1507 : * callee can do a little work without OOMing.
1508 : */
1509 : static const unsigned ARGS_LENGTH_MAX = CAPACITY_VALS - (2 * BUFFER_VALS);
1510 :
1511 : /* See stack layout comment in Stack.h. */
1512 61072169 : inline Value *firstUnused() const { return seg_ ? seg_->end() : base_; }
1513 :
1514 : StackSegment &containingSegment(const StackFrame *target) const;
1515 :
1516 : /*
1517 : * Extra space to reserve on the stack for method JIT frames, beyond the
1518 : * frame's nslots. This may be used for inlined stack frames, slots storing
1519 : * loop invariant code, or to reserve space for pushed callee frames. Note
1520 : * that this space should be reserved when pushing interpreter frames as
1521 : * well, so that we don't need to check the stack when entering the method
1522 : * JIT at loop heads or safe points.
1523 : */
1524 : static const size_t STACK_JIT_EXTRA = (/*~VALUES_PER_STACK_FRAME*/ 8 + 18) * 10;
1525 :
1526 : /*
1527 : * Return a limit against which jit code can check for. This limit is not
1528 : * necessarily the end of the stack since we lazily commit stack memory on
1529 : * some platforms. Thus, when the stack limit is exceeded, the caller should
1530 : * use tryBumpLimit to attempt to increase the stack limit by committing
1531 : * more memory. If the stack is truly exhausted, tryBumpLimit will report an
1532 : * error and return NULL.
1533 : *
1534 : * An invariant of the methodjit is that there is always space to push a
1535 : * frame on top of the current frame's expression stack (which can be at
1536 : * most script->nslots deep). getStackLimit ensures that the returned limit
1537 : * does indeed have this required space and reports an error and returns
1538 : * NULL if this reserve space cannot be allocated.
1539 : */
1540 : inline Value *getStackLimit(JSContext *cx, MaybeReportError report);
1541 : bool tryBumpLimit(JSContext *cx, Value *from, unsigned nvals, Value **limit);
1542 :
1543 : /* Called during GC: mark segments, frames, and slots under firstUnused. */
1544 : void mark(JSTracer *trc);
1545 : void markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc);
1546 :
1547 : /* Called during GC: sets active flag on compartments with active frames. */
1548 : void markActiveCompartments();
1549 :
1550 : /* We only report the committed size; uncommitted size is uninteresting. */
1551 : JS_FRIEND_API(size_t) sizeOfCommitted();
1552 : };
1553 :
1554 : /*****************************************************************************/
1555 :
1556 : class ContextStack
1557 : {
1558 : StackSegment *seg_;
1559 : StackSpace *const space_;
1560 : JSContext *cx_;
1561 :
1562 : /*
1563 : * Return whether this ContextStack is at the top of the contiguous stack.
1564 : * This is a precondition for extending the current segment by pushing
1565 : * stack frames or overrides etc.
1566 : *
1567 : * NB: Just because a stack is onTop() doesn't mean there is necessarily
1568 : * a frame pushed on the stack. For this, use hasfp().
1569 : */
1570 : bool onTop() const;
1571 :
1572 : #ifdef DEBUG
1573 : void assertSpaceInSync() const;
1574 : #else
1575 : void assertSpaceInSync() const {}
1576 : #endif
1577 :
1578 : /* Implementation details of push* public interface. */
1579 : StackSegment *pushSegment(JSContext *cx);
1580 : enum MaybeExtend { CAN_EXTEND = true, CANT_EXTEND = false };
1581 : Value *ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars,
1582 : MaybeExtend extend, bool *pushedSeg,
1583 : JSCompartment *dest = (JSCompartment *)StackSpace::CX_COMPARTMENT);
1584 :
1585 : inline StackFrame *
1586 : getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
1587 : JSFunction *fun, JSScript *script, StackFrame::Flags *pflags) const;
1588 :
1589 : /* Make pop* functions private since only called by guard classes. */
1590 : void popSegment();
1591 : friend class InvokeArgsGuard;
1592 : void popInvokeArgs(const InvokeArgsGuard &iag);
1593 : friend class FrameGuard;
1594 : void popFrame(const FrameGuard &fg);
1595 : friend class GeneratorFrameGuard;
1596 : void popGeneratorFrame(const GeneratorFrameGuard &gfg);
1597 :
1598 : friend class StackIter;
1599 :
1600 : public:
1601 : ContextStack(JSContext *cx);
1602 : ~ContextStack();
1603 :
1604 : /*** Stack accessors ***/
1605 :
1606 : /*
1607 : * A context's stack is "empty" if there are no scripts or natives
1608 : * executing. Note that JS_SaveFrameChain does not factor into this definition.
1609 : */
1610 75845 : bool empty() const { return !seg_; }
1611 :
1612 : /*
1613 : * Return whether there has been at least one frame pushed since the most
1614 : * recent call to JS_SaveFrameChain. Note that natives do not have frames
1615 : * and dummy frames are frames that do not represent script execution hence
1616 : * this query has little semantic meaning past "you can call fp()".
1617 : */
1618 -1350842085 : inline bool hasfp() const { return seg_ && seg_->maybeRegs(); }
1619 :
1620 : /*
1621 : * Return the most recent script activation's registers with the same
1622 : * caveat as hasfp regarding JS_SaveFrameChain.
1623 : */
1624 63915706 : inline FrameRegs *maybeRegs() const { return seg_ ? seg_->maybeRegs() : NULL; }
1625 630099 : inline StackFrame *maybefp() const { return seg_ ? seg_->maybefp() : NULL; }
1626 :
1627 : /* Faster alternatives to maybe* functions. */
1628 37992864 : inline FrameRegs ®s() const { JS_ASSERT(hasfp()); return seg_->regs(); }
1629 1034589721 : inline StackFrame *fp() const { JS_ASSERT(hasfp()); return seg_->fp(); }
1630 :
1631 : /* The StackSpace currently hosting this ContextStack. */
1632 117718558 : StackSpace &space() const { return *space_; }
1633 :
1634 : /* Return whether the given frame is in this context's stack. */
1635 : bool containsSlow(const StackFrame *target) const;
1636 :
1637 : /*** Stack manipulation ***/
1638 :
1639 : /*
1640 : * pushInvokeArgs allocates |argc + 2| rooted values that will be passed as
1641 : * the arguments to Invoke. A single allocation can be used for multiple
1642 : * Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
1643 : * an immediately-enclosing (stack-wise) call to pushInvokeArgs.
1644 : */
1645 : bool pushInvokeArgs(JSContext *cx, unsigned argc, InvokeArgsGuard *ag);
1646 :
1647 : /* Called by Invoke for a scripted function call. */
1648 : bool pushInvokeFrame(JSContext *cx, const CallArgs &args,
1649 : InitialFrameFlags initial, InvokeFrameGuard *ifg);
1650 :
1651 : /* Called by Execute for execution of eval or global code. */
1652 : bool pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thisv,
1653 : JSObject &scopeChain, ExecuteType type,
1654 : StackFrame *evalInFrame, ExecuteFrameGuard *efg);
1655 :
1656 : /*
1657 : * Called by SendToGenerator to resume a yielded generator. In addition to
1658 : * pushing a frame onto the VM stack, this function copies over the
1659 : * floating frame stored in 'gen'. When 'gfg' is destroyed, the destructor
1660 : * will copy the frame back to the floating frame.
1661 : */
1662 : bool pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg);
1663 :
1664 : /*
1665 : * When changing the compartment of a cx, it is necessary to immediately
1666 : * change the scope chain to a global in the right compartment since any
1667 : * amount of general VM code can run before the first scripted frame is
1668 : * pushed (if at all). This is currently and hackily accomplished by
1669 : * pushing a "dummy frame" with the correct scope chain. On success, this
1670 : * function will change the compartment to 'scopeChain.compartment()' and
1671 : * push a dummy frame for 'scopeChain'. On failure, nothing is changed.
1672 : */
1673 : bool pushDummyFrame(JSContext *cx, JSCompartment *dest, JSObject &scopeChain, DummyFrameGuard *dfg);
1674 :
1675 : /*
1676 : * An "inline frame" may only be pushed from within the top, active
1677 : * segment. This is the case for calls made inside mjit code and Interpret.
1678 : * The 'stackLimit' overload updates 'stackLimit' if it changes.
1679 : */
1680 : bool pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
1681 : JSFunction &callee, JSScript *script,
1682 : InitialFrameFlags initial);
1683 : bool pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
1684 : JSFunction &callee, JSScript *script,
1685 : InitialFrameFlags initial, Value **stackLimit);
1686 : void popInlineFrame(FrameRegs ®s);
1687 :
1688 : /* Pop a partially-pushed frame after hitting the limit before throwing. */
1689 : void popFrameAfterOverflow();
1690 :
1691 : /* Get the topmost script and optional pc on the stack. */
1692 : inline JSScript *currentScript(jsbytecode **pc = NULL) const;
1693 : inline JSScript *currentScriptWithDiagnostics(jsbytecode **pc = NULL) const;
1694 :
1695 : /* Get the scope chain for the topmost scripted call on the stack. */
1696 : inline JSObject *currentScriptedScopeChain() const;
1697 :
1698 : /*
1699 : * Called by the methodjit for an arity mismatch. Arity mismatch can be
1700 : * hot, so getFixupFrame avoids doing call setup performed by jit code when
1701 : * FixupArity returns.
1702 : */
1703 : StackFrame *getFixupFrame(JSContext *cx, MaybeReportError report,
1704 : const CallArgs &args, JSFunction *fun, JSScript *script,
1705 : void *ncode, InitialFrameFlags initial, Value **stackLimit);
1706 :
1707 : bool saveFrameChain();
1708 : void restoreFrameChain();
1709 :
1710 : /*
1711 : * As an optimization, the interpreter/mjit can operate on a local
1712 : * FrameRegs instance repoint the ContextStack to this local instance.
1713 : */
1714 25804200 : inline void repointRegs(FrameRegs *regs) { JS_ASSERT(hasfp()); seg_->repointRegs(regs); }
1715 :
1716 : /*** For JSContext: ***/
1717 :
1718 : /*
1719 : * To avoid indirection, ContextSpace caches a pointer to the StackSpace.
1720 : * This must be kept coherent with cx->thread->data.space by calling
1721 : * 'threadReset' whenver cx->thread changes.
1722 : */
1723 : void threadReset();
1724 :
1725 : /*** For jit compiler: ***/
1726 :
1727 : static size_t offsetOfSeg() { return offsetof(ContextStack, seg_); }
1728 : };
1729 :
1730 : /*****************************************************************************/
1731 :
1732 : class InvokeArgsGuard : public CallArgsList
1733 : {
1734 : friend class ContextStack;
1735 : ContextStack *stack_;
1736 : bool pushedSeg_;
1737 2142483 : void setPushed(ContextStack &stack) { JS_ASSERT(!pushed()); stack_ = &stack; }
1738 : public:
1739 2507014 : InvokeArgsGuard() : CallArgsList(), stack_(NULL), pushedSeg_(false) {}
1740 2507014 : ~InvokeArgsGuard() { if (pushed()) stack_->popInvokeArgs(*this); }
1741 7099665 : bool pushed() const { return !!stack_; }
1742 909 : void pop() { stack_->popInvokeArgs(*this); stack_ = NULL; }
1743 : };
1744 :
1745 : class FrameGuard
1746 : {
1747 : protected:
1748 : friend class ContextStack;
1749 : ContextStack *stack_;
1750 : bool pushedSeg_;
1751 : FrameRegs regs_;
1752 : FrameRegs *prevRegs_;
1753 1757483 : void setPushed(ContextStack &stack) { stack_ = &stack; }
1754 : public:
1755 1757511 : FrameGuard() : stack_(NULL), pushedSeg_(false) {}
1756 1757511 : ~FrameGuard() { if (pushed()) stack_->popFrame(*this); }
1757 3553200 : bool pushed() const { return !!stack_; }
1758 : void pop() { stack_->popFrame(*this); stack_ = NULL; }
1759 :
1760 1547479 : StackFrame *fp() const { return regs_.fp(); }
1761 : };
1762 :
1763 : class InvokeFrameGuard : public FrameGuard
1764 2751514 : {};
1765 :
1766 : class ExecuteFrameGuard : public FrameGuard
1767 305294 : {};
1768 :
1769 : class DummyFrameGuard : public FrameGuard
1770 420008 : {};
1771 :
1772 : class GeneratorFrameGuard : public FrameGuard
1773 19103 : {
1774 : friend class ContextStack;
1775 : JSGenerator *gen_;
1776 : Value *stackvp_;
1777 : public:
1778 19103 : ~GeneratorFrameGuard() { if (pushed()) stack_->popGeneratorFrame(*this); }
1779 : };
1780 :
1781 : /*****************************************************************************/
1782 :
1783 : /*
1784 : * Iterate through the callstack of the given context. Each element of said
1785 : * callstack can either be the execution of a script (scripted function call,
1786 : * global code, eval code, debugger code) or the invocation of a (C++) native.
1787 : * Example usage:
1788 : *
1789 : * for (Stackiter i(cx); !i.done(); ++i) {
1790 : * if (i.isScript()) {
1791 : * ... i.fp() ... i.sp() ... i.pc()
1792 : * } else {
1793 : * JS_ASSERT(i.isNativeCall());
1794 : * ... i.args();
1795 : * }
1796 : * }
1797 : *
1798 : * The SavedOption parameter additionally lets the iterator continue through
1799 : * breaks in the callstack (from JS_SaveFrameChain). The default is to stop.
1800 : */
1801 : class StackIter
1802 : {
1803 : friend class ContextStack;
1804 : JSContext *cx_;
1805 : public:
1806 : enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
1807 : private:
1808 : SavedOption savedOption_;
1809 :
1810 : enum State { DONE, SCRIPTED, NATIVE, IMPLICIT_NATIVE };
1811 : State state_;
1812 :
1813 : StackFrame *fp_;
1814 : CallArgsList *calls_;
1815 :
1816 : StackSegment *seg_;
1817 : Value *sp_;
1818 : jsbytecode *pc_;
1819 : JSScript *script_;
1820 : CallArgs args_;
1821 :
1822 : void poisonRegs();
1823 : void popFrame();
1824 : void popCall();
1825 : void settleOnNewSegment();
1826 : void settleOnNewState();
1827 : void startOnSegment(StackSegment *seg);
1828 :
1829 : public:
1830 : StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
1831 :
1832 53156292 : bool done() const { return state_ == DONE; }
1833 : StackIter &operator++();
1834 :
1835 : bool operator==(const StackIter &rhs) const;
1836 : bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
1837 :
1838 20466832 : bool isScript() const { JS_ASSERT(!done()); return state_ == SCRIPTED; }
1839 7777531 : StackFrame *fp() const { JS_ASSERT(!done() && isScript()); return fp_; }
1840 2593 : Value *sp() const { JS_ASSERT(!done() && isScript()); return sp_; }
1841 6283971 : jsbytecode *pc() const { JS_ASSERT(!done() && isScript()); return pc_; }
1842 1108 : JSScript *script() const { JS_ASSERT(!done() && isScript()); return script_; }
1843 :
1844 1304 : bool isNativeCall() const { JS_ASSERT(!done()); return state_ != SCRIPTED; }
1845 1304 : CallArgs nativeArgs() const { JS_ASSERT(!done() && isNativeCall()); return args_; }
1846 : };
1847 :
1848 : /* A filtering of the StackIter to only stop at scripts. */
1849 : class FrameRegsIter
1850 : {
1851 : StackIter iter_;
1852 :
1853 6298954 : void settle() {
1854 12700161 : while (!iter_.done() && !iter_.isScript())
1855 102253 : ++iter_;
1856 6298954 : }
1857 :
1858 : public:
1859 519879 : FrameRegsIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
1860 519879 : : iter_(cx, opt) { settle(); }
1861 :
1862 6324104 : bool done() const { return iter_.done(); }
1863 5779075 : FrameRegsIter &operator++() { ++iter_; settle(); return *this; }
1864 :
1865 : bool operator==(const FrameRegsIter &rhs) const { return iter_ == rhs.iter_; }
1866 : bool operator!=(const FrameRegsIter &rhs) const { return iter_ != rhs.iter_; }
1867 :
1868 7764994 : StackFrame *fp() const { return iter_.fp(); }
1869 2593 : Value *sp() const { return iter_.sp(); }
1870 6283971 : jsbytecode *pc() const { return iter_.pc(); }
1871 1108 : JSScript *script() const { return iter_.script(); }
1872 : };
1873 :
1874 : /*****************************************************************************/
1875 :
1876 : /*
1877 : * Blindly iterate over all frames in the current thread's stack. These frames
1878 : * can be from different contexts and compartments, so beware.
1879 : */
1880 : class AllFramesIter
1881 : {
1882 : public:
1883 : AllFramesIter(StackSpace &space);
1884 :
1885 208401 : bool done() const { return fp_ == NULL; }
1886 : AllFramesIter& operator++();
1887 :
1888 107829 : StackFrame *fp() const { return fp_; }
1889 :
1890 : private:
1891 : void settle();
1892 : StackSegment *seg_;
1893 : StackFrame *fp_;
1894 : };
1895 :
1896 : } /* namespace js */
1897 : #endif /* Stack_h__ */
|