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 83456355 : void setUsedRval() const { usedRval_ = true; }
195 86915450 : 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 77010793 : Value *base() const { return argv_ - 2; }
205 68844661 : JSObject &callee() const { JS_ASSERT(!usedRval_); return argv_[-2].toObject(); }
206 73558900 : Value &calleev() const { JS_ASSERT(!usedRval_); return argv_[-2]; }
207 67533937 : Value &thisv() const { return argv_[-1]; }
208 :
209 72438189 : Value &rval() const {
210 72438189 : setUsedRval();
211 72438189 : return argv_[-2];
212 : }
213 :
214 11018166 : Value *spAfterCall() const {
215 11018166 : setUsedRval();
216 11018166 : return argv_ - 1;
217 : }
218 :
219 2767377 : void setCallee(Value calleev) {
220 2767377 : clearUsedRval();
221 2767377 : this->calleev() = calleev;
222 2767377 : }
223 : };
224 :
225 : JS_ALWAYS_INLINE CallReceiver
226 72866 : CallReceiverFromArgv(Value *argv)
227 : {
228 : CallReceiver receiver;
229 72866 : receiver.clearUsedRval();
230 72866 : receiver.argv_ = argv;
231 : return receiver;
232 : }
233 :
234 : JS_ALWAYS_INLINE CallReceiver
235 12845 : CallReceiverFromVp(Value *vp)
236 : {
237 12845 : 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 70609906 : Value &operator[](unsigned i) const { JS_ASSERT(i < argc_); return argv_[i]; }
251 117842603 : Value *array() const { return argv_; }
252 197822225 : unsigned length() const { return argc_; }
253 234486619 : Value *end() const { return argv_ + argc_; }
254 1580334 : bool hasDefined(unsigned i) const { return i < argc_ && !argv_[i].isUndefined(); }
255 : };
256 :
257 : JS_ALWAYS_INLINE CallArgs
258 84075207 : CallArgsFromArgv(unsigned argc, Value *argv)
259 : {
260 : CallArgs args;
261 84075207 : args.clearUsedRval();
262 84075207 : args.argv_ = argv;
263 84075207 : args.argc_ = argc;
264 : return args;
265 : }
266 :
267 : JS_ALWAYS_INLINE CallArgs
268 26481922 : CallArgsFromVp(unsigned argc, Value *vp)
269 : {
270 26481922 : return CallArgsFromArgv(argc, vp + 2);
271 : }
272 :
273 : JS_ALWAYS_INLINE CallArgs
274 57593285 : CallArgsFromSp(unsigned argc, Value *sp)
275 : {
276 57593285 : 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 103391 : CallArgsList *prev() const { return prev_; }
297 103391 : bool active() const { return active_; }
298 8718344 : void setActive() { active_ = true; }
299 8718344 : 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 -1075368443 : bool isFunctionFrame() const {
457 -1075368443 : return !!(flags_ & FUNCTION);
458 : }
459 :
460 127240 : bool isGlobalFrame() const {
461 127240 : return !!(flags_ & GLOBAL);
462 : }
463 :
464 1495483870 : bool isDummyFrame() const {
465 1495483870 : return !!(flags_ & DUMMY);
466 : }
467 :
468 1378791628 : bool isScriptFrame() const {
469 1378791628 : bool retval = !!(flags_ & (FUNCTION | GLOBAL));
470 1378791628 : JS_ASSERT(retval == !isDummyFrame());
471 1378791628 : 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 1327494438 : bool isEvalFrame() const {
487 1327494438 : JS_ASSERT_IF(flags_ & EVAL, isScriptFrame());
488 1327494438 : return flags_ & EVAL;
489 : }
490 :
491 670300 : bool isEvalInFunction() const {
492 670300 : return (flags_ & (EVAL | FUNCTION)) == (EVAL | FUNCTION);
493 : }
494 :
495 672574981 : bool isNonEvalFunctionFrame() const {
496 672574981 : return (flags_ & (FUNCTION | EVAL)) == FUNCTION;
497 : }
498 :
499 363874 : inline bool isStrictEvalFrame() const {
500 363874 : return isEvalFrame() && script()->strictModeCode;
501 : }
502 :
503 2872391 : bool isNonStrictEvalFrame() const {
504 2872391 : 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 85579903 : StackFrame *prev() const {
521 85579903 : 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 1028881182 : Value *slots() const {
538 1028881182 : return (Value *)(this + 1);
539 : }
540 :
541 164746650 : Value *base() const {
542 164746650 : return slots() + script()->nfixed;
543 : }
544 :
545 802556 : Value &varSlot(unsigned i) {
546 802556 : JS_ASSERT(i < script()->nfixed);
547 802556 : JS_ASSERT_IF(maybeFun(), i < script()->bindings.countVars());
548 802556 : return slots()[i];
549 : }
550 :
551 787338959 : Value &localSlot(unsigned i) {
552 : /* Let variables can be above script->nfixed. */
553 787338959 : JS_ASSERT(i < script()->nslots);
554 787338959 : 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 34543894 : jsbytecode *prevpc(JSInlinedSite **pinlined) {
596 34543894 : if (flags_ & HAS_PREVPC) {
597 33265762 : if (pinlined)
598 31965033 : *pinlined = prevInline_;
599 33265762 : return prevpc_;
600 : }
601 1278132 : return prevpcSlow(pinlined);
602 : }
603 :
604 55 : JSInlinedSite *prevInline() {
605 55 : JS_ASSERT(flags_ & HAS_PREVPC);
606 55 : return prevInline_;
607 : }
608 :
609 1354960456 : JSScript *script() const {
610 1354960456 : JS_ASSERT(isScriptFrame());
611 1354960456 : return isFunctionFrame()
612 -1722857314 : ? isEvalFrame() ? u.evalScript : fun()->script()
613 -367896858 : : 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 8062035 : JSScript *maybeScript() const {
627 8062035 : return isScriptFrame() ? script() : NULL;
628 : }
629 :
630 551093 : size_t numFixed() const {
631 551093 : return script()->nfixed;
632 : }
633 :
634 5253761 : size_t numSlots() const {
635 5253761 : 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 1740297045 : JSFunction* fun() const {
653 1740297045 : JS_ASSERT(isFunctionFrame());
654 1740297045 : return exec.fun;
655 : }
656 :
657 55010186 : JSFunction* maybeFun() const {
658 55010186 : return isFunctionFrame() ? fun() : NULL;
659 : }
660 :
661 1496506 : JSFunction* maybeScriptFunction() const {
662 1496506 : if (!isFunctionFrame())
663 152061 : return NULL;
664 1344445 : const StackFrame *fp = this;
665 2688891 : while (fp->isEvalFrame())
666 1 : fp = fp->prev();
667 1344445 : 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 562643846 : bool hasArgs() const {
691 562643846 : return isNonEvalFunctionFrame();
692 : }
693 :
694 318357274 : unsigned numFormalArgs() const {
695 318357274 : JS_ASSERT(hasArgs());
696 318357274 : return fun()->nargs;
697 : }
698 :
699 102074814 : Value &formalArg(unsigned i) const {
700 102074814 : JS_ASSERT(i < numFormalArgs());
701 102074814 : return formalArgs()[i];
702 : }
703 :
704 203768964 : Value *formalArgs() const {
705 203768964 : JS_ASSERT(hasArgs());
706 203768964 : return (Value *)this - numFormalArgs();
707 : }
708 :
709 5713148 : Value *formalArgsEnd() const {
710 5713148 : JS_ASSERT(hasArgs());
711 5713148 : return (Value *)this;
712 : }
713 :
714 26575234 : Value *maybeFormalArgs() const {
715 : return (flags_ & (FUNCTION | EVAL)) == FUNCTION
716 : ? formalArgs()
717 26575234 : : 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 359960 : inline bool forEachCanonicalActualArg(Op op, unsigned start = 0, unsigned count = unsigned(-1));
727 : template <class Op> inline bool forEachFormalArg(Op op);
728 :
729 4987803 : bool hasArgsObj() const {
730 4987803 : return !!(flags_ & HAS_ARGS_OBJ);
731 : }
732 :
733 696077 : ArgumentsObject &argsObj() const {
734 696077 : JS_ASSERT(hasArgsObj());
735 696077 : JS_ASSERT(!isEvalFrame());
736 696077 : return *argsObj_;
737 : }
738 :
739 0 : ArgumentsObject *maybeArgsObj() const {
740 0 : return hasArgsObj() ? &argsObj() : NULL;
741 : }
742 :
743 : inline void setArgsObj(ArgumentsObject &obj);
744 :
745 : /*
746 : * This value
747 : *
748 : * Every frame has a this value although, until 'this' is computed, the
749 : * value may not be the semantically-correct 'this' value.
750 : *
751 : * The 'this' value is stored before the formal arguments for function
752 : * frames and directly before the frame for global frames. The *Args
753 : * members assert !isEvalFrame(), so we implement specialized inline
754 : * methods for accessing 'this'. When the caller has static knowledge that
755 : * a frame is a function or global frame, 'functionThis' and 'globalThis',
756 : * respectively, allow more efficient access.
757 : */
758 :
759 1001933 : Value &functionThis() const {
760 1001933 : JS_ASSERT(isFunctionFrame());
761 1001933 : if (isEvalFrame())
762 0 : return ((Value *)this)[-1];
763 1001933 : return formalArgs()[-1];
764 : }
765 :
766 933370 : JSObject &constructorThis() const {
767 933370 : JS_ASSERT(hasArgs());
768 933370 : return formalArgs()[-1].toObject();
769 : }
770 :
771 : Value &globalThis() const {
772 : JS_ASSERT(isGlobalFrame());
773 : return ((Value *)this)[-1];
774 : }
775 :
776 36872620 : Value &thisValue() const {
777 36872620 : if (flags_ & (EVAL | GLOBAL))
778 380374 : return ((Value *)this)[-1];
779 36492246 : return formalArgs()[-1];
780 : }
781 :
782 : /*
783 : * Callee
784 : *
785 : * Only function frames have a callee. An eval frame in a function has the
786 : * same caller as its containing function frame. maybeCalleev can be used
787 : * to return a value that is either caller object (for function frames) or
788 : * null (for global frames).
789 : */
790 :
791 15886203 : JSObject &callee() const {
792 15886203 : JS_ASSERT(isFunctionFrame());
793 15886203 : return calleev().toObject();
794 : }
795 :
796 15967194 : const Value &calleev() const {
797 15967194 : JS_ASSERT(isFunctionFrame());
798 15967194 : return mutableCalleev();
799 : }
800 :
801 0 : const Value &maybeCalleev() const {
802 0 : JS_ASSERT(isScriptFrame());
803 : Value &calleev = flags_ & (EVAL | GLOBAL)
804 0 : ? ((Value *)this)[-2]
805 0 : : formalArgs()[-2];
806 0 : JS_ASSERT(calleev.isObjectOrNull());
807 0 : return calleev;
808 : }
809 :
810 : /*
811 : * Beware! Ad hoc changes can corrupt the stack layout; the callee should
812 : * only be changed to something that is equivalent to the current callee in
813 : * terms of numFormalArgs etc. Prefer overwriteCallee since it checks.
814 : */
815 : inline void overwriteCallee(JSObject &newCallee);
816 :
817 15967194 : Value &mutableCalleev() const {
818 15967194 : JS_ASSERT(isFunctionFrame());
819 15967194 : if (isEvalFrame())
820 159 : return ((Value *)this)[-2];
821 15967035 : return formalArgs()[-2];
822 : }
823 :
824 : /*
825 : * Compute the callee function for this stack frame, cloning if needed to
826 : * implement the method read barrier. If this is not a function frame,
827 : * set *vp to null.
828 : */
829 : bool getValidCalleeObject(JSContext *cx, Value *vp);
830 :
831 60021 : CallReceiver callReceiver() const {
832 60021 : return CallReceiverFromArgv(formalArgs());
833 : }
834 :
835 : /*
836 : * Scope chain
837 : *
838 : * Every frame has a scopeChain which, when traversed via the 'parent' link
839 : * to the root, indicates the current global object. A 'call object' is a
840 : * node on a scope chain representing a function's activation record. A
841 : * call object is used for dynamically-scoped name lookup and lexically-
842 : * scoped upvar access. The call object holds the values of locals and
843 : * arguments when a function returns (and its stack frame is popped). For
844 : * performance reasons, call objects are created lazily for 'lightweight'
845 : * functions, i.e., functions which are not statically known to require a
846 : * call object. Thus, a given function frame may or may not have a call
847 : * object. When a function does have a call object, it is found by walking
848 : * up the scope chain until the first call object. Thus, it is important,
849 : * when setting the scope chain, to indicate whether the new scope chain
850 : * contains a new call object and thus changes the 'hasCallObj' state.
851 : *
852 : * The method JIT requires that HAS_SCOPECHAIN be set for all frames which
853 : * use NAME or related opcodes that can access the scope chain (so it does
854 : * not have to test the bit). To ensure this, we always initialize the
855 : * scope chain when pushing frames in the VM, and only initialize it when
856 : * pushing frames in JIT code when the above situation applies.
857 : *
858 : * NB: 'fp->hasCallObj()' implies that fp->callObj() needs to be 'put' when
859 : * the frame is popped. Since the scope chain of a non-strict eval frame
860 : * contains the call object of the parent (function) frame, it is possible
861 : * to have:
862 : * !fp->hasCall() && fp->scopeChain().isCall()
863 : */
864 :
865 : inline JSObject &scopeChain() const;
866 :
867 34229267 : bool hasCallObj() const {
868 34229267 : bool ret = !!(flags_ & HAS_CALL_OBJ);
869 34229267 : JS_ASSERT_IF(ret, !isNonStrictEvalFrame());
870 34229267 : return ret;
871 : }
872 :
873 : inline CallObject &callObj() const;
874 : inline void setScopeChainNoCallObj(JSObject &obj);
875 : inline void setScopeChainWithOwnCallObj(CallObject &obj);
876 :
877 : /* Block chain */
878 :
879 45021810 : bool hasBlockChain() const {
880 45021810 : return (flags_ & HAS_BLOCKCHAIN) && blockChain_;
881 : }
882 :
883 5719862 : StaticBlockObject *maybeBlockChain() {
884 5719862 : return (flags_ & HAS_BLOCKCHAIN) ? blockChain_ : NULL;
885 : }
886 :
887 793951 : StaticBlockObject &blockChain() const {
888 793951 : JS_ASSERT(hasBlockChain());
889 793951 : return *blockChain_;
890 : }
891 :
892 4993498 : void setBlockChain(StaticBlockObject *obj) {
893 4993498 : flags_ |= HAS_BLOCKCHAIN;
894 4993498 : blockChain_ = obj;
895 4993498 : }
896 :
897 : /*
898 : * Prologue for function frames: make a call object for heavyweight
899 : * functions, and maintain type nesting invariants.
900 : */
901 : inline bool functionPrologue(JSContext *cx);
902 :
903 : /*
904 : * Epilogue for function frames: put any args or call object for the frame
905 : * which may still be live, and maintain type nesting invariants. Note:
906 : * this does not mark the epilogue as having been completed, since the
907 : * frame is about to be popped. Use updateEpilogueFlags for this.
908 : */
909 : inline void functionEpilogue();
910 :
911 : /*
912 : * If callObj() or argsObj() have already been put, update our flags
913 : * accordingly. This call must be followed by a later functionEpilogue.
914 : */
915 : inline void updateEpilogueFlags();
916 :
917 : inline bool maintainNestingState() const;
918 :
919 : /*
920 : * Variables object
921 : *
922 : * Given that a (non-dummy) StackFrame corresponds roughly to a ES5
923 : * Execution Context (ES5 10.3), StackFrame::varObj corresponds to the
924 : * VariableEnvironment component of a Exection Context. Intuitively, the
925 : * variables object is where new bindings (variables and functions) are
926 : * stored. One might expect that this is either the callObj or
927 : * scopeChain.globalObj for function or global code, respectively, however
928 : * the JSAPI allows calls of Execute to specify a variables object on the
929 : * scope chain other than the call/global object. This allows embeddings to
930 : * run multiple scripts under the same global, each time using a new
931 : * variables object to collect and discard the script's global variables.
932 : */
933 :
934 : inline JSObject &varObj();
935 :
936 : /*
937 : * Frame compartment
938 : *
939 : * A stack frame's compartment is the frame's containing context's
940 : * compartment when the frame was pushed.
941 : */
942 :
943 : inline JSCompartment *compartment() const;
944 :
945 : /* Annotation (will be removed after bug 546848) */
946 :
947 29489449 : void* annotation() const {
948 29489449 : return (flags_ & HAS_ANNOTATION) ? annotation_ : NULL;
949 : }
950 :
951 0 : void setAnnotation(void *annot) {
952 0 : flags_ |= HAS_ANNOTATION;
953 0 : annotation_ = annot;
954 0 : }
955 :
956 : /* JIT rejoin state */
957 :
958 45090 : JSRejoinState rejoin() const {
959 45090 : return rejoin_;
960 : }
961 :
962 118152 : void setRejoin(JSRejoinState state) {
963 118152 : rejoin_ = state;
964 118152 : }
965 :
966 : /* Down frame expansion state */
967 :
968 2089038 : void setDownFramesExpanded() {
969 2089038 : flags_ |= DOWN_FRAMES_EXPANDED;
970 2089038 : }
971 :
972 2416154 : bool downFramesExpanded() {
973 2416154 : return !!(flags_ & DOWN_FRAMES_EXPANDED);
974 : }
975 :
976 : /* Debugger hook data */
977 :
978 44264080 : bool hasHookData() const {
979 44264080 : return !!(flags_ & HAS_HOOK_DATA);
980 : }
981 :
982 : void* hookData() const {
983 : JS_ASSERT(hasHookData());
984 : return hookData_;
985 : }
986 :
987 15285465 : void* maybeHookData() const {
988 15285465 : return hasHookData() ? hookData_ : NULL;
989 : }
990 :
991 2900918 : void setHookData(void *v) {
992 2900918 : hookData_ = v;
993 2900918 : flags_ |= HAS_HOOK_DATA;
994 2900918 : }
995 :
996 : /* Return value */
997 :
998 43097 : bool hasReturnValue() const {
999 43097 : return !!(flags_ & HAS_RVAL);
1000 : }
1001 :
1002 20990934 : Value &returnValue() {
1003 20990934 : if (!(flags_ & HAS_RVAL))
1004 7891026 : rval_.setUndefined();
1005 20990934 : return rval_;
1006 : }
1007 :
1008 13686733 : void markReturnValue() {
1009 13686733 : flags_ |= HAS_RVAL;
1010 13686733 : }
1011 :
1012 9512848 : void setReturnValue(const Value &v) {
1013 9512848 : rval_ = v;
1014 9512848 : markReturnValue();
1015 9512848 : }
1016 :
1017 9190 : void clearReturnValue() {
1018 9190 : rval_.setUndefined();
1019 9190 : markReturnValue();
1020 9190 : }
1021 :
1022 : /* Native-code return address */
1023 :
1024 1022194 : void *nativeReturnAddress() const {
1025 1022194 : return ncode_;
1026 : }
1027 :
1028 4283657 : void setNativeReturnAddress(void *addr) {
1029 4283657 : ncode_ = addr;
1030 4283657 : }
1031 :
1032 71085 : void **addressOfNativeReturnAddress() {
1033 71085 : return &ncode_;
1034 : }
1035 :
1036 : /*
1037 : * Generator-specific members
1038 : *
1039 : * A non-eval function frame may optionally be the activation of a
1040 : * generator. For the most part, generator frames act like ordinary frames.
1041 : * For exceptions, see js_FloatingFrameIfGenerator.
1042 : */
1043 :
1044 42769033 : bool isGeneratorFrame() const {
1045 42769033 : return !!(flags_ & GENERATOR);
1046 : }
1047 :
1048 174396 : bool isFloatingGenerator() const {
1049 174396 : JS_ASSERT_IF(flags_ & FLOATING_GENERATOR, isGeneratorFrame());
1050 174396 : return !!(flags_ & FLOATING_GENERATOR);
1051 : }
1052 :
1053 12263 : void initFloatingGenerator() {
1054 12263 : JS_ASSERT(!(flags_ & GENERATOR));
1055 12263 : flags_ |= (GENERATOR | FLOATING_GENERATOR);
1056 12263 : }
1057 :
1058 30834 : void unsetFloatingGenerator() {
1059 30834 : flags_ &= ~FLOATING_GENERATOR;
1060 30834 : }
1061 :
1062 30834 : void setFloatingGenerator() {
1063 30834 : flags_ |= FLOATING_GENERATOR;
1064 30834 : }
1065 :
1066 : /*
1067 : * js::Execute pushes both global and function frames (since eval() in a
1068 : * function pushes a frame with isFunctionFrame() && isEvalFrame()). Most
1069 : * code should not care where a frame was pushed, but if it is necessary to
1070 : * pick out frames pushed by js::Execute, this is the right query:
1071 : */
1072 :
1073 18212057 : bool isFramePushedByExecute() const {
1074 18212057 : return !!(flags_ & (GLOBAL | EVAL));
1075 : }
1076 :
1077 : /*
1078 : * Other flags
1079 : */
1080 :
1081 1026757 : InitialFrameFlags initialFlags() const {
1082 : JS_STATIC_ASSERT((int)INITIAL_NONE == 0);
1083 : JS_STATIC_ASSERT((int)INITIAL_CONSTRUCT == (int)CONSTRUCTING);
1084 : JS_STATIC_ASSERT((int)INITIAL_LOWERED == (int)LOWERED_CALL_APPLY);
1085 1026757 : uint32_t mask = CONSTRUCTING | LOWERED_CALL_APPLY;
1086 1026757 : JS_ASSERT((flags_ & mask) != mask);
1087 1026757 : return InitialFrameFlags(flags_ & mask);
1088 : }
1089 :
1090 70076531 : bool isConstructing() const {
1091 70076531 : return !!(flags_ & CONSTRUCTING);
1092 : }
1093 :
1094 : /*
1095 : * The method JIT call/apply optimization can erase Function.{call,apply}
1096 : * invocations from the stack and push the callee frame directly. The base
1097 : * of these frames will be offset by one value, however, which the
1098 : * interpreter needs to account for if it ends up popping the frame.
1099 : */
1100 12677473 : bool loweredCallOrApply() const {
1101 12677473 : return !!(flags_ & LOWERED_CALL_APPLY);
1102 : }
1103 :
1104 0 : bool isDebuggerFrame() const {
1105 0 : return !!(flags_ & DEBUGGER);
1106 : }
1107 :
1108 : bool hasOverflowArgs() const {
1109 : return !!(flags_ & OVERFLOW_ARGS);
1110 : }
1111 :
1112 2007868 : bool isYielding() {
1113 2007868 : return !!(flags_ & YIELDING);
1114 : }
1115 :
1116 23131 : void setYielding() {
1117 23131 : flags_ |= YIELDING;
1118 23131 : }
1119 :
1120 23131 : void clearYielding() {
1121 23131 : flags_ &= ~YIELDING;
1122 23131 : }
1123 :
1124 1977915 : void setFinishedInInterpreter() {
1125 1977915 : flags_ |= FINISHED_IN_INTERP;
1126 1977915 : }
1127 :
1128 1291684 : bool finishedInInterpreter() const {
1129 1291684 : return !!(flags_ & FINISHED_IN_INTERP);
1130 : }
1131 :
1132 : #ifdef DEBUG
1133 : /* Poison scopeChain value set before a frame is flushed. */
1134 : static JSObject *const sInvalidScopeChain;
1135 : #endif
1136 :
1137 : public:
1138 : /* Public, but only for JIT use: */
1139 :
1140 537567 : static size_t offsetOfFlags() {
1141 537567 : return offsetof(StackFrame, flags_);
1142 : }
1143 :
1144 194760 : static size_t offsetOfExec() {
1145 194760 : return offsetof(StackFrame, exec);
1146 : }
1147 :
1148 2528 : static size_t offsetOfNumActual() {
1149 2528 : return offsetof(StackFrame, u.nactual);
1150 : }
1151 :
1152 238286 : static size_t offsetOfScopeChain() {
1153 238286 : return offsetof(StackFrame, scopeChain_);
1154 : }
1155 :
1156 440547 : static size_t offsetOfPrev() {
1157 440547 : return offsetof(StackFrame, prev_);
1158 : }
1159 :
1160 197432 : static size_t offsetOfReturnValue() {
1161 197432 : return offsetof(StackFrame, rval_);
1162 : }
1163 :
1164 432 : static size_t offsetOfArgsObj() {
1165 432 : return offsetof(StackFrame, argsObj_);
1166 : }
1167 :
1168 690758 : static ptrdiff_t offsetOfNcode() {
1169 690758 : return offsetof(StackFrame, ncode_);
1170 : }
1171 :
1172 76185 : static ptrdiff_t offsetOfCallee(JSFunction *fun) {
1173 76185 : JS_ASSERT(fun != NULL);
1174 76185 : return -(fun->nargs + 2) * sizeof(Value);
1175 : }
1176 :
1177 468531 : static ptrdiff_t offsetOfThis(JSFunction *fun) {
1178 : return fun == NULL
1179 : ? -1 * ptrdiff_t(sizeof(Value))
1180 468531 : : -(fun->nargs + 1) * ptrdiff_t(sizeof(Value));
1181 : }
1182 :
1183 634354 : static ptrdiff_t offsetOfFormalArg(JSFunction *fun, unsigned i) {
1184 634354 : JS_ASSERT(i < fun->nargs);
1185 634354 : return (-(int)fun->nargs + i) * sizeof(Value);
1186 : }
1187 :
1188 26389578 : static size_t offsetOfFixed(unsigned i) {
1189 26389578 : return sizeof(StackFrame) + i * sizeof(Value);
1190 : }
1191 :
1192 : #ifdef JS_METHODJIT
1193 2034512 : mjit::JITScript *jit() {
1194 2034512 : return script()->getJIT(isConstructing());
1195 : }
1196 : #endif
1197 :
1198 : void methodjitStaticAsserts();
1199 :
1200 : public:
1201 : void mark(JSTracer *trc);
1202 : };
1203 :
1204 : static const size_t VALUES_PER_STACK_FRAME = sizeof(StackFrame) / sizeof(Value);
1205 :
1206 : static inline unsigned
1207 877 : ToReportFlags(InitialFrameFlags initial)
1208 : {
1209 877 : return unsigned(initial & StackFrame::CONSTRUCTING);
1210 : }
1211 :
1212 : static inline StackFrame::Flags
1213 30000910 : ToFrameFlags(InitialFrameFlags initial)
1214 : {
1215 30000910 : return StackFrame::Flags(initial);
1216 : }
1217 :
1218 : static inline InitialFrameFlags
1219 : InitialFrameFlagsFromConstructing(bool b)
1220 : {
1221 : return b ? INITIAL_CONSTRUCT : INITIAL_NONE;
1222 : }
1223 :
1224 : static inline bool
1225 11879779 : InitialFrameFlagsAreConstructing(InitialFrameFlags initial)
1226 : {
1227 11879779 : return !!(initial & INITIAL_CONSTRUCT);
1228 : }
1229 :
1230 : static inline bool
1231 4556 : InitialFrameFlagsAreLowered(InitialFrameFlags initial)
1232 : {
1233 4556 : return !!(initial & INITIAL_LOWERED);
1234 : }
1235 :
1236 17149842 : inline StackFrame * Valueify(JSStackFrame *fp) { return (StackFrame *)fp; }
1237 10850132 : static inline JSStackFrame * Jsvalify(StackFrame *fp) { return (JSStackFrame *)fp; }
1238 :
1239 : /*****************************************************************************/
1240 :
1241 : class FrameRegs
1242 : {
1243 : public:
1244 : Value *sp;
1245 : jsbytecode *pc;
1246 : private:
1247 : JSInlinedSite *inlined_;
1248 : StackFrame *fp_;
1249 : public:
1250 -1369848337 : StackFrame *fp() const { return fp_; }
1251 189703632 : JSInlinedSite *inlined() const { return inlined_; }
1252 :
1253 : /* For jit use (need constant): */
1254 : static const size_t offsetOfFp = 3 * sizeof(void *);
1255 : static const size_t offsetOfInlined = 2 * sizeof(void *);
1256 : static void staticAssert() {
1257 : JS_STATIC_ASSERT(offsetOfFp == offsetof(FrameRegs, fp_));
1258 : JS_STATIC_ASSERT(offsetOfInlined == offsetof(FrameRegs, inlined_));
1259 : }
1260 4229629 : void clearInlined() { inlined_ = NULL; }
1261 :
1262 : /* For generator: */
1263 73931 : void rebaseFromTo(const FrameRegs &from, StackFrame &to) {
1264 73931 : fp_ = &to;
1265 73931 : sp = to.slots() + (from.sp - from.fp_->slots());
1266 73931 : pc = from.pc;
1267 73931 : inlined_ = from.inlined_;
1268 73931 : JS_ASSERT(fp_);
1269 73931 : }
1270 :
1271 : /* For ContextStack: */
1272 25808299 : void popFrame(Value *newsp) {
1273 25808299 : pc = fp_->prevpc(&inlined_);
1274 25808299 : sp = newsp;
1275 25808299 : fp_ = fp_->prev();
1276 25808299 : JS_ASSERT(fp_);
1277 25808299 : }
1278 :
1279 : /* For FixupArity: */
1280 1026757 : void popPartialFrame(Value *newsp) {
1281 1026757 : sp = newsp;
1282 1026757 : fp_ = fp_->prev();
1283 1026757 : JS_ASSERT(fp_);
1284 1026757 : }
1285 :
1286 : /* For InternalInterpret: */
1287 852 : void restorePartialFrame(Value *newfp) {
1288 852 : fp_ = (StackFrame *) newfp;
1289 852 : }
1290 :
1291 : /* For stubs::CompileFunction, ContextStack: */
1292 29158208 : void prepareToRun(StackFrame &fp, JSScript *script) {
1293 29158208 : pc = script->code;
1294 29158208 : sp = fp.slots() + script->nfixed;
1295 29158208 : fp_ = &fp;
1296 29158208 : inlined_ = NULL;
1297 29158208 : }
1298 :
1299 : /* For pushDummyFrame: */
1300 259746 : void initDummyFrame(StackFrame &fp) {
1301 259746 : pc = NULL;
1302 259746 : sp = fp.slots();
1303 259746 : fp_ = &fp;
1304 259746 : inlined_ = NULL;
1305 259746 : }
1306 :
1307 : /* For expandInlineFrames: */
1308 74 : void expandInline(StackFrame *innerfp, jsbytecode *innerpc) {
1309 74 : pc = innerpc;
1310 74 : fp_ = innerfp;
1311 74 : inlined_ = NULL;
1312 74 : }
1313 :
1314 : #ifdef JS_METHODJIT
1315 : /* For LimitCheck: */
1316 12 : void updateForNcode(mjit::JITScript *jit, void *ncode) {
1317 12 : pc = mjit::NativeToPC(jit, ncode, &inlined_);
1318 12 : }
1319 : #endif
1320 : };
1321 :
1322 : /*****************************************************************************/
1323 :
1324 : class StackSegment
1325 : {
1326 : /* Previous segment within same context stack. */
1327 : StackSegment *const prevInContext_;
1328 :
1329 : /* Previous segment sequentially in memory. */
1330 : StackSegment *const prevInMemory_;
1331 :
1332 : /* Execution registers for most recent script in this segment (or null). */
1333 : FrameRegs *regs_;
1334 :
1335 : /* Call args for most recent native call in this segment (or null). */
1336 : CallArgsList *calls_;
1337 :
1338 : public:
1339 469315 : StackSegment(StackSegment *prevInContext,
1340 : StackSegment *prevInMemory,
1341 : FrameRegs *regs,
1342 : CallArgsList *calls)
1343 : : prevInContext_(prevInContext),
1344 : prevInMemory_(prevInMemory),
1345 : regs_(regs),
1346 469315 : calls_(calls)
1347 469315 : {}
1348 :
1349 : /* A segment is followed in memory by the arguments of the first call. */
1350 :
1351 268518485 : Value *slotsBegin() const {
1352 268518485 : return (Value *)(this + 1);
1353 : }
1354 :
1355 : /* Accessors. */
1356 :
1357 108712119 : FrameRegs ®s() const {
1358 108712119 : JS_ASSERT(regs_);
1359 108712119 : return *regs_;
1360 : }
1361 :
1362 -1088182208 : FrameRegs *maybeRegs() const {
1363 -1088182208 : return regs_;
1364 : }
1365 :
1366 1104038522 : StackFrame *fp() const {
1367 1104038522 : return regs_->fp();
1368 : }
1369 :
1370 109123526 : StackFrame *maybefp() const {
1371 109123526 : return regs_ ? regs_->fp() : NULL;
1372 : }
1373 :
1374 28391 : jsbytecode *maybepc() const {
1375 28391 : return regs_ ? regs_->pc : NULL;
1376 : }
1377 :
1378 6101043 : CallArgsList &calls() const {
1379 6101043 : JS_ASSERT(calls_);
1380 6101043 : return *calls_;
1381 : }
1382 :
1383 66278 : CallArgsList *maybeCalls() const {
1384 66278 : return calls_;
1385 : }
1386 :
1387 : Value *callArgv() const {
1388 : return calls_->array();
1389 : }
1390 :
1391 : Value *maybeCallArgv() const {
1392 : return calls_ ? calls_->array() : NULL;
1393 : }
1394 :
1395 470615 : StackSegment *prevInContext() const {
1396 470615 : return prevInContext_;
1397 : }
1398 :
1399 502755 : StackSegment *prevInMemory() const {
1400 502755 : return prevInMemory_;
1401 : }
1402 :
1403 36164910 : void repointRegs(FrameRegs *regs) {
1404 36164910 : JS_ASSERT_IF(regs, regs->fp());
1405 36164910 : regs_ = regs;
1406 36164910 : }
1407 :
1408 440934 : bool isEmpty() const {
1409 440934 : return !calls_ && !regs_;
1410 : }
1411 :
1412 : bool contains(const StackFrame *fp) const;
1413 : bool contains(const FrameRegs *regs) const;
1414 : bool contains(const CallArgsList *call) const;
1415 :
1416 : StackFrame *computeNextFrame(const StackFrame *fp) const;
1417 :
1418 : Value *end() const;
1419 :
1420 : FrameRegs *pushRegs(FrameRegs ®s);
1421 : void popRegs(FrameRegs *regs);
1422 : void pushCall(CallArgsList &callList);
1423 : void pointAtCall(CallArgsList &callList);
1424 : void popCall();
1425 :
1426 : /* For jit access: */
1427 :
1428 : static const size_t offsetOfRegs() { return offsetof(StackSegment, regs_); }
1429 : };
1430 :
1431 : static const size_t VALUES_PER_STACK_SEGMENT = sizeof(StackSegment) / sizeof(Value);
1432 : JS_STATIC_ASSERT(sizeof(StackSegment) % sizeof(Value) == 0);
1433 :
1434 : /*****************************************************************************/
1435 :
1436 : class StackSpace
1437 : {
1438 : StackSegment *seg_;
1439 : Value *base_;
1440 : mutable Value *conservativeEnd_;
1441 : #ifdef XP_WIN
1442 : mutable Value *commitEnd_;
1443 : #endif
1444 : Value *defaultEnd_;
1445 : Value *trustedEnd_;
1446 :
1447 41081937 : void assertInvariants() const {
1448 41081937 : JS_ASSERT(base_ <= conservativeEnd_);
1449 : #ifdef XP_WIN
1450 : JS_ASSERT(conservativeEnd_ <= commitEnd_);
1451 : JS_ASSERT(commitEnd_ <= trustedEnd_);
1452 : #endif
1453 41081937 : JS_ASSERT(conservativeEnd_ <= defaultEnd_);
1454 41081937 : JS_ASSERT(defaultEnd_ <= trustedEnd_);
1455 41081937 : }
1456 :
1457 : /* The total number of values/bytes reserved for the stack. */
1458 : static const size_t CAPACITY_VALS = 512 * 1024;
1459 : static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(Value);
1460 :
1461 : /* How much of the stack is initially committed. */
1462 : static const size_t COMMIT_VALS = 16 * 1024;
1463 : static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value);
1464 :
1465 : /* How much space is reserved at the top of the stack for trusted JS. */
1466 : static const size_t BUFFER_VALS = 16 * 1024;
1467 : static const size_t BUFFER_BYTES = BUFFER_VALS * sizeof(Value);
1468 :
1469 : static void staticAsserts() {
1470 : JS_STATIC_ASSERT(CAPACITY_VALS % COMMIT_VALS == 0);
1471 : }
1472 :
1473 : friend class AllFramesIter;
1474 : friend class ContextStack;
1475 : friend class StackFrame;
1476 :
1477 : /*
1478 : * Except when changing compartment (see pushDummyFrame), the 'dest'
1479 : * parameter of ensureSpace is cx->compartment. Ideally, we'd just pass
1480 : * this directly (and introduce a helper that supplies cx->compartment when
1481 : * no 'dest' is given). For some compilers, this really hurts performance,
1482 : * so, instead, a trivially sinkable magic constant is used to indicate
1483 : * that dest should be cx->compartment.
1484 : */
1485 : static const size_t CX_COMPARTMENT = 0xc;
1486 :
1487 : inline bool ensureSpace(JSContext *cx, MaybeReportError report,
1488 : Value *from, ptrdiff_t nvals,
1489 : JSCompartment *dest = (JSCompartment *)CX_COMPARTMENT) const;
1490 : JS_FRIEND_API(bool) ensureSpaceSlow(JSContext *cx, MaybeReportError report,
1491 : Value *from, ptrdiff_t nvals,
1492 : JSCompartment *dest) const;
1493 :
1494 : StackSegment &findContainingSegment(const StackFrame *target) const;
1495 :
1496 : public:
1497 : StackSpace();
1498 : bool init();
1499 : ~StackSpace();
1500 :
1501 : /*
1502 : * Maximum supported value of arguments.length. This bounds the maximum
1503 : * number of arguments that can be supplied to Function.prototype.apply.
1504 : * This value also bounds the number of elements parsed in an array
1505 : * initialiser.
1506 : *
1507 : * Since arguments are copied onto the stack, the stack size is the
1508 : * limiting factor for this constant. Use the max stack size (available to
1509 : * untrusted code) with an extra buffer so that, after such an apply, the
1510 : * callee can do a little work without OOMing.
1511 : */
1512 : static const unsigned ARGS_LENGTH_MAX = CAPACITY_VALS - (2 * BUFFER_VALS);
1513 :
1514 : /* See stack layout comment in Stack.h. */
1515 106666202 : inline Value *firstUnused() const { return seg_ ? seg_->end() : base_; }
1516 :
1517 : StackSegment &containingSegment(const StackFrame *target) const;
1518 :
1519 : /*
1520 : * Extra space to reserve on the stack for method JIT frames, beyond the
1521 : * frame's nslots. This may be used for inlined stack frames, slots storing
1522 : * loop invariant code, or to reserve space for pushed callee frames. Note
1523 : * that this space should be reserved when pushing interpreter frames as
1524 : * well, so that we don't need to check the stack when entering the method
1525 : * JIT at loop heads or safe points.
1526 : */
1527 : static const size_t STACK_JIT_EXTRA = (/*~VALUES_PER_STACK_FRAME*/ 8 + 18) * 10;
1528 :
1529 : /*
1530 : * Return a limit against which jit code can check for. This limit is not
1531 : * necessarily the end of the stack since we lazily commit stack memory on
1532 : * some platforms. Thus, when the stack limit is exceeded, the caller should
1533 : * use tryBumpLimit to attempt to increase the stack limit by committing
1534 : * more memory. If the stack is truly exhausted, tryBumpLimit will report an
1535 : * error and return NULL.
1536 : *
1537 : * An invariant of the methodjit is that there is always space to push a
1538 : * frame on top of the current frame's expression stack (which can be at
1539 : * most script->nslots deep). getStackLimit ensures that the returned limit
1540 : * does indeed have this required space and reports an error and returns
1541 : * NULL if this reserve space cannot be allocated.
1542 : */
1543 : inline Value *getStackLimit(JSContext *cx, MaybeReportError report);
1544 : bool tryBumpLimit(JSContext *cx, Value *from, unsigned nvals, Value **limit);
1545 :
1546 : /* Called during GC: mark segments, frames, and slots under firstUnused. */
1547 : void mark(JSTracer *trc);
1548 : void markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc);
1549 :
1550 : /* Called during GC: sets active flag on compartments with active frames. */
1551 : void markActiveCompartments();
1552 :
1553 : /* We only report the committed size; uncommitted size is uninteresting. */
1554 : JS_FRIEND_API(size_t) sizeOfCommitted();
1555 : };
1556 :
1557 : /*****************************************************************************/
1558 :
1559 : class ContextStack
1560 : {
1561 : StackSegment *seg_;
1562 : StackSpace *const space_;
1563 : JSContext *cx_;
1564 :
1565 : /*
1566 : * Return whether this ContextStack is at the top of the contiguous stack.
1567 : * This is a precondition for extending the current segment by pushing
1568 : * stack frames or overrides etc.
1569 : *
1570 : * NB: Just because a stack is onTop() doesn't mean there is necessarily
1571 : * a frame pushed on the stack. For this, use hasfp().
1572 : */
1573 : bool onTop() const;
1574 :
1575 : #ifdef DEBUG
1576 : void assertSpaceInSync() const;
1577 : #else
1578 : void assertSpaceInSync() const {}
1579 : #endif
1580 :
1581 : /* Implementation details of push* public interface. */
1582 : StackSegment *pushSegment(JSContext *cx);
1583 : enum MaybeExtend { CAN_EXTEND = true, CANT_EXTEND = false };
1584 : Value *ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars,
1585 : MaybeExtend extend, bool *pushedSeg,
1586 : JSCompartment *dest = (JSCompartment *)StackSpace::CX_COMPARTMENT);
1587 :
1588 : inline StackFrame *
1589 : getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
1590 : JSFunction *fun, JSScript *script, StackFrame::Flags *pflags) const;
1591 :
1592 : /* Make pop* functions private since only called by guard classes. */
1593 : void popSegment();
1594 : friend class InvokeArgsGuard;
1595 : void popInvokeArgs(const InvokeArgsGuard &iag);
1596 : friend class FrameGuard;
1597 : void popFrame(const FrameGuard &fg);
1598 : friend class GeneratorFrameGuard;
1599 : void popGeneratorFrame(const GeneratorFrameGuard &gfg);
1600 :
1601 : friend class StackIter;
1602 :
1603 : public:
1604 : ContextStack(JSContext *cx);
1605 : ~ContextStack();
1606 :
1607 : /*** Stack accessors ***/
1608 :
1609 : /*
1610 : * A context's stack is "empty" if there are no scripts or natives
1611 : * executing. Note that JS_SaveFrameChain does not factor into this definition.
1612 : */
1613 243593 : bool empty() const { return !seg_; }
1614 :
1615 : /*
1616 : * Return whether there has been at least one frame pushed since the most
1617 : * recent call to JS_SaveFrameChain. Note that natives do not have frames
1618 : * and dummy frames are frames that do not represent script execution hence
1619 : * this query has little semantic meaning past "you can call fp()".
1620 : */
1621 -1228930547 : inline bool hasfp() const { return seg_ && seg_->maybeRegs(); }
1622 :
1623 : /*
1624 : * Return the most recent script activation's registers with the same
1625 : * caveat as hasfp regarding JS_SaveFrameChain.
1626 : */
1627 144645234 : inline FrameRegs *maybeRegs() const { return seg_ ? seg_->maybeRegs() : NULL; }
1628 3801897 : inline StackFrame *maybefp() const { return seg_ ? seg_->maybefp() : NULL; }
1629 :
1630 : /* Faster alternatives to maybe* functions. */
1631 60106246 : inline FrameRegs ®s() const { JS_ASSERT(hasfp()); return seg_->regs(); }
1632 1101437069 : inline StackFrame *fp() const { JS_ASSERT(hasfp()); return seg_->fp(); }
1633 :
1634 : /* The StackSpace currently hosting this ContextStack. */
1635 212640411 : StackSpace &space() const { return *space_; }
1636 :
1637 : /* Return whether the given frame is in this context's stack. */
1638 : bool containsSlow(const StackFrame *target) const;
1639 :
1640 : /*** Stack manipulation ***/
1641 :
1642 : /*
1643 : * pushInvokeArgs allocates |argc + 2| rooted values that will be passed as
1644 : * the arguments to Invoke. A single allocation can be used for multiple
1645 : * Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
1646 : * an immediately-enclosing (stack-wise) call to pushInvokeArgs.
1647 : */
1648 : bool pushInvokeArgs(JSContext *cx, unsigned argc, InvokeArgsGuard *ag);
1649 :
1650 : /* Called by Invoke for a scripted function call. */
1651 : bool pushInvokeFrame(JSContext *cx, const CallArgs &args,
1652 : InitialFrameFlags initial, InvokeFrameGuard *ifg);
1653 :
1654 : /* Called by Execute for execution of eval or global code. */
1655 : bool pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thisv,
1656 : JSObject &scopeChain, ExecuteType type,
1657 : StackFrame *evalInFrame, ExecuteFrameGuard *efg);
1658 :
1659 : /*
1660 : * Called by SendToGenerator to resume a yielded generator. In addition to
1661 : * pushing a frame onto the VM stack, this function copies over the
1662 : * floating frame stored in 'gen'. When 'gfg' is destroyed, the destructor
1663 : * will copy the frame back to the floating frame.
1664 : */
1665 : bool pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg);
1666 :
1667 : /*
1668 : * When changing the compartment of a cx, it is necessary to immediately
1669 : * change the scope chain to a global in the right compartment since any
1670 : * amount of general VM code can run before the first scripted frame is
1671 : * pushed (if at all). This is currently and hackily accomplished by
1672 : * pushing a "dummy frame" with the correct scope chain. On success, this
1673 : * function will change the compartment to 'scopeChain.compartment()' and
1674 : * push a dummy frame for 'scopeChain'. On failure, nothing is changed.
1675 : */
1676 : bool pushDummyFrame(JSContext *cx, JSCompartment *dest, JSObject &scopeChain, DummyFrameGuard *dfg);
1677 :
1678 : /*
1679 : * An "inline frame" may only be pushed from within the top, active
1680 : * segment. This is the case for calls made inside mjit code and Interpret.
1681 : * The 'stackLimit' overload updates 'stackLimit' if it changes.
1682 : */
1683 : bool pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
1684 : JSFunction &callee, JSScript *script,
1685 : InitialFrameFlags initial);
1686 : bool pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
1687 : JSFunction &callee, JSScript *script,
1688 : InitialFrameFlags initial, Value **stackLimit);
1689 : void popInlineFrame(FrameRegs ®s);
1690 :
1691 : /* Pop a partially-pushed frame after hitting the limit before throwing. */
1692 : void popFrameAfterOverflow();
1693 :
1694 : /* Get the topmost script and optional pc on the stack. */
1695 : inline JSScript *currentScript(jsbytecode **pc = NULL) const;
1696 :
1697 : /* Get the scope chain for the topmost scripted call on the stack. */
1698 : inline JSObject *currentScriptedScopeChain() const;
1699 :
1700 : /*
1701 : * Called by the methodjit for an arity mismatch. Arity mismatch can be
1702 : * hot, so getFixupFrame avoids doing call setup performed by jit code when
1703 : * FixupArity returns.
1704 : */
1705 : StackFrame *getFixupFrame(JSContext *cx, MaybeReportError report,
1706 : const CallArgs &args, JSFunction *fun, JSScript *script,
1707 : void *ncode, InitialFrameFlags initial, Value **stackLimit);
1708 :
1709 : bool saveFrameChain();
1710 : void restoreFrameChain();
1711 :
1712 : /*
1713 : * As an optimization, the interpreter/mjit can operate on a local
1714 : * FrameRegs instance repoint the ContextStack to this local instance.
1715 : */
1716 36164910 : inline void repointRegs(FrameRegs *regs) { JS_ASSERT(hasfp()); seg_->repointRegs(regs); }
1717 :
1718 : /*** For JSContext: ***/
1719 :
1720 : /*
1721 : * To avoid indirection, ContextSpace caches a pointer to the StackSpace.
1722 : * This must be kept coherent with cx->thread->data.space by calling
1723 : * 'threadReset' whenver cx->thread changes.
1724 : */
1725 : void threadReset();
1726 :
1727 : /*** For jit compiler: ***/
1728 :
1729 : static size_t offsetOfSeg() { return offsetof(ContextStack, seg_); }
1730 : };
1731 :
1732 : /*****************************************************************************/
1733 :
1734 : class InvokeArgsGuard : public CallArgsList
1735 : {
1736 : friend class ContextStack;
1737 : ContextStack *stack_;
1738 : bool pushedSeg_;
1739 6101043 : void setPushed(ContextStack &stack) { JS_ASSERT(!pushed()); stack_ = &stack; }
1740 : public:
1741 6670901 : InvokeArgsGuard() : CallArgsList(), stack_(NULL), pushedSeg_(false) {}
1742 6670901 : ~InvokeArgsGuard() { if (pushed()) stack_->popInvokeArgs(*this); }
1743 21640364 : bool pushed() const { return !!stack_; }
1744 909 : void pop() { stack_->popInvokeArgs(*this); stack_ = NULL; }
1745 : };
1746 :
1747 : class FrameGuard
1748 : {
1749 : protected:
1750 : friend class ContextStack;
1751 : ContextStack *stack_;
1752 : bool pushedSeg_;
1753 : FrameRegs regs_;
1754 : FrameRegs *prevRegs_;
1755 5688408 : void setPushed(ContextStack &stack) { stack_ = &stack; }
1756 : public:
1757 5688436 : FrameGuard() : stack_(NULL), pushedSeg_(false) {}
1758 5688436 : ~FrameGuard() { if (pushed()) stack_->popFrame(*this); }
1759 11438512 : bool pushed() const { return !!stack_; }
1760 : void pop() { stack_->popFrame(*this); stack_ = NULL; }
1761 :
1762 5428662 : StackFrame *fp() const { return regs_.fp(); }
1763 : };
1764 :
1765 : class InvokeFrameGuard : public FrameGuard
1766 10436526 : {};
1767 :
1768 : class ExecuteFrameGuard : public FrameGuard
1769 359186 : {};
1770 :
1771 : class DummyFrameGuard : public FrameGuard
1772 519492 : {};
1773 :
1774 : class GeneratorFrameGuard : public FrameGuard
1775 30834 : {
1776 : friend class ContextStack;
1777 : JSGenerator *gen_;
1778 : Value *stackvp_;
1779 : public:
1780 30834 : ~GeneratorFrameGuard() { if (pushed()) stack_->popGeneratorFrame(*this); }
1781 : };
1782 :
1783 : /*****************************************************************************/
1784 :
1785 : /*
1786 : * Iterate through the callstack of the given context. Each element of said
1787 : * callstack can either be the execution of a script (scripted function call,
1788 : * global code, eval code, debugger code) or the invocation of a (C++) native.
1789 : * Example usage:
1790 : *
1791 : * for (Stackiter i(cx); !i.done(); ++i) {
1792 : * if (i.isScript()) {
1793 : * ... i.fp() ... i.sp() ... i.pc()
1794 : * } else {
1795 : * JS_ASSERT(i.isNativeCall());
1796 : * ... i.args();
1797 : * }
1798 : * }
1799 : *
1800 : * The SavedOption parameter additionally lets the iterator continue through
1801 : * breaks in the callstack (from JS_SaveFrameChain). The default is to stop.
1802 : */
1803 : class StackIter
1804 : {
1805 : friend class ContextStack;
1806 : JSContext *cx_;
1807 : public:
1808 : enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
1809 : private:
1810 : SavedOption savedOption_;
1811 :
1812 : enum State { DONE, SCRIPTED, NATIVE, IMPLICIT_NATIVE };
1813 : State state_;
1814 :
1815 : StackFrame *fp_;
1816 : CallArgsList *calls_;
1817 :
1818 : StackSegment *seg_;
1819 : Value *sp_;
1820 : jsbytecode *pc_;
1821 : JSScript *script_;
1822 : CallArgs args_;
1823 :
1824 : void poisonRegs();
1825 : void popFrame();
1826 : void popCall();
1827 : void settleOnNewSegment();
1828 : void settleOnNewState();
1829 : void startOnSegment(StackSegment *seg);
1830 :
1831 : public:
1832 : StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
1833 :
1834 35906726 : bool done() const { return state_ == DONE; }
1835 : StackIter &operator++();
1836 :
1837 : bool operator==(const StackIter &rhs) const;
1838 : bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
1839 :
1840 13482216 : bool isScript() const { JS_ASSERT(!done()); return state_ == SCRIPTED; }
1841 4528162 : StackFrame *fp() const { JS_ASSERT(!done() && isScript()); return fp_; }
1842 2992 : Value *sp() const { JS_ASSERT(!done() && isScript()); return sp_; }
1843 4416908 : jsbytecode *pc() const { JS_ASSERT(!done() && isScript()); return pc_; }
1844 1057 : JSScript *script() const { JS_ASSERT(!done() && isScript()); return script_; }
1845 :
1846 1304 : bool isNativeCall() const { JS_ASSERT(!done()); return state_ != SCRIPTED; }
1847 1304 : CallArgs nativeArgs() const { JS_ASSERT(!done() && isNativeCall()); return args_; }
1848 : };
1849 :
1850 : /* A filtering of the StackIter to only stop at scripts. */
1851 : class FrameRegsIter
1852 : {
1853 : StackIter iter_;
1854 :
1855 4431533 : void settle() {
1856 8961711 : while (!iter_.done() && !iter_.isScript())
1857 98645 : ++iter_;
1858 4431533 : }
1859 :
1860 : public:
1861 60062 : FrameRegsIter(JSContext *cx, StackIter::SavedOption opt = StackIter::STOP_AT_SAVED)
1862 60062 : : iter_(cx, opt) { settle(); }
1863 :
1864 4457510 : bool done() const { return iter_.done(); }
1865 4371471 : FrameRegsIter &operator++() { ++iter_; settle(); return *this; }
1866 :
1867 : bool operator==(const FrameRegsIter &rhs) const { return iter_ == rhs.iter_; }
1868 : bool operator!=(const FrameRegsIter &rhs) const { return iter_ != rhs.iter_; }
1869 :
1870 4515666 : StackFrame *fp() const { return iter_.fp(); }
1871 2992 : Value *sp() const { return iter_.sp(); }
1872 4416908 : jsbytecode *pc() const { return iter_.pc(); }
1873 1057 : JSScript *script() const { return iter_.script(); }
1874 : };
1875 :
1876 : /*****************************************************************************/
1877 :
1878 : /*
1879 : * Blindly iterate over all frames in the current thread's stack. These frames
1880 : * can be from different contexts and compartments, so beware.
1881 : */
1882 : class AllFramesIter
1883 : {
1884 : public:
1885 : AllFramesIter(StackSpace &space);
1886 :
1887 233602 : bool done() const { return fp_ == NULL; }
1888 : AllFramesIter& operator++();
1889 :
1890 121147 : StackFrame *fp() const { return fp_; }
1891 :
1892 : private:
1893 : void settle();
1894 : StackSegment *seg_;
1895 : StackFrame *fp_;
1896 : };
1897 :
1898 : } /* namespace js */
1899 : #endif /* Stack_h__ */
|