/ interpreter / CallFrame.cpp
CallFrame.cpp
1 /* 2 * Copyright (C) 2008-2018 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "CallFrame.h" 28 29 #include "CodeBlock.h" 30 #include "ExecutableAllocator.h" 31 #include "InlineCallFrame.h" 32 #include "JSCInlines.h" 33 #include "JSWebAssemblyInstance.h" 34 #include "LLIntPCRanges.h" 35 #include "VMEntryRecord.h" 36 #include "WasmContextInlines.h" 37 #include "WasmInstance.h" 38 #include <wtf/StringPrintStream.h> 39 40 namespace JSC { 41 42 void CallFrame::initDeprecatedCallFrameForDebugger(CallFrame* globalExec, JSCallee* globalCallee) 43 { 44 globalExec->setCodeBlock(nullptr); 45 globalExec->setCallerFrame(noCaller()); 46 globalExec->setReturnPC(nullptr); 47 globalExec->setArgumentCountIncludingThis(0); 48 globalExec->setCallee(globalCallee); 49 ASSERT(globalExec->isDeprecatedCallFrameForDebugger()); 50 } 51 52 bool CallFrame::callSiteBitsAreBytecodeOffset() const 53 { 54 ASSERT(codeBlock()); 55 switch (codeBlock()->jitType()) { 56 case JITType::InterpreterThunk: 57 case JITType::BaselineJIT: 58 return true; 59 case JITType::None: 60 case JITType::HostCallThunk: 61 RELEASE_ASSERT_NOT_REACHED(); 62 return false; 63 default: 64 return false; 65 } 66 67 RELEASE_ASSERT_NOT_REACHED(); 68 return false; 69 } 70 71 bool CallFrame::callSiteBitsAreCodeOriginIndex() const 72 { 73 ASSERT(codeBlock()); 74 switch (codeBlock()->jitType()) { 75 case JITType::DFGJIT: 76 case JITType::FTLJIT: 77 return true; 78 case JITType::None: 79 case JITType::HostCallThunk: 80 RELEASE_ASSERT_NOT_REACHED(); 81 return false; 82 default: 83 return false; 84 } 85 86 RELEASE_ASSERT_NOT_REACHED(); 87 return false; 88 } 89 90 unsigned CallFrame::callSiteAsRawBits() const 91 { 92 return this[static_cast<int>(CallFrameSlot::argumentCountIncludingThis)].tag(); 93 } 94 95 SUPPRESS_ASAN unsigned CallFrame::unsafeCallSiteAsRawBits() const 96 { 97 return this[static_cast<int>(CallFrameSlot::argumentCountIncludingThis)].unsafeTag(); 98 } 99 100 CallSiteIndex CallFrame::callSiteIndex() const 101 { 102 return CallSiteIndex::fromBits(callSiteAsRawBits()); 103 } 104 105 SUPPRESS_ASAN CallSiteIndex CallFrame::unsafeCallSiteIndex() const 106 { 107 return CallSiteIndex::fromBits(unsafeCallSiteAsRawBits()); 108 } 109 110 const Instruction* CallFrame::currentVPC() const 111 { 112 ASSERT(callSiteBitsAreBytecodeOffset()); 113 return codeBlock()->instructions().at(callSiteBitsAsBytecodeOffset()).ptr(); 114 } 115 116 void CallFrame::setCurrentVPC(const Instruction* vpc) 117 { 118 CallSiteIndex callSite(codeBlock()->bytecodeIndex(vpc)); 119 this[static_cast<int>(CallFrameSlot::argumentCountIncludingThis)].tag() = callSite.bits(); 120 ASSERT(currentVPC() == vpc); 121 } 122 123 unsigned CallFrame::callSiteBitsAsBytecodeOffset() const 124 { 125 ASSERT(codeBlock()); 126 ASSERT(callSiteBitsAreBytecodeOffset()); 127 return callSiteIndex().bits(); 128 } 129 130 BytecodeIndex CallFrame::bytecodeIndex() const 131 { 132 ASSERT(!callee().isWasm()); 133 if (!codeBlock()) 134 return BytecodeIndex(0); 135 #if ENABLE(DFG_JIT) 136 if (callSiteBitsAreCodeOriginIndex()) { 137 ASSERT(codeBlock()); 138 CodeOrigin codeOrigin = this->codeOrigin(); 139 for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame(); inlineCallFrame;) { 140 codeOrigin = inlineCallFrame->directCaller; 141 inlineCallFrame = codeOrigin.inlineCallFrame(); 142 } 143 return codeOrigin.bytecodeIndex(); 144 } 145 #endif 146 ASSERT(callSiteBitsAreBytecodeOffset()); 147 return callSiteIndex().bytecodeIndex(); 148 } 149 150 CodeOrigin CallFrame::codeOrigin() const 151 { 152 if (!codeBlock()) 153 return CodeOrigin(BytecodeIndex(0)); 154 #if ENABLE(DFG_JIT) 155 if (callSiteBitsAreCodeOriginIndex()) { 156 CallSiteIndex index = callSiteIndex(); 157 ASSERT(codeBlock()->canGetCodeOrigin(index)); 158 return codeBlock()->codeOrigin(index); 159 } 160 #endif 161 return CodeOrigin(callSiteIndex().bytecodeIndex()); 162 } 163 164 Register* CallFrame::topOfFrameInternal() 165 { 166 CodeBlock* codeBlock = this->codeBlock(); 167 ASSERT(codeBlock); 168 return registers() + codeBlock->stackPointerOffset(); 169 } 170 171 bool CallFrame::isAnyWasmCallee() 172 { 173 CalleeBits callee = this->callee(); 174 if (callee.isWasm()) 175 return true; 176 177 ASSERT(callee.isCell()); 178 if (!!callee.rawPtr() && isWebAssemblyModule(callee.asCell())) 179 return true; 180 181 return false; 182 } 183 184 CallFrame* CallFrame::callerFrame(EntryFrame*& currEntryFrame) const 185 { 186 if (callerFrameOrEntryFrame() == currEntryFrame) { 187 VMEntryRecord* currVMEntryRecord = vmEntryRecord(currEntryFrame); 188 currEntryFrame = currVMEntryRecord->prevTopEntryFrame(); 189 return currVMEntryRecord->prevTopCallFrame(); 190 } 191 return static_cast<CallFrame*>(callerFrameOrEntryFrame()); 192 } 193 194 SUPPRESS_ASAN CallFrame* CallFrame::unsafeCallerFrame(EntryFrame*& currEntryFrame) const 195 { 196 if (unsafeCallerFrameOrEntryFrame() == currEntryFrame) { 197 VMEntryRecord* currVMEntryRecord = vmEntryRecord(currEntryFrame); 198 currEntryFrame = currVMEntryRecord->unsafePrevTopEntryFrame(); 199 return currVMEntryRecord->unsafePrevTopCallFrame(); 200 } 201 return static_cast<CallFrame*>(unsafeCallerFrameOrEntryFrame()); 202 } 203 204 SourceOrigin CallFrame::callerSourceOrigin(VM& vm) 205 { 206 RELEASE_ASSERT(callee().isCell()); 207 SourceOrigin sourceOrigin; 208 bool haveSkippedFirstFrame = false; 209 StackVisitor::visit(this, vm, [&](StackVisitor& visitor) { 210 if (!std::exchange(haveSkippedFirstFrame, true)) 211 return StackVisitor::Status::Continue; 212 213 switch (visitor->codeType()) { 214 case StackVisitor::Frame::CodeType::Function: 215 // Skip the builtin functions since they should not pass the source origin to the dynamic code generation calls. 216 // Consider the following code. 217 // 218 // [ "42 + 44" ].forEach(eval); 219 // 220 // In the above case, the eval function will be interpreted as the indirect call to eval inside forEach function. 221 // At that time, the generated eval code should have the source origin to the original caller of the forEach function 222 // instead of the source origin of the forEach function. 223 if (static_cast<FunctionExecutable*>(visitor->codeBlock()->ownerExecutable())->isBuiltinFunction()) 224 return StackVisitor::Status::Continue; 225 FALLTHROUGH; 226 227 case StackVisitor::Frame::CodeType::Eval: 228 case StackVisitor::Frame::CodeType::Module: 229 case StackVisitor::Frame::CodeType::Global: 230 sourceOrigin = visitor->codeBlock()->ownerExecutable()->sourceOrigin(); 231 return StackVisitor::Status::Done; 232 233 case StackVisitor::Frame::CodeType::Native: 234 return StackVisitor::Status::Continue; 235 236 case StackVisitor::Frame::CodeType::Wasm: 237 // FIXME: Should return the source origin for WASM. 238 return StackVisitor::Status::Done; 239 } 240 241 RELEASE_ASSERT_NOT_REACHED(); 242 return StackVisitor::Status::Done; 243 }); 244 return sourceOrigin; 245 } 246 247 String CallFrame::friendlyFunctionName() 248 { 249 CodeBlock* codeBlock = this->codeBlock(); 250 if (!codeBlock) 251 return emptyString(); 252 253 switch (codeBlock->codeType()) { 254 case EvalCode: 255 return "eval code"_s; 256 case ModuleCode: 257 return "module code"_s; 258 case GlobalCode: 259 return "global code"_s; 260 case FunctionCode: 261 if (jsCallee()) 262 return getCalculatedDisplayName(codeBlock->vm(), jsCallee()); 263 return emptyString(); 264 } 265 266 ASSERT_NOT_REACHED(); 267 return emptyString(); 268 } 269 270 void CallFrame::dump(PrintStream& out) const 271 { 272 if (CodeBlock* codeBlock = this->codeBlock()) { 273 out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), " ", bytecodeIndex(), "]"); 274 275 out.print("("); 276 thisValue().dumpForBacktrace(out); 277 278 for (size_t i = 0; i < argumentCount(); ++i) { 279 out.print(", "); 280 JSValue value = argument(i); 281 value.dumpForBacktrace(out); 282 } 283 284 out.print(")"); 285 286 return; 287 } 288 289 out.print(returnPC()); 290 } 291 292 const char* CallFrame::describeFrame() 293 { 294 constexpr size_t bufferSize = 200; 295 static char* buffer = nullptr; 296 static std::once_flag onceKey; 297 std::call_once(onceKey, [&] { 298 buffer = static_cast<char*>(fastZeroedMalloc(bufferSize + 1)); 299 }); 300 301 WTF::StringPrintStream stringStream; 302 303 dump(stringStream); 304 305 strncpy(buffer, stringStream.toCString().data(), bufferSize); 306 buffer[bufferSize] = '\0'; 307 308 return buffer; 309 } 310 311 void CallFrame::convertToStackOverflowFrame(VM& vm, CodeBlock* codeBlockToKeepAliveUntilFrameIsUnwound) 312 { 313 ASSERT(!isDeprecatedCallFrameForDebugger()); 314 ASSERT(codeBlockToKeepAliveUntilFrameIsUnwound->inherits<CodeBlock>(vm)); 315 316 EntryFrame* entryFrame = vm.topEntryFrame; 317 CallFrame* throwOriginFrame = this; 318 do { 319 throwOriginFrame = throwOriginFrame->callerFrame(entryFrame); 320 } while (throwOriginFrame && throwOriginFrame->callee().isWasm()); 321 322 JSObject* originCallee = throwOriginFrame ? throwOriginFrame->jsCallee() : vmEntryRecord(vm.topEntryFrame)->callee(); 323 JSObject* stackOverflowCallee = originCallee->globalObject()->stackOverflowFrameCallee(); 324 325 setCodeBlock(codeBlockToKeepAliveUntilFrameIsUnwound); 326 setCallee(stackOverflowCallee); 327 setArgumentCountIncludingThis(0); 328 } 329 330 #if ENABLE(WEBASSEMBLY) 331 JSGlobalObject* CallFrame::lexicalGlobalObjectFromWasmCallee(VM& vm) const 332 { 333 return vm.wasmContext.load()->owner<JSWebAssemblyInstance>()->globalObject(); 334 } 335 #endif 336 337 bool isFromJSCode(void* returnAddress) 338 { 339 UNUSED_PARAM(returnAddress); 340 #if ENABLE(JIT) 341 if (isJITPC(returnAddress)) 342 return true; 343 #endif 344 #if ENABLE(C_LOOP) 345 return true; 346 #else 347 return LLInt::isLLIntPC(returnAddress); 348 #endif 349 } 350 351 } // namespace JSC