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/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;
     };