Eliminate HostCall bit from JSC Stack CallerFrame
https://bugs.webkit.org/show_bug.cgi?id=123642
Reviewed by Geoffrey Garen.
Source/JavaScriptCore:
Replace the HostCallFrame bit or'ed to the CallerFrame value in a CallFrame with
a VM entry sentinel CallFrame. Logically, the VM entry sentinel call frame is
pushed on the stack before the callee frame when calling from native to JavaScript
code. The callee frame's CallerFrame points at the VM entry sentinel call frame
and the VM entry sentinel call frame's CallerFrame points to the real caller.
The VM entry sentinel call frame has a sentinel (1) in the CodeBlock to indicate
its a VM entry sentinel call frame. It's ScopeChain has vm.topCallFrame at the
time of the call. This allows for a complete stack walk as well as walking just
the contiguous JS frames.
The VM entry sentinel call frame and callee frame are currently allocated and
initialized in ExecState::init(), but this initialization will be moved to
ctiTrampoline when we actually move onto the native stack.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::noticeIncomingCall):
* debugger/DebuggerCallFrame.cpp:
(JSC::DebuggerCallFrame::callerFrame):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compileExceptionHandlers):
* interpreter/CallFrame.h:
(JSC::ExecState::frameExtent):
(JSC::ExecState::currentVPC):
(JSC::ExecState::setCurrentVPC):
(JSC::ExecState::init):
(JSC::ExecState::noCaller):
(JSC::ExecState::isVMEntrySentinel):
(JSC::ExecState::vmEntrySentinelCallerFrame):
(JSC::ExecState::initializeVMEntrySentinelFrame):
(JSC::ExecState::callerFrameSkippingVMEntrySentinel):
(JSC::ExecState::vmEntrySentinelCodeBlock):
* interpreter/Interpreter.cpp:
(JSC::unwindCallFrame):
(JSC::Interpreter::getStackTrace):
* interpreter/Interpreter.h:
(JSC::TopCallFrameSetter::TopCallFrameSetter):
(JSC::TopCallFrameSetter::~TopCallFrameSetter):
(JSC::NativeCallFrameTracer::NativeCallFrameTracer):
* interpreter/JSStack.cpp:
(JSC::JSStack::~JSStack):
* interpreter/JSStackInlines.h:
(JSC::JSStack::getStartOfFrame):
(JSC::JSStack::pushFrame):
(JSC::JSStack::popFrame):
* interpreter/Register.h:
(JSC::Register::operator=):
(JSC::Register::callFrame):
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::readFrame):
(JSC::StackVisitor::readNonInlinedFrame):
(JSC::StackVisitor::readInlinedFrame):
(JSC::StackVisitor::Frame::print):
* interpreter/VMInspector.cpp:
(JSC::VMInspector::countFrames):
* jit/JIT.cpp:
(JSC::JIT::privateCompileExceptionHandlers):
* jit/JITOperations.cpp:
* jit/JITStubsARM.h:
(JSC::ctiTrampoline):
* jit/JITStubsARM64.h:
* jit/JITStubsARMv7.h:
(JSC::ctiTrampoline):
* jit/JITStubsMIPS.h:
* jit/JITStubsMSVC64.asm:
* jit/JITStubsSH4.h:
* jit/JITStubsX86.h:
* jit/JITStubsX86_64.h:
* jsc.cpp:
(functionDumpCallFrame):
* llint/LowLevelInterpreter.cpp:
(JSC::CLoop::execute):
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::throwException):
Source/WebCore:
Updated JavaScript stack walking as a result of the corresponding changes made in
JavaScriptCore.
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::shouldBypassMainWorldContentSecurityPolicy):
* bindings/js/ScriptDebugServer.cpp:
(WebCore::ScriptDebugServer::stepOutOfFunction):
(WebCore::ScriptDebugServer::returnEvent):
(WebCore::ScriptDebugServer::didExecuteProgram):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@158586 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index c2262be..505ace6 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,85 @@
+2013-11-04 Michael Saboff <msaboff@apple.com>
+
+ Eliminate HostCall bit from JSC Stack CallerFrame
+ https://bugs.webkit.org/show_bug.cgi?id=123642
+
+ Reviewed by Geoffrey Garen.
+
+ Replace the HostCallFrame bit or'ed to the CallerFrame value in a CallFrame with
+ a VM entry sentinel CallFrame. Logically, the VM entry sentinel call frame is
+ pushed on the stack before the callee frame when calling from native to JavaScript
+ code. The callee frame's CallerFrame points at the VM entry sentinel call frame
+ and the VM entry sentinel call frame's CallerFrame points to the real caller.
+ The VM entry sentinel call frame has a sentinel (1) in the CodeBlock to indicate
+ its a VM entry sentinel call frame. It's ScopeChain has vm.topCallFrame at the
+ time of the call. This allows for a complete stack walk as well as walking just
+ the contiguous JS frames.
+
+ The VM entry sentinel call frame and callee frame are currently allocated and
+ initialized in ExecState::init(), but this initialization will be moved to
+ ctiTrampoline when we actually move onto the native stack.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::noticeIncomingCall):
+ * debugger/DebuggerCallFrame.cpp:
+ (JSC::DebuggerCallFrame::callerFrame):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::compileExceptionHandlers):
+ * interpreter/CallFrame.h:
+ (JSC::ExecState::frameExtent):
+ (JSC::ExecState::currentVPC):
+ (JSC::ExecState::setCurrentVPC):
+ (JSC::ExecState::init):
+ (JSC::ExecState::noCaller):
+ (JSC::ExecState::isVMEntrySentinel):
+ (JSC::ExecState::vmEntrySentinelCallerFrame):
+ (JSC::ExecState::initializeVMEntrySentinelFrame):
+ (JSC::ExecState::callerFrameSkippingVMEntrySentinel):
+ (JSC::ExecState::vmEntrySentinelCodeBlock):
+ * interpreter/Interpreter.cpp:
+ (JSC::unwindCallFrame):
+ (JSC::Interpreter::getStackTrace):
+ * interpreter/Interpreter.h:
+ (JSC::TopCallFrameSetter::TopCallFrameSetter):
+ (JSC::TopCallFrameSetter::~TopCallFrameSetter):
+ (JSC::NativeCallFrameTracer::NativeCallFrameTracer):
+ * interpreter/JSStack.cpp:
+ (JSC::JSStack::~JSStack):
+ * interpreter/JSStackInlines.h:
+ (JSC::JSStack::getStartOfFrame):
+ (JSC::JSStack::pushFrame):
+ (JSC::JSStack::popFrame):
+ * interpreter/Register.h:
+ (JSC::Register::operator=):
+ (JSC::Register::callFrame):
+ * interpreter/StackVisitor.cpp:
+ (JSC::StackVisitor::readFrame):
+ (JSC::StackVisitor::readNonInlinedFrame):
+ (JSC::StackVisitor::readInlinedFrame):
+ (JSC::StackVisitor::Frame::print):
+ * interpreter/VMInspector.cpp:
+ (JSC::VMInspector::countFrames):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileExceptionHandlers):
+ * jit/JITOperations.cpp:
+ * jit/JITStubsARM.h:
+ (JSC::ctiTrampoline):
+ * jit/JITStubsARM64.h:
+ * jit/JITStubsARMv7.h:
+ (JSC::ctiTrampoline):
+ * jit/JITStubsMIPS.h:
+ * jit/JITStubsMSVC64.asm:
+ * jit/JITStubsSH4.h:
+ * jit/JITStubsX86.h:
+ * jit/JITStubsX86_64.h:
+ * jsc.cpp:
+ (functionDumpCallFrame):
+ * llint/LowLevelInterpreter.cpp:
+ (JSC::CLoop::execute):
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ (JSC::VM::throwException):
+
2013-11-04 Mark Hahnenberg <mhahnenberg@apple.com>
JSArrayBufferViews of length 0 allocate 0 CopiedSpace bytes, which is invalid
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index e309993..08c28fa 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -2925,7 +2925,7 @@
ExecState* frame = callerFrame;
for (unsigned i = Options::maximumInliningDepth(); i--; frame = frame->callerFrame()) {
- if (frame->hasHostCallFrameFlag())
+ if (frame->isVMEntrySentinel())
break;
if (frame->codeBlock() == this) {
// Recursive calls won't be inlined.
diff --git a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
index f3ed3df..f8d1c43 100644
--- a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
+++ b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp
@@ -69,7 +69,7 @@
if (m_caller)
return m_caller;
- CallFrame* callerFrame = m_callFrame->callerFrameNoFlags();
+ CallFrame* callerFrame = m_callFrame->callerFrameSkippingVMEntrySentinel();
if (!callerFrame)
return 0;
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index b281e52..4708812 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -125,10 +125,8 @@
Jump doLookup;
if (!m_exceptionChecksWithCallFrameRollback.empty()) {
- // Remove hostCallFrameFlag from caller.
m_exceptionChecksWithCallFrameRollback.link(this);
emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::argumentGPR0);
- andPtr(TrustedImm32(safeCast<int32_t>(~CallFrame::hostCallFrameFlag())), GPRInfo::argumentGPR0);
doLookup = jump();
}
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h
index 65064f2..91806bb 100644
--- a/Source/JavaScriptCore/interpreter/CallFrame.h
+++ b/Source/JavaScriptCore/interpreter/CallFrame.h
@@ -179,7 +179,7 @@
Register* frameExtent()
{
- if (!codeBlock())
+ if (isVMEntrySentinel() || !codeBlock())
return registers() - 1;
return frameExtentInternal();
}
@@ -189,10 +189,12 @@
#if USE(JSVALUE32_64)
Instruction* currentVPC() const
{
+ ASSERT(!isVMEntrySentinel());
return bitwise_cast<Instruction*>(this[JSStack::ArgumentCount].tag());
}
void setCurrentVPC(Instruction* vpc)
{
+ ASSERT(!isVMEntrySentinel());
this[JSStack::ArgumentCount].tag() = bitwise_cast<int32_t>(vpc);
}
#else
@@ -206,8 +208,7 @@
ALWAYS_INLINE void init(CodeBlock* codeBlock, Instruction* vPC, JSScope* scope,
CallFrame* callerFrame, int argc, JSObject* callee)
{
- ASSERT(callerFrame); // Use noCaller() rather than 0 for the outer host call frame caller.
- ASSERT(callerFrame == noCaller() || callerFrame->removeHostCallFrameFlag()->stack()->containsAddress(this));
+ ASSERT(callerFrame == noCaller() || callerFrame->isVMEntrySentinel() || callerFrame->stack()->containsAddress(this));
setCodeBlock(codeBlock);
setScope(scope);
@@ -265,20 +266,42 @@
int hostThisRegister() { return thisArgumentOffset(); }
JSValue hostThisValue() { return thisValue(); }
- static CallFrame* noCaller() { return reinterpret_cast<CallFrame*>(HostCallFrameFlag); }
+ static CallFrame* noCaller() { return 0; }
- bool hasHostCallFrameFlag() const { return reinterpret_cast<intptr_t>(this) & HostCallFrameFlag; }
- CallFrame* addHostCallFrameFlag() const { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) | HostCallFrameFlag); }
- CallFrame* removeHostCallFrameFlag() { return reinterpret_cast<CallFrame*>(reinterpret_cast<intptr_t>(this) & ~HostCallFrameFlag); }
- static intptr_t hostCallFrameFlag() { return HostCallFrameFlag; }
+ bool isVMEntrySentinel() const
+ {
+ return !!this && codeBlock() == vmEntrySentinelCodeBlock();
+ }
+
+ CallFrame* vmEntrySentinelCallerFrame() const
+ {
+ ASSERT(isVMEntrySentinel());
+ return this[JSStack::ScopeChain].callFrame();
+ }
+
+ void initializeVMEntrySentinelFrame(CallFrame* callFrame)
+ {
+ setCallerFrame(noCaller());
+ setReturnPC(0);
+ setCodeBlock(vmEntrySentinelCodeBlock());
+ static_cast<Register*>(this)[JSStack::ScopeChain] = callFrame;
+ setCallee(0);
+ setArgumentCountIncludingThis(0);
+ }
+
+ CallFrame* callerFrameSkippingVMEntrySentinel()
+ {
+ CallFrame* caller = callerFrame();
+ if (caller->isVMEntrySentinel())
+ return caller->vmEntrySentinelCallerFrame();
+ return caller;
+ }
void setArgumentCountIncludingThis(int count) { static_cast<Register*>(this)[JSStack::ArgumentCount].payload() = count; }
void setCallee(JSObject* callee) { static_cast<Register*>(this)[JSStack::Callee] = Register::withCallee(callee); }
void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[JSStack::CodeBlock] = codeBlock; }
void setReturnPC(void* value) { callerFrameAndPC().pc = reinterpret_cast<Instruction*>(value); }
- CallFrame* callerFrameNoFlags() { return callerFrame()->removeHostCallFrameFlag(); }
-
// CallFrame::iterate() expects a Functor that implements the following method:
// StackVisitor::Status operator()(StackVisitor&);
@@ -288,7 +311,7 @@
}
private:
- static const intptr_t HostCallFrameFlag = 1;
+ static const intptr_t s_VMEntrySentinel = 1;
#ifndef NDEBUG
JSStack* stack();
@@ -328,6 +351,8 @@
CallerFrameAndPC& callerFrameAndPC() { return *reinterpret_cast<CallerFrameAndPC*>(this); }
const CallerFrameAndPC& callerFrameAndPC() const { return *reinterpret_cast<const CallerFrameAndPC*>(this); }
+ static CodeBlock* vmEntrySentinelCodeBlock() { return reinterpret_cast<CodeBlock*>(s_VMEntrySentinel); }
+
friend class JSStack;
friend class VMInspector;
};
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 8bf518b..fa9970a 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -426,8 +426,11 @@
}
CallFrame* callerFrame = callFrame->callerFrame();
- callFrame->vm().topCallFrame = callerFrame->removeHostCallFrameFlag();
- return !callerFrame->hasHostCallFrameFlag();
+ if (callerFrame->isVMEntrySentinel()) {
+ callFrame->vm().topCallFrame = callerFrame->vmEntrySentinelCallerFrame();
+ return false;
+ }
+ return true;
}
static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor)
@@ -544,7 +547,7 @@
void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
{
VM& vm = m_vm;
- ASSERT(!vm.topCallFrame->hasHostCallFrameFlag());
+ ASSERT(!vm.topCallFrame->isVMEntrySentinel());
CallFrame* callFrame = vm.topCallFrame;
if (!callFrame)
return;
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.h b/Source/JavaScriptCore/interpreter/Interpreter.h
index 61589e6..9705567 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.h
+++ b/Source/JavaScriptCore/interpreter/Interpreter.h
@@ -156,13 +156,13 @@
: vm(currentVM)
, oldCallFrame(currentVM.topCallFrame)
{
- ASSERT(!callFrame->hasHostCallFrameFlag());
+ ASSERT(!callFrame->isVMEntrySentinel());
currentVM.topCallFrame = callFrame;
}
~TopCallFrameSetter()
{
- ASSERT(!oldCallFrame->hasHostCallFrameFlag());
+ ASSERT(!oldCallFrame->isVMEntrySentinel());
vm.topCallFrame = oldCallFrame;
}
private:
@@ -176,7 +176,7 @@
{
ASSERT(vm);
ASSERT(callFrame);
- ASSERT(!callFrame->hasHostCallFrameFlag());
+ ASSERT(!callFrame->isVMEntrySentinel());
vm->topCallFrame = callFrame;
}
};
diff --git a/Source/JavaScriptCore/interpreter/JSStack.cpp b/Source/JavaScriptCore/interpreter/JSStack.cpp
index ea57154..da3d07d 100644
--- a/Source/JavaScriptCore/interpreter/JSStack.cpp
+++ b/Source/JavaScriptCore/interpreter/JSStack.cpp
@@ -60,8 +60,8 @@
JSStack::~JSStack()
{
- void* highAddress = reinterpret_cast_ptr<void*>(static_cast<char*>(m_reservation.base()) + m_reservation.size());
- m_reservation.decommit(reinterpret_cast_ptr<void*>(m_commitEnd), reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd));
+ void* highAddress = reinterpret_cast<void*>(static_cast<char*>(m_reservation.base()) + m_reservation.size());
+ m_reservation.decommit(reinterpret_cast<void*>(m_commitEnd), reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd));
addToCommittedByteCount(-(reinterpret_cast<intptr_t>(highAddress) - reinterpret_cast<intptr_t>(m_commitEnd)));
m_reservation.deallocate();
}
diff --git a/Source/JavaScriptCore/interpreter/JSStackInlines.h b/Source/JavaScriptCore/interpreter/JSStackInlines.h
index c321b82..7fd2cd1 100644
--- a/Source/JavaScriptCore/interpreter/JSStackInlines.h
+++ b/Source/JavaScriptCore/interpreter/JSStackInlines.h
@@ -46,7 +46,7 @@
inline Register* JSStack::getStartOfFrame(CallFrame* frame)
{
- CallFrame* callerFrame = frame->callerFrameNoFlags();
+ CallFrame* callerFrame = frame->callerFrameSkippingVMEntrySentinel();
return getTopOfFrame(callerFrame);
}
@@ -64,7 +64,7 @@
paddedArgsCount = numParameters;
}
- Register* newCallFrameSlot = oldEnd - paddedArgsCount - JSStack::CallFrameHeaderSize;
+ Register* newCallFrameSlot = oldEnd - paddedArgsCount - (2 * JSStack::CallFrameHeaderSize);
#if ENABLE(DEBUG_JSSTACK)
newCallFrameSlot -= JSStack::FenceSize;
@@ -78,6 +78,10 @@
if (!grow(newEnd))
return 0;
+ // Compute the address of the new VM sentinal frame for this invocation:
+ CallFrame* newVMEntrySentinalFrame = CallFrame::create(newCallFrameSlot + paddedArgsCount + JSStack::CallFrameHeaderSize);
+ ASSERT(!!newVMEntrySentinalFrame);
+
// Compute the address of the new frame for this invocation:
CallFrame* newCallFrame = CallFrame::create(newCallFrameSlot);
ASSERT(!!newCallFrame);
@@ -87,9 +91,11 @@
// the top frame on the stack.
callerFrame = m_topCallFrame;
- // Initialize the frame header:
- newCallFrame->init(codeBlock, 0, scope,
- callerFrame->addHostCallFrameFlag(), argsCount, callee);
+ // Initialize the VM sentinal frame header:
+ newVMEntrySentinalFrame->initializeVMEntrySentinelFrame(callerFrame);
+
+ // Initialize the callee frame header:
+ newCallFrame->init(codeBlock, 0, scope, newVMEntrySentinalFrame, argsCount, callee);
ASSERT(!!newCallFrame->scope());
@@ -112,7 +118,9 @@
inline void JSStack::popFrame(CallFrame* frame)
{
validateFence(frame, __FUNCTION__, __LINE__);
- CallFrame* callerFrame = frame->callerFrameNoFlags();
+
+ // Pop off the callee frame and the sentinal frame.
+ CallFrame* callerFrame = frame->callerFrame()->vmEntrySentinelCallerFrame();
// Pop to the caller:
m_topCallFrame = callerFrame;
@@ -151,6 +159,8 @@
// |--------------------------------------|
// | *** the Fence *** |
// |--------------------------------------|
+// | VM entry sentinal frame header |
+// |--------------------------------------|
// | Args of new frame |
// |--------------------------------------|
// | Frame Header of new frame |
diff --git a/Source/JavaScriptCore/interpreter/Register.h b/Source/JavaScriptCore/interpreter/Register.h
index 8573ad1..13a7e58 100644
--- a/Source/JavaScriptCore/interpreter/Register.h
+++ b/Source/JavaScriptCore/interpreter/Register.h
@@ -54,11 +54,13 @@
JSValue jsValue() const;
EncodedJSValue encodedJSValue() const;
+ Register& operator=(CallFrame*);
Register& operator=(CodeBlock*);
Register& operator=(JSScope*);
int32_t i() const;
JSActivation* activation() const;
+ CallFrame* callFrame() const;
CodeBlock* codeBlock() const;
JSObject* function() const;
JSPropertyNameIterator* propertyNameIterator() const;
@@ -85,6 +87,7 @@
private:
union {
EncodedJSValue value;
+ CallFrame* callFrame;
CodeBlock* codeBlock;
EncodedValueDescriptor encodedValue;
double number;
@@ -122,6 +125,12 @@
// Interpreter functions
+ ALWAYS_INLINE Register& Register::operator=(CallFrame* callFrame)
+ {
+ u.callFrame = callFrame;
+ return *this;
+ }
+
ALWAYS_INLINE Register& Register::operator=(CodeBlock* codeBlock)
{
u.codeBlock = codeBlock;
@@ -133,6 +142,11 @@
return jsValue().asInt32();
}
+ ALWAYS_INLINE CallFrame* Register::callFrame() const
+ {
+ return u.callFrame;
+ }
+
ALWAYS_INLINE CodeBlock* Register::codeBlock() const
{
return u.codeBlock;
diff --git a/Source/JavaScriptCore/interpreter/StackVisitor.cpp b/Source/JavaScriptCore/interpreter/StackVisitor.cpp
index a9e23ad..d922e7f 100644
--- a/Source/JavaScriptCore/interpreter/StackVisitor.cpp
+++ b/Source/JavaScriptCore/interpreter/StackVisitor.cpp
@@ -56,7 +56,7 @@
void StackVisitor::readFrame(CallFrame* callFrame)
{
- ASSERT(!callFrame->hasHostCallFrameFlag());
+ ASSERT(!callFrame->isVMEntrySentinel());
if (!callFrame) {
m_frame.setToEnd();
return;
@@ -104,7 +104,7 @@
{
m_frame.m_callFrame = callFrame;
m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
- m_frame.m_callerFrame = callFrame->callerFrame()->removeHostCallFrameFlag();
+ m_frame.m_callerFrame = callFrame->callerFrameSkippingVMEntrySentinel();
m_frame.m_callee = callFrame->callee();
m_frame.m_scope = callFrame->scope();
m_frame.m_codeBlock = callFrame->codeBlock();
@@ -127,7 +127,7 @@
void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
{
ASSERT(codeOrigin);
- ASSERT(!callFrame->hasHostCallFrameFlag());
+ ASSERT(!callFrame->isVMEntrySentinel());
int frameOffset = inlinedFrameOffset(codeOrigin);
bool isInlined = !!frameOffset;
@@ -380,7 +380,7 @@
printif(i, " name '%s'\n", functionName().utf8().data());
printif(i, " sourceURL '%s'\n", sourceURL().utf8().data());
- printif(i, " hostFlag %d\n", callerFrame->hasHostCallFrameFlag());
+ printif(i, " isVMEntrySentinel %d\n", callerFrame->isVMEntrySentinel());
#if ENABLE(DFG_JIT)
printif(i, " isInlinedFrame %d\n", isInlinedFrame());
@@ -390,7 +390,7 @@
printif(i, " callee %p\n", callee());
printif(i, " returnPC %p\n", returnPC);
- printif(i, " callerFrame %p\n", callerFrame->removeHostCallFrameFlag());
+ printif(i, " callerFrame %p\n", callerFrame);
unsigned locationRawBits = callFrame->locationAsRawBits();
printif(i, " rawLocationBits %u 0x%x\n", locationRawBits, locationRawBits);
printif(i, " codeBlock %p\n", codeBlock);
diff --git a/Source/JavaScriptCore/interpreter/VMInspector.cpp b/Source/JavaScriptCore/interpreter/VMInspector.cpp
index 58bc150..162e0a7 100644
--- a/Source/JavaScriptCore/interpreter/VMInspector.cpp
+++ b/Source/JavaScriptCore/interpreter/VMInspector.cpp
@@ -102,7 +102,7 @@
int VMInspector::countFrames(CallFrame* frame)
{
int count = -1;
- while (frame && !frame->hasHostCallFrameFlag()) {
+ while (frame && !frame->isVMEntrySentinel()) {
count++;
frame = frame->callerFrame();
}
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 16c9587..6efa734 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -800,10 +800,8 @@
Jump doLookup;
if (!m_exceptionChecksWithCallFrameRollback.empty()) {
- // Remove hostCallFlag from caller
m_exceptionChecksWithCallFrameRollback.link(this);
emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::argumentGPR0);
- andPtr(TrustedImm32(safeCast<int32_t>(~CallFrame::hostCallFrameFlag())), GPRInfo::argumentGPR0);
doLookup = jump();
}
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 52aa2fd..89a182a 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -74,8 +74,8 @@
{
// We pass in our own code block, because the callframe hasn't been populated.
VM* vm = codeBlock->vm();
- CallFrame* callerFrame = exec->callerFrame();
- NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
+ CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel();
+ NativeCallFrameTracer tracer(vm, callerFrame);
JSStack& stack = vm->interpreter->stack();
@@ -86,8 +86,8 @@
int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec)
{
VM* vm = &exec->vm();
- CallFrame* callerFrame = exec->callerFrame();
- NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
+ CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel();
+ NativeCallFrameTracer tracer(vm, callerFrame);
JSStack& stack = vm->interpreter->stack();
@@ -101,8 +101,8 @@
int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec)
{
VM* vm = &exec->vm();
- CallFrame* callerFrame = exec->callerFrame();
- NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
+ CallFrame* callerFrame = exec->callerFrameSkippingVMEntrySentinel();
+ NativeCallFrameTracer tracer(vm, callerFrame);
JSStack& stack = vm->interpreter->stack();
@@ -1696,7 +1696,7 @@
VM* vm = &exec->vm();
NativeCallFrameTracer tracer(vm, exec);
- ASSERT(!exec->hasHostCallFrameFlag());
+ ASSERT(!exec->isVMEntrySentinel());
genericUnwind(vm, exec, vm->exception());
}
diff --git a/Source/JavaScriptCore/jit/JITStubsARM.h b/Source/JavaScriptCore/jit/JITStubsARM.h
index 3ddb836..37533b7 100644
--- a/Source/JavaScriptCore/jit/JITStubsARM.h
+++ b/Source/JavaScriptCore/jit/JITStubsARM.h
@@ -161,6 +161,8 @@
"stmdb sp!, {r4-r6, r8-r11, lr}" "\n"
"sub sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n"
"mov r5, r2" "\n"
+ "ldr r4, [r5]" "\n"
+ "str r11, [r4]" "\n"
// r0 contains the code
"blx r0" "\n"
"add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n"
@@ -356,6 +358,8 @@
stmdb sp!, {r4-r6, r8-r11, lr}
sub sp, sp, # PRESERVEDR4_OFFSET
mov r5, r2
+ ldr r4, [r5]
+ str r11, [r4]
mov lr, pc
bx r0
add sp, sp, # PRESERVEDR4_OFFSET
@@ -422,6 +426,8 @@
MSVC_BEGIN( stmdb sp!, {r4-r6, r8-r11, lr})
MSVC_BEGIN( sub sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
MSVC_BEGIN( mov r5, r2)
+MSVC_BEGIN( ldr r4, [r5])
+MSVC_BEGIN( str r11, [r4])
MSVC_BEGIN( ; r0 contains the code)
MSVC_BEGIN( mov lr, pc)
MSVC_BEGIN( bx r0)
diff --git a/Source/JavaScriptCore/jit/JITStubsARM64.h b/Source/JavaScriptCore/jit/JITStubsARM64.h
index 59aa184..e877a9c 100644
--- a/Source/JavaScriptCore/jit/JITStubsARM64.h
+++ b/Source/JavaScriptCore/jit/JITStubsARM64.h
@@ -81,6 +81,8 @@
"str x2, [sp, #" STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "]" "\n"
"str x4, [sp, #" STRINGIZE_VALUE_OF(PROFILER_REFERENCE_OFFSET) "]" "\n"
"str x5, [sp, #" STRINGIZE_VALUE_OF(VM_OFFSET) "]" "\n"
+ "ldr x19, [x2]" "\n" // Store the previous frame pointer in the VM entry sentinal frame above us
+ "str x29, [x19]" "\n"
"mov x25, x2" "\n" // callFrameRegister = ARM64Registers::x25
"mov x26, #512" "\n" // timeoutCheckRegister = ARM64Registers::x26
"mov x27, #0xFFFF000000000000" "\n" // tagTypeNumberRegister = ARM64Registers::x27
diff --git a/Source/JavaScriptCore/jit/JITStubsARMv7.h b/Source/JavaScriptCore/jit/JITStubsARMv7.h
index 85f084c..7a4f107 100644
--- a/Source/JavaScriptCore/jit/JITStubsARMv7.h
+++ b/Source/JavaScriptCore/jit/JITStubsARMv7.h
@@ -221,6 +221,8 @@
"str r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n"
"str r1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "]" "\n"
"mov r5, r2" "\n"
+ "ldr r4, [r5]" "\n"
+ "str r7, [r4]" "\n"
"blx r0" "\n"
"ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n"
"ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET) "]" "\n"
@@ -455,6 +457,8 @@
str r11, [sp, # PRESERVED_R11_OFFSET ]
str r1, [sp, # REGISTER_FILE_OFFSET ]
mov r5, r2
+ ldr r4, [r5]
+ str r7, [r4]
blx r0
ldr r11, [sp, # PRESERVED_R11_OFFSET ]
ldr r10, [sp, # PRESERVED_R10_OFFSET ]
diff --git a/Source/JavaScriptCore/jit/JITStubsMIPS.h b/Source/JavaScriptCore/jit/JITStubsMIPS.h
index c12029f..04bf748 100644
--- a/Source/JavaScriptCore/jit/JITStubsMIPS.h
+++ b/Source/JavaScriptCore/jit/JITStubsMIPS.h
@@ -72,6 +72,8 @@
#if WTF_MIPS_PIC
"sw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n"
#endif
+ "lw $18, ($6) # get caller's frame" "\n"
+ "sw $30, ($18) # store previous frame pointer in VM entry sentinal frame" "\n"
"move $16,$6 # set callFrameRegister" "\n"
"li $17,512 # set timeoutCheckRegister" "\n"
"move $25,$4 # move executableAddress to t9" "\n"
diff --git a/Source/JavaScriptCore/jit/JITStubsMSVC64.asm b/Source/JavaScriptCore/jit/JITStubsMSVC64.asm
index 1fa3bd8..b59a821 100644
--- a/Source/JavaScriptCore/jit/JITStubsMSVC64.asm
+++ b/Source/JavaScriptCore/jit/JITStubsMSVC64.asm
@@ -39,6 +39,7 @@
mov qword ptr[rsp+8h], rcx
push rbp
+ mov rbp, rax ; Save previous frame pointer
mov rbp, rsp
push r12
push r13
@@ -55,6 +56,8 @@
mov r14, 0FFFF000000000000h
mov r15, 0FFFF000000000002h
mov r13, r8
+ mov r11, qword ptr[r13] ; Put the previous frame pointer in the host call frame above us
+ mov qword ptr[r11], rax
call rcx
add rsp, 28h
pop rbx
diff --git a/Source/JavaScriptCore/jit/JITStubsSH4.h b/Source/JavaScriptCore/jit/JITStubsSH4.h
index 40d883d..7011a5c 100644
--- a/Source/JavaScriptCore/jit/JITStubsSH4.h
+++ b/Source/JavaScriptCore/jit/JITStubsSH4.h
@@ -63,6 +63,8 @@
"mov.l r9, @-r15" "\n"
"mov.l r8, @-r15" "\n"
"add #-" STRINGIZE_VALUE_OF(SAVED_R8_OFFSET) ", r15" "\n"
+ "mov.l @r6, r7" "\n"
+ "mov.l r14, @r7" "\n"
"mov r6, r14" "\n"
"jsr @r4" "\n"
"nop" "\n"
diff --git a/Source/JavaScriptCore/jit/JITStubsX86.h b/Source/JavaScriptCore/jit/JITStubsX86.h
index 4180c4d..4e3e0c9 100644
--- a/Source/JavaScriptCore/jit/JITStubsX86.h
+++ b/Source/JavaScriptCore/jit/JITStubsX86.h
@@ -51,6 +51,7 @@
HIDE_SYMBOL(ctiTrampoline) "\n"
SYMBOL_STRING(ctiTrampoline) ":" "\n"
"pushl %ebp" "\n"
+ "movl %ebp, %eax" "\n" // Save previous frame pointer
"movl %esp, %ebp" "\n"
"pushl %esi" "\n"
"pushl %edi" "\n"
@@ -62,6 +63,8 @@
// by 0x1c bytes.
"subl $0x1c, %esp" "\n"
"movl 0x38(%esp), %edi" "\n"
+ "movl (%edi), %ebx" "\n" // Put the previous frame pointer in the VM entry sentinal frame above us
+ "movl %eax, (%ebx)" "\n"
"call *0x30(%esp)" "\n"
"addl $0x1c, %esp" "\n"
@@ -247,6 +250,7 @@
{
__asm {
push ebp;
+ mov eax, ebp;
mov ebp, esp;
push esi;
push edi;
@@ -254,6 +258,8 @@
sub esp, 0x1c;
mov ecx, esp;
mov edi, [esp + 0x38];
+ mov ebx, [edi];
+ mov [ebx], eax;
call [esp + 0x30];
add esp, 0x1c;
pop ebx;
diff --git a/Source/JavaScriptCore/jit/JITStubsX86_64.h b/Source/JavaScriptCore/jit/JITStubsX86_64.h
index 68d80f0..7fa3d8e 100644
--- a/Source/JavaScriptCore/jit/JITStubsX86_64.h
+++ b/Source/JavaScriptCore/jit/JITStubsX86_64.h
@@ -51,6 +51,7 @@
HIDE_SYMBOL(ctiTrampoline) "\n"
SYMBOL_STRING(ctiTrampoline) ":" "\n"
"pushq %rbp" "\n"
+ "movq %rbp, %rax" "\n" // Save previous frame pointer
"movq %rsp, %rbp" "\n"
"pushq %r12" "\n"
"pushq %r13" "\n"
@@ -66,6 +67,8 @@
"movq $0xFFFF000000000000, %r14" "\n"
"movq $0xFFFF000000000002, %r15" "\n"
"movq %rdx, %r13" "\n"
+ "movq (%r13), %r11" "\n" // Put the previous frame pointer in the VM entry sentinal frame above us
+ "movq %rax, (%r11)" "\n"
"call *%rdi" "\n"
"addq $0x8, %rsp" "\n"
"popq %rbx" "\n"
diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp
index 097c4f4..6265cab 100644
--- a/Source/JavaScriptCore/jsc.cpp
+++ b/Source/JavaScriptCore/jsc.cpp
@@ -306,7 +306,7 @@
#ifndef NDEBUG
EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
{
- if (!exec->callerFrame()->hasHostCallFrameFlag())
+ if (!exec->callerFrame()->isVMEntrySentinel())
exec->vm().interpreter->dumpCallFrame(exec->callerFrame());
return JSValue::encode(jsUndefined());
}
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp b/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp
index 760accc..5c4fda6 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.cpp
@@ -449,7 +449,7 @@
doReturnHelper: {
ASSERT(!!callFrame);
- if (callFrame->hasHostCallFrameFlag()) {
+ if (callFrame->isVMEntrySentinel()) {
#if USE(JSVALUE32_64)
return JSValue(t1.i, t0.i); // returning JSValue(tag, payload);
#else
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp
index 0aeff5f..566aa28 100644
--- a/Source/JavaScriptCore/runtime/VM.cpp
+++ b/Source/JavaScriptCore/runtime/VM.cpp
@@ -163,7 +163,7 @@
, heap(this, heapType)
, vmType(vmType)
, clientData(0)
- , topCallFrame(CallFrame::noCaller()->removeHostCallFrameFlag())
+ , topCallFrame(CallFrame::noCaller())
, arrayConstructorTable(adoptPtr(new HashTable(JSC::arrayConstructorTable)))
, arrayPrototypeTable(adoptPtr(new HashTable(JSC::arrayPrototypeTable)))
, booleanPrototypeTable(adoptPtr(new HashTable(JSC::booleanPrototypeTable)))
@@ -650,8 +650,10 @@
if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) {
unsigned stackIndex = 0;
CallFrame* callFrame;
- for (callFrame = exec; callFrame && !callFrame->codeBlock(); callFrame = callFrame->callerFrame()->removeHostCallFrameFlag())
+ for (callFrame = exec; callFrame && !callFrame->codeBlock(); ) {
stackIndex++;
+ callFrame = callFrame->callerFrameSkippingVMEntrySentinel();
+ }
if (callFrame && callFrame->codeBlock()) {
stackFrame = stackTrace.at(stackIndex);
bytecodeOffset = stackFrame.bytecodeOffset;
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 92bfb5d..1abced8 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,20 @@
+2013-11-04 Michael Saboff <msaboff@apple.com>
+
+ Eliminate HostCall bit from JSC Stack CallerFrame
+ https://bugs.webkit.org/show_bug.cgi?id=123642
+
+ Reviewed by Geoffrey Garen.
+
+ Updated JavaScript stack walking as a result of the corresponding changes made in
+ JavaScriptCore.
+
+ * bindings/js/ScriptController.cpp:
+ (WebCore::ScriptController::shouldBypassMainWorldContentSecurityPolicy):
+ * bindings/js/ScriptDebugServer.cpp:
+ (WebCore::ScriptDebugServer::stepOutOfFunction):
+ (WebCore::ScriptDebugServer::returnEvent):
+ (WebCore::ScriptDebugServer::didExecuteProgram):
+
2013-11-04 Bem Jones-Bey <bjonesbe@adobe.com>
[css shapes] Fix support for shape-outside on a float with padding
diff --git a/Source/WebCore/bindings/js/ScriptController.cpp b/Source/WebCore/bindings/js/ScriptController.cpp
index e6c78c5..2c3ef93af 100644
--- a/Source/WebCore/bindings/js/ScriptController.cpp
+++ b/Source/WebCore/bindings/js/ScriptController.cpp
@@ -472,7 +472,7 @@
bool ScriptController::shouldBypassMainWorldContentSecurityPolicy()
{
CallFrame* callFrame = JSDOMWindow::commonVM()->topCallFrame;
- if (!callFrame || callFrame == CallFrame::noCaller())
+ if (callFrame == CallFrame::noCaller())
return false;
DOMWrapperWorld& domWrapperWorld = currentWorld(callFrame);
if (domWrapperWorld.isNormal())
diff --git a/Source/WebCore/bindings/js/ScriptDebugServer.cpp b/Source/WebCore/bindings/js/ScriptDebugServer.cpp
index 462db84..7d8fb8e 100644
--- a/Source/WebCore/bindings/js/ScriptDebugServer.cpp
+++ b/Source/WebCore/bindings/js/ScriptDebugServer.cpp
@@ -311,7 +311,7 @@
if (!m_paused)
return;
- m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrameNoFlags() : 0;
+ m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrameSkippingVMEntrySentinel() : 0;
m_doneProcessingDebuggerEvents = true;
}
@@ -567,9 +567,9 @@
// Treat stepping over a return statement like stepping out.
if (m_currentCallFrame == m_pauseOnCallFrame)
- m_pauseOnCallFrame = m_currentCallFrame->callerFrameNoFlags();
+ m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
- m_currentCallFrame = m_currentCallFrame->callerFrameNoFlags();
+ m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
}
void ScriptDebugServer::exception(CallFrame* callFrame, JSValue, bool hasHandler)
@@ -602,11 +602,11 @@
if (!m_currentCallFrame)
return;
if (m_currentCallFrame == m_pauseOnCallFrame) {
- m_pauseOnCallFrame = m_currentCallFrame->callerFrameNoFlags();
+ m_pauseOnCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
if (!m_currentCallFrame)
return;
}
- m_currentCallFrame = m_currentCallFrame->callerFrameNoFlags();
+ m_currentCallFrame = m_currentCallFrame->callerFrameSkippingVMEntrySentinel();
}
void ScriptDebugServer::didReachBreakpoint(CallFrame* callFrame)