summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter/CallFrame.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/interpreter/CallFrame.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/interpreter/CallFrame.cpp')
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrame.cpp281
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