diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/interpreter/CallFrame.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/interpreter/CallFrame.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/CallFrame.cpp | 281 |
1 files changed, 233 insertions, 48 deletions
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.cpp b/Source/JavaScriptCore/interpreter/CallFrame.cpp index a226e9848..de57c0100 100644 --- a/Source/JavaScriptCore/interpreter/CallFrame.cpp +++ b/Source/JavaScriptCore/interpreter/CallFrame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2013-2014, 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,80 +26,140 @@ #include "config.h" #include "CallFrame.h" -#include "CallFrameInlines.h" #include "CodeBlock.h" +#include "InlineCallFrame.h" #include "Interpreter.h" -#include "Operations.h" +#include "JSCInlines.h" #include "VMEntryScope.h" +#include <wtf/StringPrintStream.h> namespace JSC { -#ifndef NDEBUG -JSStack* CallFrame::stack() +void ExecState::initGlobalExec(ExecState* globalExec, JSCallee* globalCallee) { - return &interpreter()->stack(); + globalExec->setCodeBlock(nullptr); + globalExec->setCallerFrame(noCaller()); + globalExec->setReturnPC(0); + globalExec->setArgumentCountIncludingThis(0); + globalExec->setCallee(globalCallee); } -#endif - -#if USE(JSVALUE32_64) -unsigned CallFrame::locationAsBytecodeOffset() const +bool CallFrame::callSiteBitsAreBytecodeOffset() const { ASSERT(codeBlock()); - ASSERT(hasLocationAsBytecodeOffset()); - return currentVPC() - codeBlock()->instructions().begin(); + switch (codeBlock()->jitType()) { + case JITCode::InterpreterThunk: + case JITCode::BaselineJIT: + return true; + case JITCode::None: + case JITCode::HostCallThunk: + RELEASE_ASSERT_NOT_REACHED(); + return false; + default: + return false; + } + + RELEASE_ASSERT_NOT_REACHED(); + return false; } -void CallFrame::setLocationAsBytecodeOffset(unsigned offset) +bool CallFrame::callSiteBitsAreCodeOriginIndex() const { ASSERT(codeBlock()); - setCurrentVPC(codeBlock()->instructions().begin() + offset); - ASSERT(hasLocationAsBytecodeOffset()); + switch (codeBlock()->jitType()) { + case JITCode::DFGJIT: + case JITCode::FTLJIT: + return true; + case JITCode::None: + case JITCode::HostCallThunk: + RELEASE_ASSERT_NOT_REACHED(); + return false; + default: + return false; + } + + RELEASE_ASSERT_NOT_REACHED(); + return false; } -#else + +unsigned CallFrame::callSiteAsRawBits() const +{ + return this[CallFrameSlot::argumentCount].tag(); +} + +SUPPRESS_ASAN unsigned CallFrame::unsafeCallSiteAsRawBits() const +{ + return this[CallFrameSlot::argumentCount].unsafeTag(); +} + +CallSiteIndex CallFrame::callSiteIndex() const +{ + return CallSiteIndex(callSiteAsRawBits()); +} + +SUPPRESS_ASAN CallSiteIndex CallFrame::unsafeCallSiteIndex() const +{ + return CallSiteIndex(unsafeCallSiteAsRawBits()); +} + +#if USE(JSVALUE32_64) Instruction* CallFrame::currentVPC() const { - return codeBlock()->instructions().begin() + locationAsBytecodeOffset(); + return bitwise_cast<Instruction*>(callSiteIndex().bits()); } + void CallFrame::setCurrentVPC(Instruction* vpc) { - setLocationAsBytecodeOffset(vpc - codeBlock()->instructions().begin()); + CallSiteIndex callSite(vpc); + this[CallFrameSlot::argumentCount].tag() = callSite.bits(); } -#endif - -#if ENABLE(DFG_JIT) -unsigned CallFrame::bytecodeOffsetFromCodeOriginIndex() -{ - ASSERT(hasLocationAsCodeOriginIndex()); - CodeBlock* codeBlock = this->codeBlock(); - ASSERT(codeBlock); - CodeOrigin codeOrigin; - unsigned index = locationAsCodeOriginIndex(); - ASSERT(codeBlock->canGetCodeOrigin(index)); - codeOrigin = codeBlock->codeOrigin(index); +unsigned CallFrame::callSiteBitsAsBytecodeOffset() const +{ + ASSERT(codeBlock()); + ASSERT(callSiteBitsAreBytecodeOffset()); + return currentVPC() - codeBlock()->instructions().begin(); +} - for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { - if (inlineCallFrame->baselineCodeBlock() == codeBlock) - return codeOrigin.bytecodeIndex; +#else // USE(JSVALUE32_64) +Instruction* CallFrame::currentVPC() const +{ + ASSERT(callSiteBitsAreBytecodeOffset()); + return codeBlock()->instructions().begin() + callSiteBitsAsBytecodeOffset(); +} - codeOrigin = inlineCallFrame->caller; - inlineCallFrame = codeOrigin.inlineCallFrame; - } - return codeOrigin.bytecodeIndex; +void CallFrame::setCurrentVPC(Instruction* vpc) +{ + CallSiteIndex callSite(vpc - codeBlock()->instructions().begin()); + this[CallFrameSlot::argumentCount].tag() = static_cast<int32_t>(callSite.bits()); } -#endif // ENABLE(DFG_JIT) +unsigned CallFrame::callSiteBitsAsBytecodeOffset() const +{ + ASSERT(codeBlock()); + ASSERT(callSiteBitsAreBytecodeOffset()); + return callSiteIndex().bits(); +} +#endif + unsigned CallFrame::bytecodeOffset() { if (!codeBlock()) return 0; #if ENABLE(DFG_JIT) - if (hasLocationAsCodeOriginIndex()) - return bytecodeOffsetFromCodeOriginIndex(); + if (callSiteBitsAreCodeOriginIndex()) { + ASSERT(codeBlock()); + CodeOrigin codeOrigin = this->codeOrigin(); + for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { + codeOrigin = inlineCallFrame->directCaller; + inlineCallFrame = codeOrigin.inlineCallFrame; + } + return codeOrigin.bytecodeIndex; + } #endif - return locationAsBytecodeOffset(); + ASSERT(callSiteBitsAreBytecodeOffset()); + return callSiteBitsAsBytecodeOffset(); } CodeOrigin CallFrame::codeOrigin() @@ -107,26 +167,29 @@ CodeOrigin CallFrame::codeOrigin() if (!codeBlock()) return CodeOrigin(0); #if ENABLE(DFG_JIT) - if (hasLocationAsCodeOriginIndex()) { - unsigned index = locationAsCodeOriginIndex(); + if (callSiteBitsAreCodeOriginIndex()) { + CallSiteIndex index = callSiteIndex(); ASSERT(codeBlock()->canGetCodeOrigin(index)); return codeBlock()->codeOrigin(index); } #endif - return CodeOrigin(locationAsBytecodeOffset()); + return CodeOrigin(callSiteBitsAsBytecodeOffset()); } -Register* CallFrame::frameExtentInternal() +Register* CallFrame::topOfFrameInternal() { CodeBlock* codeBlock = this->codeBlock(); ASSERT(codeBlock); - return registers() + virtualRegisterForLocal(codeBlock->frameRegisterCount()).offset(); + return registers() + codeBlock->stackPointerOffset(); } JSGlobalObject* CallFrame::vmEntryGlobalObject() { - if (this == lexicalGlobalObject()->globalExec()) - return lexicalGlobalObject(); + if (callee()->isObject()) { + if (this == lexicalGlobalObject()->globalExec()) + return lexicalGlobalObject(); + } + // If we're not an object, we're wasm, and therefore we're executing code and the below is safe. // For any ExecState that's not a globalExec, the // dynamic global object must be set since code is running @@ -134,4 +197,126 @@ JSGlobalObject* CallFrame::vmEntryGlobalObject() return vm().entryScope->globalObject(); } +CallFrame* CallFrame::callerFrame(VMEntryFrame*& currVMEntryFrame) +{ + if (callerFrameOrVMEntryFrame() == currVMEntryFrame) { + VMEntryRecord* currVMEntryRecord = vmEntryRecord(currVMEntryFrame); + currVMEntryFrame = currVMEntryRecord->prevTopVMEntryFrame(); + return currVMEntryRecord->prevTopCallFrame(); + } + return static_cast<CallFrame*>(callerFrameOrVMEntryFrame()); +} + +SUPPRESS_ASAN CallFrame* CallFrame::unsafeCallerFrame(VMEntryFrame*& currVMEntryFrame) +{ + if (unsafeCallerFrameOrVMEntryFrame() == currVMEntryFrame) { + VMEntryRecord* currVMEntryRecord = vmEntryRecord(currVMEntryFrame); + currVMEntryFrame = currVMEntryRecord->unsafePrevTopVMEntryFrame(); + return currVMEntryRecord->unsafePrevTopCallFrame(); + } + return static_cast<CallFrame*>(unsafeCallerFrameOrVMEntryFrame()); +} + +SourceOrigin CallFrame::callerSourceOrigin() +{ + SourceOrigin sourceOrigin; + bool haveSkippedFirstFrame = false; + StackVisitor::visit(this, [&](StackVisitor& visitor) { + if (!std::exchange(haveSkippedFirstFrame, true)) + return StackVisitor::Status::Continue; + + switch (visitor->codeType()) { + case StackVisitor::Frame::CodeType::Function: + // Skip the builtin functions since they should not pass the source origin to the dynamic code generation calls. + // Consider the following code. + // + // [ "42 + 44" ].forEach(eval); + // + // In the above case, the eval function will be interpreted as the indirect call to eval inside forEach function. + // At that time, the generated eval code should have the source origin to the original caller of the forEach function + // instead of the source origin of the forEach function. + if (static_cast<FunctionExecutable*>(visitor->codeBlock()->ownerScriptExecutable())->isBuiltinFunction()) + return StackVisitor::Status::Continue; + FALLTHROUGH; + + case StackVisitor::Frame::CodeType::Eval: + case StackVisitor::Frame::CodeType::Module: + case StackVisitor::Frame::CodeType::Global: + sourceOrigin = visitor->codeBlock()->ownerScriptExecutable()->sourceOrigin(); + return StackVisitor::Status::Done; + + case StackVisitor::Frame::CodeType::Native: + return StackVisitor::Status::Continue; + + case StackVisitor::Frame::CodeType::Wasm: + // FIXME: Should return the source origin for WASM. + return StackVisitor::Status::Done; + } + + RELEASE_ASSERT_NOT_REACHED(); + return StackVisitor::Status::Done; + }); + return sourceOrigin; +} + +String CallFrame::friendlyFunctionName() +{ + CodeBlock* codeBlock = this->codeBlock(); + if (!codeBlock) + return emptyString(); + + switch (codeBlock->codeType()) { + case EvalCode: + return ASCIILiteral("eval code"); + case ModuleCode: + return ASCIILiteral("module code"); + case GlobalCode: + return ASCIILiteral("global code"); + case FunctionCode: + if (jsCallee()) + return getCalculatedDisplayName(vm(), jsCallee()); + return emptyString(); + } + + ASSERT_NOT_REACHED(); + return emptyString(); +} + +void CallFrame::dump(PrintStream& out) +{ + if (CodeBlock* codeBlock = this->codeBlock()) { + out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), "]"); + + out.print("("); + thisValue().dumpForBacktrace(out); + + for (size_t i = 0; i < argumentCount(); ++i) { + out.print(", "); + JSValue value = argument(i); + value.dumpForBacktrace(out); + } + + out.print(")"); + + return; + } + + out.print(returnPC()); +} + +const char* CallFrame::describeFrame() +{ + const size_t bufferSize = 200; + static char buffer[bufferSize + 1]; + + WTF::StringPrintStream stringStream; + + dump(stringStream); + + strncpy(buffer, stringStream.toCString().data(), bufferSize); + buffer[bufferSize] = '\0'; + + return buffer; +} + } // namespace JSC |