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

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

Generated by: LCOV version 1.7