This is not a limited-enumerated attribute, so let's use reflectString instead.

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=4 sw=4 et tw=79 ft=cpp: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is SpiderMonkey JavaScript engine. * * The Initial Developer of the Original Code is * Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Luke Wagner <luke@mozilla.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */#ifndef Stack_h__#define Stack_h__#include"jsfun.h"structJSContext;structJSCompartment;namespacejs{classStackFrame;classFrameRegs;classStackSegment;classStackSpace;classContextStack;classInvokeArgsGuard;classInvokeFrameGuard;classFrameGuard;classExecuteFrameGuard;classDummyFrameGuard;classGeneratorFrameGuard;classCallIter;classFrameRegsIter;classAllFramesIter;classArgumentsObject;namespacemjit{structJITScript;}/* * VM stack layout * * SpiderMonkey uses a per-thread stack to store the activation records, * parameters, locals, and expression temporaries for the stack of actively * executing scripts, functions and generators. The per-thread stack is owned * by the StackSpace object stored in the thread's ThreadData. * * The per-thread stack is subdivided into contiguous segments of memory which * have a memory layout invariant that allows fixed offsets to be used for stack * access (by jit code) as well as fast call/return. This memory layout is * encapsulated by a set of types that describe different regions of memory. * This encapsulation has holes: to avoid calling into C++ from generated code, * JIT compilers generate code that simulates analogous operations in C++. * * A sample memory layout of a segment looks like: * * regs * .---------------------------------------------. * | V * | fp .--FrameRegs--. sp * | V V * |StackSegment| slots |StackFrame| slots |StackFrame| slots | * | ^ | * ? <----------' `-----------' * prev prev * * A segment starts with a fixed-size header (js::StackSegment) which logically * describes the segment, links it to the rest of the stack, and points to the * end of the stack. * * Each script activation (global or function code) is given a fixed-size header * (js::StackFrame) which is associated with the values (called "slots") before * and after it. The frame contains bookkeeping information about the activation * and links to the previous frame. * * The slots preceding a (function) StackFrame in memory are the arguments of * the call. The slots after a StackFrame in memory are its locals followed by * its expression stack. There is no clean line between the arguments of a * frame and the expression stack of the previous frame since the top slots of * the expression become the arguments of a call. There are also layout * invariants concerning the arguments and StackFrame; see "Arguments" comment * in StackFrame for more details. * * The top of a segment's current frame's expression stack is pointed to by the * segment's "current regs", which contains the stack pointer 'sp'. In the * interpreter, sp is adjusted as individual values are pushed and popped from * the stack and the FrameRegs struct (pointed by the StackSegment) is a local * var of js::Interpret. JIT code simulates this by lazily updating FrameRegs * when calling from JIT code into the VM. Ideally, we'd like to remove all * dependence on FrameRegs outside the interpreter. * * A call to a native (C++) function does not push a frame. Instead, an array * of values is passed to the native. The layout of this array is abstracted by * js::CallArgs. With respect to the StackSegment layout above, the args to a * native call are inserted anywhere there can be slots. A sample memory layout * looks like: * * regs * .----------------------------------------. * | V * | fp .--FrameRegs--. sp * | V V * |StackSegment| native call | slots |StackFrame| slots | native call | * | vp <--argc--> end vp <--argc--> end * | CallArgs <------------------------------ CallArgs * | prev ^ * `-----------------------------------------------------' * calls * * Here there are two native calls on the stack. The start of each native arg * range is recorded by a CallArgs element which is prev-linked like stack * frames. Note that, in full generality, native and scripted calls can * interleave arbitrarily. Thus, the end of a segment is the maximum of its * current frame and its current native call. Similarly, the top of the entire * thread stack is the end of its current segment. * * Note that, between any two StackFrames there may be any number * of native calls, so the meaning of 'prev' is not 'directly called by'. * * An additional feature (perhaps not for much longer: bug 650361) is that * multiple independent "contexts" can interleave (LIFO) on a single contiguous * stack. "Independent" here means that neither context sees the other's * frames. Concretely, an embedding may enter the JS engine on cx1 and then, * from a native called by the JS engine, reenter the VM on cx2. Changing from * cx1 to cx2 causes a new segment to be started for cx2's stack on top of * cx1's current segment. These two segments are linked from the perspective of * StackSpace, since they are adjacent on the thread's stack, but not from the * perspective of cx1 and cx2. Thus, each segment has two links: prevInMemory * and prevInContext. Each independent stack is encapsulated and managed by * the js::ContextStack object stored in JSContext. ContextStack is the primary * interface to the rest of the engine for pushing and popping the stack. *//*****************************************************************************/classCallReceiver{protected:#ifdef DEBUGmutableboolusedRval_;voidsetUsedRval()const{usedRval_=true;}voidclearUsedRval()const{usedRval_=false;}#elsevoidsetUsedRval()const{}voidclearUsedRval()const{}#endifValue*argv_;public:friendCallReceiverCallReceiverFromVp(Value*);friendCallReceiverCallReceiverFromArgv(Value*);Value*base()const{returnargv_-2;}JSObject&callee()const{JS_ASSERT(!usedRval_);returnargv_[-2].toObject();}Value&calleev()const{JS_ASSERT(!usedRval_);returnargv_[-2];}Value&thisv()const{returnargv_[-1];}Value&rval()const{setUsedRval();returnargv_[-2];}Value*spAfterCall()const{setUsedRval();returnargv_-1;}voidcalleeHasBeenReset()const{clearUsedRval();}};JS_ALWAYS_INLINECallReceiverCallReceiverFromArgv(Value*argv){CallReceiverreceiver;receiver.clearUsedRval();receiver.argv_=argv;returnreceiver;}JS_ALWAYS_INLINECallReceiverCallReceiverFromVp(Value*vp){returnCallReceiverFromArgv(vp+2);}/*****************************************************************************/classCallArgs:publicCallReceiver{protected:uintNargc_;public:friendCallArgsCallArgsFromVp(uintN,Value*);friendCallArgsCallArgsFromArgv(uintN,Value*);friendCallArgsCallArgsFromSp(uintN,Value*);Value&operator[](unsignedi)const{JS_ASSERT(i<argc_);returnargv_[i];}Value*argv()const{returnargv_;}uintNargc()const{returnargc_;}Value*end()const{returnargv_+argc_;}};JS_ALWAYS_INLINECallArgsCallArgsFromArgv(uintNargc,Value*argv){CallArgsargs;args.clearUsedRval();args.argv_=argv;args.argc_=argc;returnargs;}JS_ALWAYS_INLINECallArgsCallArgsFromVp(uintNargc,Value*vp){returnCallArgsFromArgv(argc,vp+2);}JS_ALWAYS_INLINECallArgsCallArgsFromSp(uintNargc,Value*sp){returnCallArgsFromArgv(argc,sp-argc);}/*****************************************************************************/classCallArgsList:publicCallArgs{friendclassStackSegment;CallArgsList*prev_;boolactive_;public:friendCallArgsListCallArgsListFromVp(uintN,Value*,CallArgsList*);friendCallArgsListCallArgsListFromArgv(uintN,Value*,CallArgsList*);CallArgsList*prev()const{returnprev_;}boolactive()const{returnactive_;}voidsetActive(){active_=true;}voidsetInactive(){active_=false;}};JS_ALWAYS_INLINECallArgsListCallArgsListFromArgv(uintNargc,Value*argv,CallArgsList*prev){CallArgsListargs;#ifdef DEBUGargs.usedRval_=false;#endifargs.argv_=argv;args.argc_=argc;args.prev_=prev;args.active_=false;returnargs;}JS_ALWAYS_INLINECallArgsListCallArgsListFromVp(uintNargc,Value*vp,CallArgsList*prev){returnCallArgsListFromArgv(argc,vp+2,prev);}/*****************************************************************************/enumMaybeConstruct{NO_CONSTRUCT=0,/* == false */CONSTRUCT=0x80/* == StackFrame::CONSTRUCTING, asserted below */};enumExecuteType{EXECUTE_GLOBAL=0x1,/* == StackFrame::GLOBAL */EXECUTE_DIRECT_EVAL=0x8,/* == StackFrame::EVAL */EXECUTE_INDIRECT_EVAL=0x9,/* == StackFrame::GLOBAL | EVAL */EXECUTE_DEBUG=0x18/* == StackFrame::EVAL | DEBUGGER */};/*****************************************************************************/classStackFrame{public:enumFlags{/* Primary frame type */GLOBAL=0x1,/* frame pushed for a global script */FUNCTION=0x2,/* frame pushed for a scripted call */DUMMY=0x4,/* frame pushed for bookkeeping *//* Frame subtypes */EVAL=0x8,/* frame pushed for eval() or debugger eval */DEBUGGER=0x10,/* frame pushed for debugger eval */GENERATOR=0x20,/* frame is associated with a generator */FLOATING_GENERATOR=0x40,/* frame is is in generator obj, not on stack */CONSTRUCTING=0x80,/* frame is for a constructor invocation *//* Temporary frame states */YIELDING=0x100,/* js::Interpret dispatched JSOP_YIELD */FINISHED_IN_INTERP=0x200,/* set if frame finished in Interpret() *//* Concerning function arguments */OVERRIDE_ARGS=0x400,/* overridden arguments local variable */OVERFLOW_ARGS=0x800,/* numActualArgs > numFormalArgs */UNDERFLOW_ARGS=0x1000,/* numActualArgs < numFormalArgs *//* Lazy frame initialization */HAS_IMACRO_PC=0x2000,/* frame has imacpc value available */HAS_CALL_OBJ=0x4000,/* frame has a callobj reachable from scopeChain_ */HAS_ARGS_OBJ=0x8000,/* frame has an argsobj in StackFrame::args */HAS_HOOK_DATA=0x10000,/* frame has hookData_ set */HAS_ANNOTATION=0x20000,/* frame has annotation_ set */HAS_RVAL=0x40000,/* frame has rval_ set */HAS_SCOPECHAIN=0x80000,/* frame has scopeChain_ set */HAS_PREVPC=0x100000/* frame has prevpc_ set */};private:mutableuint32flags_;/* bits described by Flags */union{/* describes what code is executing in a */JSScript*script;/* global frame */JSFunction*fun;/* function frame, pre GetScopeChain */}exec;union{/* describes the arguments of a function */uintNnactual;/* before js_GetArgsObject */ArgumentsObject*obj;/* after js_GetArgsObject */JSScript*script;/* eval has no args, but needs a script */}args;mutableJSObject*scopeChain_;/* current scope chain */StackFrame*prev_;/* previous cx->regs->fp */void*ncode_;/* return address for method JIT *//* Lazily initialized */Valuerval_;/* return value of the frame */jsbytecode*prevpc_;/* pc of previous frame*/jsbytecode*imacropc_;/* pc of macro caller */void*hookData_;/* closure returned by call hook */void*annotation_;/* perhaps remove with bug 546848 */staticvoidstaticAsserts(){JS_STATIC_ASSERT(offsetof(StackFrame,rval_)%sizeof(Value)==0);JS_STATIC_ASSERT(sizeof(StackFrame)%sizeof(Value)==0);}inlinevoidinitPrev(JSContext*cx);jsbytecode*prevpcSlow();public:/* * Frame initialization * * After acquiring a pointer to an uninitialized stack frame on the VM * stack from StackSpace, these members are used to initialize the stack * frame before officially pushing the frame into the context. *//* Used for Invoke, Interpret, trace-jit LeaveTree, and method-jit stubs. */voidinitCallFrame(JSContext*cx,JSObject&callee,JSFunction*fun,JSScript*script,uint32nactual,StackFrame::Flagsflags);/* Used for SessionInvoke. */voidresetCallFrame(JSScript*script);/* Called by jit stubs and serve as a specification for jit-code. */voidinitJitFrameCallerHalf(StackFrame*prev,StackFrame::Flagsflags,void*ncode);voidinitJitFrameEarlyPrologue(JSFunction*fun,uint32nactual);boolinitJitFrameLatePrologue(JSContext*cx,Value**limit);/* Used for eval. */voidinitExecuteFrame(JSScript*script,StackFrame*prev,FrameRegs*regs,constValue&thisv,JSObject&scopeChain,ExecuteTypetype);/* Used when activating generators. */voidstealFrameAndSlots(Value*vp,StackFrame*otherfp,Value*othervp,Value*othersp);/* Perhaps one fine day we will remove dummy frames. */voidinitDummyFrame(JSContext*cx,JSObject&chain);/* * Stack frame type * * A stack frame may have one of three types, which determines which * members of the frame may be accessed and other invariants: * * global frame: execution of global code or an eval in global code * function frame: execution of function code or an eval in a function * dummy frame: bookkeeping frame (to be removed in bug 625199) */boolisFunctionFrame()const{return!!(flags_&FUNCTION);}boolisGlobalFrame()const{return!!(flags_&GLOBAL);}boolisDummyFrame()const{return!!(flags_&DUMMY);}boolisScriptFrame()const{boolretval=!!(flags_&(FUNCTION|GLOBAL));JS_ASSERT(retval==!isDummyFrame());returnretval;}/* * Eval frames * * As noted above, global and function frames may optionally be 'eval * frames'. Eval code shares its parent's arguments which means that the * arg-access members of StackFrame may not be used for eval frames. * Search for 'hasArgs' below for more details. * * A further sub-classification of eval frames is whether the frame was * pushed for an ES5 strict-mode eval(). */boolisEvalFrame()const{JS_ASSERT_IF(flags_&EVAL,isScriptFrame());returnflags_&EVAL;}boolisEvalInFunction()const{return(flags_&(EVAL|FUNCTION))==(EVAL|FUNCTION);}boolisNonEvalFunctionFrame()const{return(flags_&(FUNCTION|EVAL))==FUNCTION;}inlineboolisStrictEvalFrame()const{returnisEvalFrame()&&script()->strictModeCode;}boolisNonStrictEvalFrame()const{returnisEvalFrame()&&!script()->strictModeCode;}/* * Previous frame * * A frame's 'prev' frame is either null or the previous frame pointed to * by cx->regs->fp when this frame was pushed. Often, given two prev-linked * frames, the next-frame is a function or eval that was called by the * prev-frame, but not always: the prev-frame may have called a native that * reentered the VM through JS_CallFunctionValue on the same context * (without calling JS_SaveFrameChain) which pushed the next-frame. Thus, * 'prev' has little semantic meaning and basically just tells the VM what * to set cx->regs->fp to when this frame is popped. */StackFrame*prev()const{returnprev_;}inlinevoidresetGeneratorPrev(JSContext*cx);/* * Frame slots * * A frame's 'slots' are the fixed slots associated with the frame (like * local variables) followed by an expression stack holding temporary * values. A frame's 'base' is the base of the expression stack. */Value*slots()const{return(Value*)(this+1);}Value*base()const{returnslots()+script()->nfixed;}Value&varSlot(uintNi){JS_ASSERT(i<script()->nfixed);JS_ASSERT_IF(maybeFun(),i<script()->bindings.countVars());returnslots()[i];}/* * Script * * All function and global frames have an associated JSScript which holds * the bytecode being executed for the frame. *//* * Get the frame's current bytecode, assuming |this| is in |cx|. * * Beware, as the name implies, pcQuadratic can lead to quadratic behavior * in loops such as: * * for ( ...; fp; fp = fp->prev()) * ... fp->pcQuadratic(cx); * * For such situations, prefer FrameRegsIter; its amortized O(1). * * When I get to the bottom I go back to the top of the stack * Where I stop and I turn and I go right back * Till I get to the bottom and I see you again... */jsbytecode*pcQuadratic(JSContext*cx)const;jsbytecode*prevpc(){if(flags_&HAS_PREVPC)returnprevpc_;returnprevpcSlow();}JSScript*script()const{JS_ASSERT(isScriptFrame());returnisFunctionFrame()?isEvalFrame()?args.script:fun()->script():exec.script;}JSScript*functionScript()const{JS_ASSERT(isFunctionFrame());returnisEvalFrame()?args.script:fun()->script();}JSScript*globalScript()const{JS_ASSERT(isGlobalFrame());returnexec.script;}JSScript*maybeScript()const{returnisScriptFrame()?script():NULL;}size_tnumFixed()const{returnscript()->nfixed;}size_tnumSlots()const{returnscript()->nslots;}size_tnumGlobalVars()const{JS_ASSERT(isGlobalFrame());returnexec.script->nfixed;}/* * Function * * All function frames have an associated interpreted JSFunction. */JSFunction*fun()const{JS_ASSERT(isFunctionFrame());returnexec.fun;}JSFunction*maybeFun()const{returnisFunctionFrame()?fun():NULL;}/* * Arguments * * Only non-eval function frames have arguments. A frame follows its * arguments contiguously in memory. The arguments pushed by the caller are * the 'actual' arguments. The declared arguments of the callee are the * 'formal' arguments. When the caller passes less or equal actual * arguments, the actual and formal arguments are the same array (but with * different extents). When the caller passes too many arguments, the * formal subset of the actual arguments is copied onto the top of the * stack. This allows the engine to maintain a jit-time constant offset of * arguments from the frame pointer. Since the formal subset of the actual * arguments is potentially on the stack twice, it is important for all * reads/writes to refer to the same canonical memory location. * * An arguments object (the object returned by the 'arguments' keyword) is * lazily created, so a given function frame may or may not have one. *//* True if this frame has arguments. Contrast with hasArgsObj. */boolhasArgs()const{returnisNonEvalFunctionFrame();}uintNnumFormalArgs()const{JS_ASSERT(hasArgs());returnfun()->nargs;}Value&formalArg(uintNi)const{JS_ASSERT(i<numFormalArgs());returnformalArgs()[i];}Value*formalArgs()const{JS_ASSERT(hasArgs());return(Value*)this-numFormalArgs();}Value*formalArgsEnd()const{JS_ASSERT(hasArgs());return(Value*)this;}Value*maybeFormalArgs()const{return(flags_&(FUNCTION|EVAL))==FUNCTION?formalArgs():NULL;}inlineuintNnumActualArgs()const;inlineValue*actualArgs()const;inlineValue*actualArgsEnd()const;inlineValue&canonicalActualArg(uintNi)const;template<classOp>inlineboolforEachCanonicalActualArg(Opop,uintNstart=0,uintNcount=uintN(-1));template<classOp>inlineboolforEachFormalArg(Opop);boolhasArgsObj()const{return!!(flags_&HAS_ARGS_OBJ);}ArgumentsObject&argsObj()const{JS_ASSERT(hasArgsObj());JS_ASSERT(!isEvalFrame());return*args.obj;}ArgumentsObject*maybeArgsObj()const{returnhasArgsObj()?&argsObj():NULL;}inlinevoidsetArgsObj(ArgumentsObject&obj);/* * This value * * Every frame has a this value although, until 'this' is computed, the * value may not be the semantically-correct 'this' value. * * The 'this' value is stored before the formal arguments for function * frames and directly before the frame for global frames. The *Args * members assert !isEvalFrame(), so we implement specialized inline * methods for accessing 'this'. When the caller has static knowledge that * a frame is a function or global frame, 'functionThis' and 'globalThis', * respectively, allow more efficient access. */Value&functionThis()const{JS_ASSERT(isFunctionFrame());if(isEvalFrame())return((Value*)this)[-1];returnformalArgs()[-1];}JSObject&constructorThis()const{JS_ASSERT(hasArgs());returnformalArgs()[-1].toObject();}Value&globalThis()const{JS_ASSERT(isGlobalFrame());return((Value*)this)[-1];}Value&thisValue()const{if(flags_&(EVAL|GLOBAL))return((Value*)this)[-1];returnformalArgs()[-1];}/* * Callee * * Only function frames have a callee. An eval frame in a function has the * same caller as its containing function frame. maybeCalleev can be used * to return a value that is either caller object (for function frames) or * null (for global frames). */JSObject&callee()const{JS_ASSERT(isFunctionFrame());returncalleev().toObject();}constValue&calleev()const{JS_ASSERT(isFunctionFrame());returnmutableCalleev();}constValue&maybeCalleev()const{JS_ASSERT(isScriptFrame());Value&calleev=flags_&(EVAL|GLOBAL)?((Value*)this)[-2]:formalArgs()[-2];JS_ASSERT(calleev.isObjectOrNull());returncalleev;}/* * Beware! Ad hoc changes can corrupt the stack layout; the callee should * only be changed to something that is equivalent to the current callee in * terms of numFormalArgs etc. Prefer overwriteCallee since it checks. */voidoverwriteCallee(JSObject&newCallee){JS_ASSERT(callee().getFunctionPrivate()==newCallee.getFunctionPrivate());mutableCalleev().setObject(newCallee);}Value&mutableCalleev()const{JS_ASSERT(isFunctionFrame());if(isEvalFrame())return((Value*)this)[-2];returnformalArgs()[-2];}/* * Compute the callee function for this stack frame, cloning if needed to * implement the method read barrier. If this is not a function frame, * set *vp to null. */boolgetValidCalleeObject(JSContext*cx,Value*vp);CallReceivercallReceiver()const{returnCallReceiverFromArgv(formalArgs());}/* * Scope chain * * Every frame has a scopeChain which, when traversed via the 'parent' link * to the root, indicates the current global object. A 'call object' is a * node on a scope chain representing a function's activation record. A * call object is used for dynamically-scoped name lookup and lexically- * scoped upvar access. The call object holds the values of locals and * arguments when a function returns (and its stack frame is popped). For * performance reasons, call objects are created lazily for 'lightweight' * functions, i.e., functions which are not statically known to require a * call object. Thus, a given function frame may or may not have a call * object. When a function does have a call object, it is found by walking * up the scope chain until the first call object. Thus, it is important, * when setting the scope chain, to indicate whether the new scope chain * contains a new call object and thus changes the 'hasCallObj' state. * * NB: 'fp->hasCallObj()' implies that fp->callObj() needs to be 'put' when * the frame is popped. Since the scope chain of a non-strict eval frame * contains the call object of the parent (function) frame, it is possible * to have: * !fp->hasCall() && fp->scopeChain().isCall() */JSObject&scopeChain()const{JS_ASSERT_IF(!(flags_&HAS_SCOPECHAIN),isFunctionFrame());if(!(flags_&HAS_SCOPECHAIN)){scopeChain_=callee().getParent();flags_|=HAS_SCOPECHAIN;}return*scopeChain_;}boolhasCallObj()const{boolret=!!(flags_&HAS_CALL_OBJ);JS_ASSERT_IF(ret,!isNonStrictEvalFrame());returnret;}inlineJSObject&callObj()const;inlinevoidsetScopeChainNoCallObj(JSObject&obj);inlinevoidsetScopeChainWithOwnCallObj(JSObject&obj);/* * NB: putActivationObjects does not mark activation objects as having been * put (since the frame is about to be popped). */inlinevoidputActivationObjects();inlinevoidmarkActivationObjectsAsPut();/* * Variables object * * Given that a (non-dummy) StackFrame corresponds roughly to a ES5 * Execution Context (ES5 10.3), StackFrame::varObj corresponds to the * VariableEnvironment component of a Exection Context. Intuitively, the * variables object is where new bindings (variables and functions) are * stored. One might expect that this is either the callObj or * scopeChain.globalObj for function or global code, respectively, however * the JSAPI allows calls of Execute to specify a variables object on the * scope chain other than the call/global object. This allows embeddings to * run multiple scripts under the same global, each time using a new * variables object to collect and discard the script's global variables. */JSObject&varObj(){JSObject*obj=&scopeChain();while(!obj->isVarObj())obj=obj->getParent();return*obj;}/* * Frame compartment * * A stack frame's compartment is the frame's containing context's * compartment when the frame was pushed. */JSCompartment*compartment()const{JS_ASSERT_IF(isScriptFrame(),scopeChain().compartment()==script()->compartment);returnscopeChain().compartment();}/* * Imacropc * * A frame's IMacro pc is the bytecode address when an imacro started * executing (guaranteed non-null). An imacro does not push a frame, so * when the imacro finishes, the frame's IMacro pc becomes the current pc. */boolhasImacropc()const{returnflags_&HAS_IMACRO_PC;}jsbytecode*imacropc()const{JS_ASSERT(hasImacropc());returnimacropc_;}jsbytecode*maybeImacropc()const{returnhasImacropc()?imacropc():NULL;}voidclearImacropc(){flags_&=~HAS_IMACRO_PC;}voidsetImacropc(jsbytecode*pc){JS_ASSERT(pc);JS_ASSERT(!(flags_&HAS_IMACRO_PC));imacropc_=pc;flags_|=HAS_IMACRO_PC;}/* Annotation (will be removed after bug 546848) */void*annotation()const{return(flags_&HAS_ANNOTATION)?annotation_:NULL;}voidsetAnnotation(void*annot){flags_|=HAS_ANNOTATION;annotation_=annot;}/* Debugger hook data */boolhasHookData()const{return!!(flags_&HAS_HOOK_DATA);}void*hookData()const{JS_ASSERT(hasHookData());returnhookData_;}void*maybeHookData()const{returnhasHookData()?hookData_:NULL;}voidsetHookData(void*v){hookData_=v;flags_|=HAS_HOOK_DATA;}/* Return value */constValue&returnValue(){if(!(flags_&HAS_RVAL))rval_.setUndefined();returnrval_;}voidmarkReturnValue(){flags_|=HAS_RVAL;}voidsetReturnValue(constValue&v){rval_=v;markReturnValue();}voidclearReturnValue(){rval_.setUndefined();markReturnValue();}/* Native-code return address */void*nativeReturnAddress()const{returnncode_;}voidsetNativeReturnAddress(void*addr){ncode_=addr;}void**addressOfNativeReturnAddress(){return&ncode_;}/* * Generator-specific members * * A non-eval function frame may optionally be the activation of a * generator. For the most part, generator frames act like ordinary frames. * For exceptions, see js_FloatingFrameIfGenerator. */boolisGeneratorFrame()const{return!!(flags_&GENERATOR);}boolisFloatingGenerator()const{JS_ASSERT_IF(flags_&FLOATING_GENERATOR,isGeneratorFrame());return!!(flags_&FLOATING_GENERATOR);}voidinitFloatingGenerator(){JS_ASSERT(!(flags_&GENERATOR));flags_|=(GENERATOR|FLOATING_GENERATOR);}voidunsetFloatingGenerator(){flags_&=~FLOATING_GENERATOR;}voidsetFloatingGenerator(){flags_|=FLOATING_GENERATOR;}/* * js::Execute pushes both global and function frames (since eval() in a * function pushes a frame with isFunctionFrame() && isEvalFrame()). Most * code should not care where a frame was pushed, but if it is necessary to * pick out frames pushed by js::Execute, this is the right query: */boolisFramePushedByExecute()const{return!!(flags_&(GLOBAL|EVAL));}/* * Other flags */MaybeConstructisConstructing()const{JS_STATIC_ASSERT((int)CONSTRUCT==(int)CONSTRUCTING);JS_STATIC_ASSERT((int)NO_CONSTRUCT==0);returnMaybeConstruct(flags_&CONSTRUCTING);}boolisDebuggerFrame()const{return!!(flags_&DEBUGGER);}boolhasOverriddenArgs()const{return!!(flags_&OVERRIDE_ARGS);}boolhasOverflowArgs()const{return!!(flags_&OVERFLOW_ARGS);}voidsetOverriddenArgs(){flags_|=OVERRIDE_ARGS;}boolisYielding(){return!!(flags_&YIELDING);}voidsetYielding(){flags_|=YIELDING;}voidclearYielding(){flags_&=~YIELDING;}voidsetFinishedInInterpreter(){flags_|=FINISHED_IN_INTERP;}boolfinishedInInterpreter()const{return!!(flags_&FINISHED_IN_INTERP);}#ifdef DEBUG/* Poison scopeChain value set before a frame is flushed. */staticJSObject*constsInvalidScopeChain;#endifpublic:/* Public, but only for JIT use: */staticsize_toffsetOfFlags(){returnoffsetof(StackFrame,flags_);}staticsize_toffsetOfExec(){returnoffsetof(StackFrame,exec);}staticsize_toffsetOfArgs(){returnoffsetof(StackFrame,args);}void*addressOfArgs(){return&args;}staticsize_toffsetOfScopeChain(){returnoffsetof(StackFrame,scopeChain_);}JSObject**addressOfScopeChain(){JS_ASSERT(flags_&HAS_SCOPECHAIN);return&scopeChain_;}staticsize_toffsetOfPrev(){returnoffsetof(StackFrame,prev_);}staticsize_toffsetOfReturnValue(){returnoffsetof(StackFrame,rval_);}staticptrdiff_toffsetOfNcode(){returnoffsetof(StackFrame,ncode_);}staticptrdiff_toffsetOfCallee(JSFunction*fun){JS_ASSERT(fun!=NULL);return-(fun->nargs+2)*sizeof(Value);}staticptrdiff_toffsetOfThis(JSFunction*fun){returnfun==NULL?-1*ptrdiff_t(sizeof(Value)):-(fun->nargs+1)*ptrdiff_t(sizeof(Value));}staticptrdiff_toffsetOfFormalArg(JSFunction*fun,uintNi){JS_ASSERT(i<fun->nargs);return(-(int)fun->nargs+i)*sizeof(Value);}staticsize_toffsetOfFixed(uintNi){returnsizeof(StackFrame)+i*sizeof(Value);}#ifdef JS_METHODJITmjit::JITScript*jit(){returnscript()->getJIT(isConstructing());}#endifvoidmethodjitStaticAsserts();};staticconstsize_tVALUES_PER_STACK_FRAME=sizeof(StackFrame)/sizeof(Value);staticinlineuintNToReportFlags(MaybeConstructconstruct){returnuintN(construct);}staticinlineStackFrame::FlagsToFrameFlags(MaybeConstructconstruct){JS_STATIC_ASSERT((int)CONSTRUCT==(int)StackFrame::CONSTRUCTING);JS_STATIC_ASSERT((int)NO_CONSTRUCT==0);returnStackFrame::Flags(construct);}staticinlineMaybeConstructMaybeConstructFromBool(boolb){returnb?CONSTRUCT:NO_CONSTRUCT;}inlineStackFrame*Valueify(JSStackFrame*fp){return(StackFrame*)fp;}staticinlineJSStackFrame*Jsvalify(StackFrame*fp){return(JSStackFrame*)fp;}/*****************************************************************************/classFrameRegs{public:Value*sp;jsbytecode*pc;private:StackFrame*fp_;public:StackFrame*fp()const{returnfp_;}/* For jit use (need constant): */staticconstsize_toffsetOfFp=2*sizeof(void*);staticvoidstaticAssert(){JS_STATIC_ASSERT(offsetOfFp==offsetof(FrameRegs,fp_));}/* For generator: */voidrebaseFromTo(constFrameRegs&from,StackFrame&to){fp_=&to;sp=to.slots()+(from.sp-from.fp_->slots());pc=from.pc;JS_ASSERT(fp_);}/* For ContextStack: */voidpopFrame(Value*newsp){pc=fp_->prevpc();sp=newsp;fp_=fp_->prev();JS_ASSERT(fp_);}/* For FixupArity: */voidpopPartialFrame(Value*newsp){sp=newsp;fp_=fp_->prev();JS_ASSERT(fp_);}/* For stubs::CompileFunction, ContextStack: */voidprepareToRun(StackFrame&fp,JSScript*script){pc=script->code;sp=fp.slots()+script->nfixed;fp_=&fp;JS_ASSERT(fp_);}/* For pushDummyFrame: */voidinitDummyFrame(StackFrame&fp){pc=NULL;sp=fp.slots();fp_=&fp;JS_ASSERT(fp_);}};/*****************************************************************************/classStackSegment{/* Previous segment within same context stack. */StackSegment*constprevInContext_;/* Previous segment sequentially in memory. */StackSegment*constprevInMemory_;/* Execution registers for most recent script in this segment (or null). */FrameRegs*regs_;/* Call args for most recent native call in this segment (or null). */CallArgsList*calls_;public:StackSegment(StackSegment*prevInContext,StackSegment*prevInMemory,FrameRegs*regs,CallArgsList*calls):prevInContext_(prevInContext),prevInMemory_(prevInMemory),regs_(regs),calls_(calls){}/* A segment is followed in memory by the arguments of the first call. */Value*slotsBegin()const{return(Value*)(this+1);}/* Accessors. */FrameRegs&regs()const{JS_ASSERT(regs_);return*regs_;}FrameRegs*maybeRegs()const{returnregs_;}StackFrame*fp()const{returnregs_->fp();}StackFrame*maybefp()const{returnregs_?regs_->fp():NULL;}CallArgsList&calls()const{JS_ASSERT(calls_);return*calls_;}CallArgsList*maybeCalls()const{returncalls_;}Value*callArgv()const{returncalls_->argv();}Value*maybeCallArgv()const{returncalls_?calls_->argv():NULL;}StackSegment*prevInContext()const{returnprevInContext_;}StackSegment*prevInMemory()const{returnprevInMemory_;}voidrepointRegs(FrameRegs*regs){JS_ASSERT_IF(regs,regs->fp());regs_=regs;}boolisEmpty()const{return!calls_&&!regs_;}boolcontains(constStackFrame*fp)const;boolcontains(constFrameRegs*regs)const;boolcontains(constCallArgsList*call)const;StackFrame*computeNextFrame(constStackFrame*fp)const;Value*end()const;FrameRegs*pushRegs(FrameRegs&regs);voidpopRegs(FrameRegs*regs);voidpushCall(CallArgsList&callList);voidpointAtCall(CallArgsList&callList);voidpopCall();/* For jit access: */staticconstsize_toffsetOfRegs(){returnoffsetof(StackSegment,regs_);}};staticconstsize_tVALUES_PER_STACK_SEGMENT=sizeof(StackSegment)/sizeof(Value);JS_STATIC_ASSERT(sizeof(StackSegment)%sizeof(Value)==0);/*****************************************************************************/classStackSpace{StackSegment*seg_;Value*base_;mutableValue*conservativeEnd_;#ifdef XP_WINmutableValue*commitEnd_;#endifValue*defaultEnd_;Value*trustedEnd_;voidassertInvariants()const{JS_ASSERT(base_<=conservativeEnd_);#ifdef XP_WINJS_ASSERT(conservativeEnd_<=commitEnd_);JS_ASSERT(commitEnd_<=trustedEnd_);#endifJS_ASSERT(conservativeEnd_<=defaultEnd_);JS_ASSERT(defaultEnd_<=trustedEnd_);}/* The total number of values/bytes reserved for the stack. */staticconstsize_tCAPACITY_VALS=512*1024;staticconstsize_tCAPACITY_BYTES=CAPACITY_VALS*sizeof(Value);/* How much of the stack is initially committed. */staticconstsize_tCOMMIT_VALS=16*1024;staticconstsize_tCOMMIT_BYTES=COMMIT_VALS*sizeof(Value);/* How much space is reserved at the top of the stack for trusted JS. */staticconstsize_tBUFFER_VALS=16*1024;staticconstsize_tBUFFER_BYTES=BUFFER_VALS*sizeof(Value);staticvoidstaticAsserts(){JS_STATIC_ASSERT(CAPACITY_VALS%COMMIT_VALS==0);}friendclassAllFramesIter;friendclassContextStack;friendclassStackFrame;inlineboolensureSpace(JSContext*cx,MaybeReportErrorreport,Value*from,ptrdiff_tnvals,JSCompartment*dest)const;inlineboolensureSpace(JSContext*cx,MaybeReportErrorreport,Value*from,ptrdiff_tnvals)const;JS_FRIEND_API(bool)ensureSpaceSlow(JSContext*cx,MaybeReportErrorreport,Value*from,ptrdiff_tnvals,JSCompartment*dest)const;StackSegment&findContainingSegment(constStackFrame*target)const;public:StackSpace();boolinit();~StackSpace();/* * Maximum supported value of arguments.length. This bounds the maximum * number of arguments that can be supplied to Function.prototype.apply. * This value also bounds the number of elements parsed in an array * initialiser. * * Since arguments are copied onto the stack, the stack size is the * limiting factor for this constant. Use the max stack size (available to * untrusted code) with an extra buffer so that, after such an apply, the * callee can do a little work without OOMing. */staticconstuintNARGS_LENGTH_MAX=CAPACITY_VALS-(2*BUFFER_VALS);/* See stack layout comment above. */Value*firstUnused()const{returnseg_?seg_->end():base_;}#ifdef JS_TRACER/* * LeaveTree requires stack allocation to rebuild the stack. There is no * good way to handle an OOM for these allocations, so this function checks * that OOM cannot occur using the size of the TraceNativeStorage as a * conservative upper bound. * * Despite taking a 'cx', this function does not report an error if it * returns 'false'. */inlineboolensureEnoughSpaceToEnterTrace(JSContext*cx);#endif/* * Return a limit against which jit code can check for. This limit is not * necessarily the end of the stack since we lazily commit stack memory on * some platforms. Thus, when the stack limit is exceeded, the caller should * use tryBumpLimit to attempt to increase the stack limit by committing * more memory. If the stack is truly exhausted, tryBumpLimit will report an * error and return NULL. * * An invariant of the methodjit is that there is always space to push a * frame on top of the current frame's expression stack (which can be at * most script->nslots deep). getStackLimit ensures that the returned limit * does indeed have this required space and reports an error and returns * NULL if this reserve space cannot be allocated. */inlineValue*getStackLimit(JSContext*cx,MaybeReportErrorreport);booltryBumpLimit(JSContext*cx,Value*from,uintNnvals,Value**limit);/* Called during GC: mark segments, frames, and slots under firstUnused. */voidmark(JSTracer*trc);/* We only report the committed size; uncommitted size is uninteresting. */JS_FRIEND_API(size_t)committedSize();};/*****************************************************************************/classContextStack{StackSegment*seg_;StackSpace*space_;JSContext*cx_;/* * Return whether this ContextStack is at the top of the contiguous stack. * This is a precondition for extending the current segment by pushing * stack frames or overrides etc. * * NB: Just because a stack is onTop() doesn't mean there is necessarily * a frame pushed on the stack. For this, use hasfp(). */boolonTop()const;#ifdef DEBUGvoidassertSpaceInSync()const;#elsevoidassertSpaceInSync()const{}#endif/* Implementation details of push* public interface. */StackSegment*pushSegment(JSContext*cx);enumMaybeExtend{CAN_EXTEND=true,CANT_EXTEND=false};Value*ensureOnTop(JSContext*cx,MaybeReportErrorreport,uintNnvars,MaybeExtendextend,bool*pushedSeg,JSCompartment*dest);Value*ensureOnTop(JSContext*cx,MaybeReportErrorreport,uintNnvars,MaybeExtendextend,bool*pushedSeg);inlineStackFrame*getCallFrame(JSContext*cx,MaybeReportErrorreport,constCallArgs&args,JSFunction*fun,JSScript*script,StackFrame::Flags*pflags)const;/* Make pop* functions private since only called by guard classes. */voidpopSegment();friendclassInvokeArgsGuard;voidpopInvokeArgs(constInvokeArgsGuard&iag);friendclassFrameGuard;voidpopFrame(constFrameGuard&fg);friendclassGeneratorFrameGuard;voidpopGeneratorFrame(constGeneratorFrameGuard&gfg);friendclassStackIter;public:ContextStack(JSContext*cx);~ContextStack();/*** Stack accessors ***//* * A context's stack is "empty" if there are no scripts or natives * executing. Note that JS_SaveFrameChain does factor into this definition. */boolempty()const{return!seg_;}/* * Return whether there has been at least one frame pushed since the most * recent call to JS_SaveFrameChain. Note that natives do not have frames * and dummy frames are frames that do not represent script execution hence * this query has little semantic meaning past "you can call fp()". */boolhasfp()const{returnseg_&&seg_->maybeRegs();}/* * Return the most recent script activation's registers with the same * caveat as hasfp regarding JS_SaveFrameChain. */FrameRegs*maybeRegs()const{returnseg_?seg_->maybeRegs():NULL;}StackFrame*maybefp()const{returnseg_?seg_->maybefp():NULL;}/* Faster alternatives to maybe* functions. */FrameRegs&regs()const{JS_ASSERT(hasfp());returnseg_->regs();}StackFrame*fp()const{JS_ASSERT(hasfp());returnseg_->fp();}/* The StackSpace currently hosting this ContextStack. */StackSpace&space()const{assertSpaceInSync();return*space_;}/* Return whether the given frame is in this context's stack. */boolcontainsSlow(constStackFrame*target)const;/*** Stack manipulation ***//* * pushInvokeArgs allocates |argc + 2| rooted values that will be passed as * the arguments to Invoke. A single allocation can be used for multiple * Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from * an immediately-enclosing (stack-wise) call to pushInvokeArgs. */boolpushInvokeArgs(JSContext*cx,uintNargc,InvokeArgsGuard*ag);/* Called by Invoke for a scripted function call. */boolpushInvokeFrame(JSContext*cx,constCallArgs&args,MaybeConstructconstruct,InvokeFrameGuard*ifg);/* Called by Execute for execution of eval or global code. */boolpushExecuteFrame(JSContext*cx,JSScript*script,constValue&thisv,JSObject&scopeChain,ExecuteTypetype,StackFrame*evalInFrame,ExecuteFrameGuard*efg);/* * Called by SendToGenerator to resume a yielded generator. In addition to * pushing a frame onto the VM stack, this function copies over the * floating frame stored in 'gen'. When 'gfg' is destroyed, the destructor * will copy the frame back to the floating frame. */boolpushGeneratorFrame(JSContext*cx,JSGenerator*gen,GeneratorFrameGuard*gfg);/* * When changing the compartment of a cx, it is necessary to immediately * change the scope chain to a global in the right compartment since any * amount of general VM code can run before the first scripted frame is * pushed (if at all). This is currently and hackily accomplished by * pushing a "dummy frame" with the correct scope chain. On success, this * function will change the compartment to 'scopeChain.compartment()' and * push a dummy frame for 'scopeChain'. On failure, nothing is changed. */boolpushDummyFrame(JSContext*cx,JSObject&scopeChain,DummyFrameGuard*dfg);/* * An "inline frame" may only be pushed from within the top, active * segment. This is the case for calls made inside mjit code and Interpret. * The 'stackLimit' overload updates 'stackLimit' if it changes. */boolpushInlineFrame(JSContext*cx,FrameRegs&regs,constCallArgs&args,JSObject&callee,JSFunction*fun,JSScript*script,MaybeConstructconstruct);boolpushInlineFrame(JSContext*cx,FrameRegs&regs,constCallArgs&args,JSObject&callee,JSFunction*fun,JSScript*script,MaybeConstructconstruct,Value**stackLimit);voidpopInlineFrame(FrameRegs&regs);/* Pop a partially-pushed frame after hitting the limit before throwing. */voidpopFrameAfterOverflow();/* * Called by the methodjit for an arity mismatch. Arity mismatch can be * hot, so getFixupFrame avoids doing call setup performed by jit code when * FixupArity returns. In terms of work done: * * getFixupFrame = pushInlineFrame - * (fp->initJitFrameLatePrologue + regs->prepareToRun) */StackFrame*getFixupFrame(JSContext*cx,MaybeReportErrorreport,constCallArgs&args,JSFunction*fun,JSScript*script,void*ncode,MaybeConstructconstruct,Value**stackLimit);boolsaveFrameChain();voidrestoreFrameChain();/* * As an optimization, the interpreter/mjit can operate on a local * FrameRegs instance repoint the ContextStack to this local instance. */voidrepointRegs(FrameRegs*regs){JS_ASSERT(hasfp());seg_->repointRegs(regs);}/*** For JSContext: ***//* * To avoid indirection, ContextSpace caches a pointer to the StackSpace. * This must be kept coherent with cx->thread->data.space by calling * 'threadReset' whenver cx->thread changes. */voidthreadReset();/*** For jit compiler: ***/staticsize_toffsetOfSeg(){returnoffsetof(ContextStack,seg_);}};/*****************************************************************************/classInvokeArgsGuard:publicCallArgsList{friendclassContextStack;ContextStack*stack_;boolpushedSeg_;voidsetPushed(ContextStack&stack){JS_ASSERT(!pushed());stack_=&stack;}public:InvokeArgsGuard():CallArgsList(),stack_(NULL),pushedSeg_(false){}~InvokeArgsGuard(){if(pushed())stack_->popInvokeArgs(*this);}boolpushed()const{return!!stack_;}voidpop(){stack_->popInvokeArgs(*this);stack_=NULL;}};classFrameGuard{protected:friendclassContextStack;ContextStack*stack_;boolpushedSeg_;FrameRegsregs_;FrameRegs*prevRegs_;voidsetPushed(ContextStack&stack){stack_=&stack;}public:FrameGuard():stack_(NULL),pushedSeg_(false){}~FrameGuard(){if(pushed())stack_->popFrame(*this);}boolpushed()const{return!!stack_;}voidpop(){stack_->popFrame(*this);stack_=NULL;}StackFrame*fp()const{returnregs_.fp();}};classInvokeFrameGuard:publicFrameGuard{};classExecuteFrameGuard:publicFrameGuard{};classDummyFrameGuard:publicFrameGuard{};classGeneratorFrameGuard:publicFrameGuard{friendclassContextStack;JSGenerator*gen_;Value*stackvp_;public:~GeneratorFrameGuard(){if(pushed())stack_->popGeneratorFrame(*this);}};/*****************************************************************************//* * Iterate through the callstack of the given context. Each element of said * callstack can either be the execution of a script (scripted function call, * global code, eval code, debugger code) or the invocation of a (C++) native. * Example usage: * * for (Stackiter i(cx); !i.done(); ++i) { * if (i.isScript()) { * ... i.fp() ... i.sp() ... i.pc() * } else { * JS_ASSERT(i.isNativeCall()); * ... i.args(); * } * * The SavedOption parameter additionally lets the iterator continue through * breaks in the callstack (from JS_SaveFrameChain). The default is to stop. */classStackIter{friendclassContextStack;JSContext*cx_;public:enumSavedOption{STOP_AT_SAVED,GO_THROUGH_SAVED};private:SavedOptionsavedOption_;enumState{DONE,SCRIPTED,NATIVE,IMPLICIT_NATIVE};Statestate_;StackFrame*fp_;CallArgsList*calls_;StackSegment*seg_;Value*sp_;jsbytecode*pc_;CallArgsargs_;voidpoisonRegs();voidpopFrame();voidpopCall();voidsettleOnNewSegment();voidsettleOnNewState();voidstartOnSegment(StackSegment*seg);public:StackIter(JSContext*cx,SavedOption=STOP_AT_SAVED);booldone()const{returnstate_==DONE;}StackIter&operator++();booloperator==(constStackIter&rhs)const;booloperator!=(constStackIter&rhs)const{return!(*this==rhs);}boolisScript()const{JS_ASSERT(!done());returnstate_==SCRIPTED;}StackFrame*fp()const{JS_ASSERT(!done()&&isScript());returnfp_;}Value*sp()const{JS_ASSERT(!done()&&isScript());returnsp_;}jsbytecode*pc()const{JS_ASSERT(!done()&&isScript());returnpc_;}boolisNativeCall()const{JS_ASSERT(!done());returnstate_!=SCRIPTED;}CallArgsnativeArgs()const{JS_ASSERT(!done()&&isNativeCall());returnargs_;}};/* A filtering of the StackIter to only stop at scripts. */classFrameRegsIter{StackIteriter_;voidsettle(){while(!iter_.done()&&!iter_.isScript())++iter_;}public:FrameRegsIter(JSContext*cx):iter_(cx){settle();}booldone()const{returniter_.done();}FrameRegsIter&operator++(){++iter_;settle();return*this;}booloperator==(constFrameRegsIter&rhs)const{returniter_==rhs.iter_;}booloperator!=(constFrameRegsIter&rhs)const{returniter_!=rhs.iter_;}StackFrame*fp()const{returniter_.fp();}Value*sp()const{returniter_.sp();}jsbytecode*pc()const{returniter_.pc();}};/*****************************************************************************//* * Blindly iterate over all frames in the current thread's stack. These frames * can be from different contexts and compartments, so beware. */classAllFramesIter{public:AllFramesIter(StackSpace&space);booldone()const{returnfp_==NULL;}AllFramesIter&operator++();StackFrame*fp()const{returnfp_;}private:StackSegment*seg_;StackFrame*fp_;};}/* namespace js */#endif /* Stack_h__ */