1/* 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, 2013, 2014 Apple Inc. All rights reserved. 5 * 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. 10 * 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. 15 * 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. 20 * 21 */ 22 23#ifndef CallFrame_h 24#define CallFrame_h 25 26#include "AbstractPC.h" 27#include "VM.h" 28#include "JSStack.h" 29#include "MacroAssemblerCodeRef.h" 30#include "Register.h" 31#include "StackVisitor.h" 32 33namespace JSC { 34 35 class Arguments; 36 class JSActivation; 37 class Interpreter; 38 class JSScope; 39 40 // Represents the current state of script execution. 41 // Passed as the first argument to most functions. 42 class ExecState : private Register { 43 public: 44 JSValue calleeAsValue() const { return this[JSStack::Callee].jsValue(); } 45 JSObject* callee() const { return this[JSStack::Callee].function(); } 46 CodeBlock* codeBlock() const { return this[JSStack::CodeBlock].Register::codeBlock(); } 47 JSScope* scope() const 48 { 49 ASSERT(this[JSStack::ScopeChain].Register::scope()); 50 return this[JSStack::ScopeChain].Register::scope(); 51 } 52 53 bool hasActivation() const { return !!uncheckedActivation(); } 54 JSActivation* activation() const; 55 JSValue uncheckedActivation() const; 56 57 // Global object in which execution began. 58 JS_EXPORT_PRIVATE JSGlobalObject* vmEntryGlobalObject(); 59 60 // Global object in which the currently executing code was defined. 61 // Differs from vmEntryGlobalObject() during function calls across web browser frames. 62 JSGlobalObject* lexicalGlobalObject() const; 63 64 // Differs from lexicalGlobalObject because this will have DOM window shell rather than 65 // the actual DOM window, which can't be "this" for security reasons. 66 JSObject* globalThisValue() const; 67 68 VM& vm() const; 69 70 // Convenience functions for access to global data. 71 // It takes a few memory references to get from a call frame to the global data 72 // pointer, so these are inefficient, and should be used sparingly in new code. 73 // But they're used in many places in legacy code, so they're not going away any time soon. 74 75 void clearException() { vm().clearException(); } 76 void clearSupplementaryExceptionInfo() 77 { 78 vm().clearExceptionStack(); 79 } 80 81 JSValue exception() const { return vm().exception(); } 82 bool hadException() const { return !vm().exception().isEmpty(); } 83 84 AtomicStringTable* atomicStringTable() const { return vm().atomicStringTable(); } 85 const CommonIdentifiers& propertyNames() const { return *vm().propertyNames; } 86 const MarkedArgumentBuffer& emptyList() const { return *vm().emptyList; } 87 Interpreter* interpreter() { return vm().interpreter; } 88 Heap* heap() { return &vm().heap; } 89 90 static const HashTable& arrayConstructorTable(VM& vm) { return *vm.arrayConstructorTable; } 91 static const HashTable& arrayPrototypeTable(VM& vm) { return *vm.arrayPrototypeTable; } 92 static const HashTable& booleanPrototypeTable(VM& vm) { return *vm.booleanPrototypeTable; } 93 static const HashTable& dataViewTable(VM& vm) { return *vm.dataViewTable; } 94 static const HashTable& dateTable(VM& vm) { return *vm.dateTable; } 95 static const HashTable& dateConstructorTable(VM& vm) { return *vm.dateConstructorTable; } 96 static const HashTable& errorPrototypeTable(VM& vm) { return *vm.errorPrototypeTable; } 97 static const HashTable& globalObjectTable(VM& vm) { return *vm.globalObjectTable; } 98 static const HashTable& jsonTable(VM& vm) { return *vm.jsonTable; } 99 static const HashTable& numberConstructorTable(VM& vm) { return *vm.numberConstructorTable; } 100 static const HashTable& numberPrototypeTable(VM& vm) { return *vm.numberPrototypeTable; } 101 static const HashTable& objectConstructorTable(VM& vm) { return *vm.objectConstructorTable; } 102 static const HashTable& privateNamePrototypeTable(VM& vm) { return *vm.privateNamePrototypeTable; } 103 static const HashTable& regExpTable(VM& vm) { return *vm.regExpTable; } 104 static const HashTable& regExpConstructorTable(VM& vm) { return *vm.regExpConstructorTable; } 105 static const HashTable& regExpPrototypeTable(VM& vm) { return *vm.regExpPrototypeTable; } 106 static const HashTable& stringConstructorTable(VM& vm) { return *vm.stringConstructorTable; } 107#if ENABLE(PROMISES) 108 static const HashTable& promisePrototypeTable(VM& vm) { return *vm.promisePrototypeTable; } 109 static const HashTable& promiseConstructorTable(VM& vm) { return *vm.promiseConstructorTable; } 110#endif 111 112 static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); } 113 Register* registers() { return this; } 114 const Register* registers() const { return this; } 115 116 CallFrame& operator=(const Register& r) { *static_cast<Register*>(this) = r; return *this; } 117 118 CallFrame* callerFrame() const { return callerFrameAndPC().callerFrame; } 119 static ptrdiff_t callerFrameOffset() { return OBJECT_OFFSETOF(CallerFrameAndPC, callerFrame); } 120 121 ReturnAddressPtr returnPC() const { return ReturnAddressPtr(callerFrameAndPC().pc); } 122 bool hasReturnPC() const { return !!callerFrameAndPC().pc; } 123 void clearReturnPC() { callerFrameAndPC().pc = 0; } 124 static ptrdiff_t returnPCOffset() { return OBJECT_OFFSETOF(CallerFrameAndPC, pc); } 125 AbstractPC abstractReturnPC(VM& vm) { return AbstractPC(vm, this); } 126 127 class Location { 128 public: 129 static inline uint32_t decode(uint32_t bits); 130 131 static inline bool isBytecodeLocation(uint32_t bits); 132#if USE(JSVALUE64) 133 static inline uint32_t encodeAsBytecodeOffset(uint32_t bits); 134#else 135 static inline uint32_t encodeAsBytecodeInstruction(Instruction*); 136#endif 137 138 static inline bool isCodeOriginIndex(uint32_t bits); 139 static inline uint32_t encodeAsCodeOriginIndex(uint32_t bits); 140 141 private: 142 enum TypeTag { 143 BytecodeLocationTag = 0, 144 CodeOriginIndexTag = 1, 145 }; 146 147 static inline uint32_t encode(TypeTag, uint32_t bits); 148 149 static const uint32_t s_mask = 0x1; 150#if USE(JSVALUE64) 151 static const uint32_t s_shift = 31; 152 static const uint32_t s_shiftedMask = s_mask << s_shift; 153#else 154 static const uint32_t s_shift = 1; 155#endif 156 }; 157 158 bool hasLocationAsBytecodeOffset() const; 159 bool hasLocationAsCodeOriginIndex() const; 160 161 unsigned locationAsRawBits() const; 162 unsigned locationAsBytecodeOffset() const; 163 unsigned locationAsCodeOriginIndex() const; 164 165 void setLocationAsRawBits(unsigned); 166 void setLocationAsBytecodeOffset(unsigned); 167 168#if ENABLE(DFG_JIT) 169 unsigned bytecodeOffsetFromCodeOriginIndex(); 170#endif 171 172 // This will try to get you the bytecode offset, but you should be aware that 173 // this bytecode offset may be bogus in the presence of inlining. This will 174 // also return 0 if the call frame has no notion of bytecode offsets (for 175 // example if it's native code). 176 // https://bugs.webkit.org/show_bug.cgi?id=121754 177 unsigned bytecodeOffset(); 178 179 // This will get you a CodeOrigin. It will always succeed. May return 180 // CodeOrigin(0) if we're in native code. 181 CodeOrigin codeOrigin(); 182 183 Register* topOfFrame() 184 { 185 if (isVMEntrySentinel() || !codeBlock()) 186 return registers(); 187 return topOfFrameInternal(); 188 } 189 190#if USE(JSVALUE32_64) 191 Instruction* currentVPC() const 192 { 193 ASSERT(!isVMEntrySentinel()); 194 return bitwise_cast<Instruction*>(this[JSStack::ArgumentCount].tag()); 195 } 196 void setCurrentVPC(Instruction* vpc) 197 { 198 ASSERT(!isVMEntrySentinel()); 199 this[JSStack::ArgumentCount].tag() = bitwise_cast<int32_t>(vpc); 200 } 201#else 202 Instruction* currentVPC() const; 203 void setCurrentVPC(Instruction* vpc); 204#endif 205 206 void setCallerFrame(CallFrame* frame) { callerFrameAndPC().callerFrame = frame; } 207 void setScope(JSScope* scope) { static_cast<Register*>(this)[JSStack::ScopeChain] = scope; } 208 void setActivation(JSActivation*); 209 210 ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, JSScope* scope, 211 CallFrame* callerFrame, int argc, JSObject* callee) 212 { 213 ASSERT(callerFrame == noCaller() || callerFrame->isVMEntrySentinel() || callerFrame->stack()->containsAddress(this)); 214 215 setCodeBlock(codeBlock); 216 setScope(scope); 217 setCallerFrame(callerFrame); 218 setReturnPC(vPC); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*. 219 setArgumentCountIncludingThis(argc); // original argument count (for the sake of the "arguments" object) 220 setCallee(callee); 221 } 222 223 // Read a register from the codeframe (or constant from the CodeBlock). 224 Register& r(int); 225 // Read a register for a non-constant 226 Register& uncheckedR(int); 227 228 // Access to arguments as passed. (After capture, arguments may move to a different location.) 229 size_t argumentCount() const { return argumentCountIncludingThis() - 1; } 230 size_t argumentCountIncludingThis() const { return this[JSStack::ArgumentCount].payload(); } 231 static int argumentOffset(int argument) { return (JSStack::FirstArgument + argument); } 232 static int argumentOffsetIncludingThis(int argument) { return (JSStack::ThisArgument + argument); } 233 234 // In the following (argument() and setArgument()), the 'argument' 235 // parameter is the index of the arguments of the target function of 236 // this frame. The index starts at 0 for the first arg, 1 for the 237 // second, etc. 238 // 239 // The arguments (in this case) do not include the 'this' value. 240 // arguments(0) will not fetch the 'this' value. To get/set 'this', 241 // use thisValue() and setThisValue() below. 242 243 JSValue argument(size_t argument) 244 { 245 if (argument >= argumentCount()) 246 return jsUndefined(); 247 return getArgumentUnsafe(argument); 248 } 249 JSValue uncheckedArgument(size_t argument) 250 { 251 ASSERT(argument < argumentCount()); 252 return getArgumentUnsafe(argument); 253 } 254 void setArgument(size_t argument, JSValue value) 255 { 256 this[argumentOffset(argument)] = value; 257 } 258 259 static int thisArgumentOffset() { return argumentOffsetIncludingThis(0); } 260 JSValue thisValue() { return this[thisArgumentOffset()].jsValue(); } 261 void setThisValue(JSValue value) { this[thisArgumentOffset()] = value; } 262 263 JSValue argumentAfterCapture(size_t argument); 264 265 static int offsetFor(size_t argumentCountIncludingThis) { return argumentCountIncludingThis + JSStack::ThisArgument - 1; } 266 267 static CallFrame* noCaller() { return 0; } 268 269 bool isVMEntrySentinel() const 270 { 271 return !!this && codeBlock() == vmEntrySentinelCodeBlock(); 272 } 273 274 CallFrame* vmEntrySentinelCallerFrame() const 275 { 276 ASSERT(isVMEntrySentinel()); 277 return this[JSStack::ScopeChain].callFrame(); 278 } 279 280 void initializeVMEntrySentinelFrame(CallFrame* callFrame) 281 { 282 setCallerFrame(noCaller()); 283 setReturnPC(0); 284 setCodeBlock(vmEntrySentinelCodeBlock()); 285 static_cast<Register*>(this)[JSStack::ScopeChain] = callFrame; 286 setCallee(0); 287 setArgumentCountIncludingThis(0); 288 } 289 290 CallFrame* callerFrameSkippingVMEntrySentinel() 291 { 292 CallFrame* caller = callerFrame(); 293 if (caller->isVMEntrySentinel()) 294 return caller->vmEntrySentinelCallerFrame(); 295 return caller; 296 } 297 298 void setArgumentCountIncludingThis(int count) { static_cast<Register*>(this)[JSStack::ArgumentCount].payload() = count; } 299 void setCallee(JSObject* callee) { static_cast<Register*>(this)[JSStack::Callee] = Register::withCallee(callee); } 300 void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[JSStack::CodeBlock] = codeBlock; } 301 void setReturnPC(void* value) { callerFrameAndPC().pc = reinterpret_cast<Instruction*>(value); } 302 303 // CallFrame::iterate() expects a Functor that implements the following method: 304 // StackVisitor::Status operator()(StackVisitor&); 305 306 template <typename Functor> void iterate(Functor& functor) 307 { 308 StackVisitor::visit<Functor>(this, functor); 309 } 310 311 void dump(PrintStream&); 312 JS_EXPORT_PRIVATE const char* describeFrame(); 313 314 private: 315 static const intptr_t s_VMEntrySentinel = 1; 316 317#ifndef NDEBUG 318 JSStack* stack(); 319#endif 320 ExecState(); 321 ~ExecState(); 322 323 Register* topOfFrameInternal(); 324 325 // The following are for internal use in debugging and verification 326 // code only and not meant as an API for general usage: 327 328 size_t argIndexForRegister(Register* reg) 329 { 330 // The register at 'offset' number of slots from the frame pointer 331 // i.e. 332 // reg = frame[offset]; 333 // ==> reg = frame + offset; 334 // ==> offset = reg - frame; 335 int offset = reg - this->registers(); 336 337 // The offset is defined (based on argumentOffset()) to be: 338 // offset = JSStack::FirstArgument - argIndex; 339 // Hence: 340 // argIndex = JSStack::FirstArgument - offset; 341 size_t argIndex = offset - JSStack::FirstArgument; 342 return argIndex; 343 } 344 345 JSValue getArgumentUnsafe(size_t argIndex) 346 { 347 // User beware! This method does not verify that there is a valid 348 // argument at the specified argIndex. This is used for debugging 349 // and verification code only. The caller is expected to know what 350 // he/she is doing when calling this method. 351 return this[argumentOffset(argIndex)].jsValue(); 352 } 353 354 CallerFrameAndPC& callerFrameAndPC() { return *reinterpret_cast<CallerFrameAndPC*>(this); } 355 const CallerFrameAndPC& callerFrameAndPC() const { return *reinterpret_cast<const CallerFrameAndPC*>(this); } 356 357 static CodeBlock* vmEntrySentinelCodeBlock() { return reinterpret_cast<CodeBlock*>(s_VMEntrySentinel); } 358 359 friend class JSStack; 360 friend class VMInspector; 361 }; 362 363} // namespace JSC 364 365#endif // CallFrame_h 366