LCOV - code coverage report
Current view: directory - js/src/vm - Stack.h (source / functions) Found Hit Coverage
Test: app.info Lines: 430 415 96.5 %
Date: 2012-06-02 Functions: 191 187 97.9 %

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

Generated by: LCOV version 1.7