LCOV - app.info - js/src/vm/Stack.h

LCOV - code coverage report
| Current view: | directory - js/src/vm - Stack.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 431 | 409 | 94.9 %
| Date: | 2012-04-07 | Functions: | 190 | 185 | 97.4 %

           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 &regs() 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 &regs);
        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 &regs() 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 &regs, const CallArgs &args,
        1681                 :                          JSFunction &callee, JSScript *script,
        1682                 :                          InitialFrameFlags initial);
        1683                 :     bool pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
        1684                 :                          JSFunction &callee, JSScript *script,
        1685                 :                          InitialFrameFlags initial, Value **stackLimit);
        1686                 :     void popInlineFrame(FrameRegs &regs);
        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__ */

Generated by: LCOV version 1.7