2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 
   3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com) 
   4  *  Copyright (C) 2003, 2007, 2008, 2011 Apple Inc. All rights reserved. 
   6  *  This library is free software; you can redistribute it and/or 
   7  *  modify it under the terms of the GNU Library General Public 
   8  *  License as published by the Free Software Foundation; either 
   9  *  version 2 of the License, or (at your option) any later version. 
  11  *  This library is distributed in the hope that it will be useful, 
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
  14  *  Library General Public License for more details. 
  16  *  You should have received a copy of the GNU Library General Public License 
  17  *  along with this library; see the file COPYING.LIB.  If not, write to 
  18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
  19  *  Boston, MA 02110-1301, USA. 
  26 #include "AbstractPC.h" 
  27 #include "JSGlobalData.h" 
  28 #include "MacroAssemblerCodeRef.h" 
  29 #include "RegisterFile.h" 
  38     // Represents the current state of script execution. 
  39     // Passed as the first argument to most functions. 
  40     class ExecState 
: private Register 
{ 
  42         JSValue 
calleeAsValue() const { return this[RegisterFile::Callee
].jsValue(); } 
  43         JSObject
* callee() const { return this[RegisterFile::Callee
].function(); } 
  44         CodeBlock
* codeBlock() const { return this[RegisterFile::CodeBlock
].Register::codeBlock(); } 
  45         ScopeChainNode
* scopeChain() const 
  47             ASSERT(this[RegisterFile::ScopeChain
].Register::scopeChain()); 
  48             return this[RegisterFile::ScopeChain
].Register::scopeChain(); 
  51         // Global object in which execution began. 
  52         JSGlobalObject
* dynamicGlobalObject(); 
  54         // Global object in which the currently executing code was defined. 
  55         // Differs from dynamicGlobalObject() during function calls across web browser frames. 
  56         inline JSGlobalObject
* lexicalGlobalObject() const; 
  58         // Differs from lexicalGlobalObject because this will have DOM window shell rather than 
  59         // the actual DOM window, which can't be "this" for security reasons. 
  60         inline JSObject
* globalThisValue() const; 
  62         inline JSGlobalData
& globalData() const; 
  64         // Convenience functions for access to global data. 
  65         // It takes a few memory references to get from a call frame to the global data 
  66         // pointer, so these are inefficient, and should be used sparingly in new code. 
  67         // But they're used in many places in legacy code, so they're not going away any time soon. 
  69         void clearException() { globalData().exception 
= JSValue(); } 
  70         JSValue 
exception() const { return globalData().exception
; } 
  71         bool hadException() const { return globalData().exception
; } 
  73         const CommonIdentifiers
& propertyNames() const { return *globalData().propertyNames
; } 
  74         const MarkedArgumentBuffer
& emptyList() const { return *globalData().emptyList
; } 
  75         Interpreter
* interpreter() { return globalData().interpreter
; } 
  76         Heap
* heap() { return &globalData().heap
; } 
  80         static const HashTable
* arrayConstructorTable(CallFrame
* callFrame
) { return callFrame
->globalData().arrayConstructorTable
; } 
  81         static const HashTable
* arrayPrototypeTable(CallFrame
* callFrame
) { return callFrame
->globalData().arrayPrototypeTable
; } 
  82         static const HashTable
* booleanPrototypeTable(CallFrame
* callFrame
) { return callFrame
->globalData().booleanPrototypeTable
; } 
  83         static const HashTable
* dateTable(CallFrame
* callFrame
) { return callFrame
->globalData().dateTable
; } 
  84         static const HashTable
* dateConstructorTable(CallFrame
* callFrame
) { return callFrame
->globalData().dateConstructorTable
; } 
  85         static const HashTable
* errorPrototypeTable(CallFrame
* callFrame
) { return callFrame
->globalData().errorPrototypeTable
; } 
  86         static const HashTable
* globalObjectTable(CallFrame
* callFrame
) { return callFrame
->globalData().globalObjectTable
; } 
  87         static const HashTable
* jsonTable(CallFrame
* callFrame
) { return callFrame
->globalData().jsonTable
; } 
  88         static const HashTable
* mathTable(CallFrame
* callFrame
) { return callFrame
->globalData().mathTable
; } 
  89         static const HashTable
* numberConstructorTable(CallFrame
* callFrame
) { return callFrame
->globalData().numberConstructorTable
; } 
  90         static const HashTable
* numberPrototypeTable(CallFrame
* callFrame
) { return callFrame
->globalData().numberPrototypeTable
; } 
  91         static const HashTable
* objectConstructorTable(CallFrame
* callFrame
) { return callFrame
->globalData().objectConstructorTable
; } 
  92         static const HashTable
* objectPrototypeTable(CallFrame
* callFrame
) { return callFrame
->globalData().objectPrototypeTable
; } 
  93         static const HashTable
* regExpTable(CallFrame
* callFrame
) { return callFrame
->globalData().regExpTable
; } 
  94         static const HashTable
* regExpConstructorTable(CallFrame
* callFrame
) { return callFrame
->globalData().regExpConstructorTable
; } 
  95         static const HashTable
* regExpPrototypeTable(CallFrame
* callFrame
) { return callFrame
->globalData().regExpPrototypeTable
; } 
  96         static const HashTable
* stringTable(CallFrame
* callFrame
) { return callFrame
->globalData().stringTable
; } 
  97         static const HashTable
* stringConstructorTable(CallFrame
* callFrame
) { return callFrame
->globalData().stringConstructorTable
; } 
  99         static CallFrame
* create(Register
* callFrameBase
) { return static_cast<CallFrame
*>(callFrameBase
); } 
 100         Register
* registers() { return this; } 
 102         CallFrame
& operator=(const Register
& r
) { *static_cast<Register
*>(this) = r
; return *this; } 
 104         CallFrame
* callerFrame() const { return this[RegisterFile::CallerFrame
].callFrame(); } 
 106         ReturnAddressPtr 
returnPC() const { return ReturnAddressPtr(this[RegisterFile::ReturnPC
].vPC()); } 
 107         bool hasReturnPC() const { return !!this[RegisterFile::ReturnPC
].vPC(); } 
 108         void clearReturnPC() { registers()[RegisterFile::ReturnPC
] = static_cast<Instruction
*>(0); } 
 110         AbstractPC 
abstractReturnPC(JSGlobalData
& globalData
) { return AbstractPC(globalData
, this); } 
 111 #if USE(JSVALUE32_64) 
 112         unsigned bytecodeOffsetForNonDFGCode() const; 
 113         void setBytecodeOffsetForNonDFGCode(unsigned offset
); 
 115         unsigned bytecodeOffsetForNonDFGCode() const 
 118             return this[RegisterFile::ArgumentCount
].tag(); 
 121         void setBytecodeOffsetForNonDFGCode(unsigned offset
) 
 124             this[RegisterFile::ArgumentCount
].tag() = static_cast<int32_t>(offset
); 
 128         Register
* frameExtent() 
 132             return frameExtentInternal(); 
 135         Register
* frameExtentInternal(); 
 138         InlineCallFrame
* inlineCallFrame() const { return this[RegisterFile::ReturnPC
].asInlineCallFrame(); } 
 139         unsigned codeOriginIndexForDFG() const { return this[RegisterFile::ArgumentCount
].tag(); } 
 141         // This will never be called if !ENABLE(DFG_JIT) since all calls should be guarded by 
 142         // isInlineCallFrame(). But to make it easier to write code without having a bunch of 
 143         // #if's, we make a dummy implementation available anyway. 
 144         InlineCallFrame
* inlineCallFrame() const 
 146             ASSERT_NOT_REACHED(); 
 150 #if ENABLE(CLASSIC_INTERPRETER) 
 151         Instruction
* returnVPC() const { return this[RegisterFile::ReturnPC
].vPC(); } 
 153 #if USE(JSVALUE32_64) 
 154         Instruction
* currentVPC() const 
 156             return bitwise_cast
<Instruction
*>(this[RegisterFile::ArgumentCount
].tag()); 
 158         void setCurrentVPC(Instruction
* vpc
) 
 160             this[RegisterFile::ArgumentCount
].tag() = bitwise_cast
<int32_t>(vpc
); 
 163         Instruction
* currentVPC() const; 
 164         void setCurrentVPC(Instruction
* vpc
); 
 167         void setCallerFrame(CallFrame
* callerFrame
) { static_cast<Register
*>(this)[RegisterFile::CallerFrame
] = callerFrame
; } 
 168         void setScopeChain(ScopeChainNode
* scopeChain
) { static_cast<Register
*>(this)[RegisterFile::ScopeChain
] = scopeChain
; } 
 170         ALWAYS_INLINE 
void init(CodeBlock
* codeBlock
, Instruction
* vPC
, ScopeChainNode
* scopeChain
, 
 171             CallFrame
* callerFrame
, int argc
, JSObject
* callee
) 
 173             ASSERT(callerFrame
); // Use noCaller() rather than 0 for the outer host call frame caller. 
 174             ASSERT(callerFrame 
== noCaller() || callerFrame
->removeHostCallFrameFlag()->registerFile()->end() >= this); 
 176             setCodeBlock(codeBlock
); 
 177             setScopeChain(scopeChain
); 
 178             setCallerFrame(callerFrame
); 
 179             setReturnPC(vPC
); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*. 
 180             setArgumentCountIncludingThis(argc
); // original argument count (for the sake of the "arguments" object) 
 184         // Read a register from the codeframe (or constant from the CodeBlock). 
 185         inline Register
& r(int); 
 186         // Read a register for a non-constant  
 187         inline Register
& uncheckedR(int); 
 189         // Access to arguments. 
 190         size_t argumentCount() const { return argumentCountIncludingThis() - 1; } 
 191         size_t argumentCountIncludingThis() const { return this[RegisterFile::ArgumentCount
].payload(); } 
 192         static int argumentOffset(size_t argument
) { return s_firstArgumentOffset 
- argument
; } 
 193         static int argumentOffsetIncludingThis(size_t argument
) { return s_thisArgumentOffset 
- argument
; } 
 195         JSValue 
argument(size_t argument
) 
 197             if (argument 
>= argumentCount()) 
 198                  return jsUndefined(); 
 199             return this[argumentOffset(argument
)].jsValue(); 
 201         void setArgument(size_t argument
, JSValue value
) 
 203             this[argumentOffset(argument
)] = value
; 
 206         static int thisArgumentOffset() { return argumentOffsetIncludingThis(0); } 
 207         JSValue 
thisValue() { return this[thisArgumentOffset()].jsValue(); } 
 208         void setThisValue(JSValue value
) { this[thisArgumentOffset()] = value
; } 
 210         static int offsetFor(size_t argumentCountIncludingThis
) { return argumentCountIncludingThis 
+ RegisterFile::CallFrameHeaderSize
; } 
 212         // FIXME: Remove these. 
 213         int hostThisRegister() { return thisArgumentOffset(); } 
 214         JSValue 
hostThisValue() { return thisValue(); } 
 216         static CallFrame
* noCaller() { return reinterpret_cast<CallFrame
*>(HostCallFrameFlag
); } 
 218         bool hasHostCallFrameFlag() const { return reinterpret_cast<intptr_t>(this) & HostCallFrameFlag
; } 
 219         CallFrame
* addHostCallFrameFlag() const { return reinterpret_cast<CallFrame
*>(reinterpret_cast<intptr_t>(this) | HostCallFrameFlag
); } 
 220         CallFrame
* removeHostCallFrameFlag() { return reinterpret_cast<CallFrame
*>(reinterpret_cast<intptr_t>(this) & ~HostCallFrameFlag
); } 
 222         void setArgumentCountIncludingThis(int count
) { static_cast<Register
*>(this)[RegisterFile::ArgumentCount
].payload() = count
; } 
 223         void setCallee(JSObject
* callee
) { static_cast<Register
*>(this)[RegisterFile::Callee
] = Register::withCallee(callee
); } 
 224         void setCodeBlock(CodeBlock
* codeBlock
) { static_cast<Register
*>(this)[RegisterFile::CodeBlock
] = codeBlock
; } 
 225         void setReturnPC(void* value
) { static_cast<Register
*>(this)[RegisterFile::ReturnPC
] = (Instruction
*)value
; } 
 228         bool isInlineCallFrame(); 
 230         void setInlineCallFrame(InlineCallFrame
* inlineCallFrame
) { static_cast<Register
*>(this)[RegisterFile::ReturnPC
] = inlineCallFrame
; } 
 232         // Call this to get the semantically correct JS CallFrame* for the 
 233         // currently executing function. 
 234         CallFrame
* trueCallFrame(AbstractPC
); 
 236         // Call this to get the semantically correct JS CallFrame* corresponding 
 237         // to the caller. This resolves issues surrounding inlining and the 
 238         // HostCallFrameFlag stuff. 
 239         CallFrame
* trueCallerFrame(); 
 241         bool isInlineCallFrame() { return false; } 
 243         CallFrame
* trueCallFrame(AbstractPC
) { return this; } 
 244         CallFrame
* trueCallerFrame() { return callerFrame()->removeHostCallFrameFlag(); } 
 247         // Call this to get the true call frame (accounted for inlining and any 
 248         // other optimizations), when you have entered into VM code through one 
 249         // of the "blessed" entrypoints (JITStubs or DFGOperations). This means 
 250         // that if you're pretty much anywhere in the VM you can safely call this; 
 251         // though if you were to magically get an ExecState* by, say, interrupting 
 252         // a thread that is running JS code and brutishly scraped the call frame 
 253         // register, calling this method would probably lead to horrible things 
 255         CallFrame
* trueCallFrameFromVMCode() { return trueCallFrame(AbstractPC()); } 
 258         static const intptr_t HostCallFrameFlag 
= 1; 
 259         static const int s_thisArgumentOffset 
= -1 - RegisterFile::CallFrameHeaderSize
; 
 260         static const int s_firstArgumentOffset 
= s_thisArgumentOffset 
- 1; 
 263         RegisterFile
* registerFile(); 
 266         bool isInlineCallFrameSlow(); 
 274 #endif // CallFrame_h