Transition stack check JITStubs to CCallHelper functions
https://bugs.webkit.org/show_bug.cgi?id=122289

Reviewed by Filip Pizlo.

Replaced jit stubs cti_stack_check, cti_op_call_arityCheck and cti_op_construct_arityCheck with
jit operations operationStackCheck, operationCallArityCheck & operationConstructArityCheck.
Added new callOperationWithCallFrameRollbackOnException() in baseline and DFG JITs to call
these new functions.  Added code to unwind one frame in JIT::privateCompileExceptionHandlers() 
and JITCompiler::compileExceptionHandlers() for these cases that need to throw exceptions in
their caller frame when the stack is exhausted.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::andPtr): Added to handle masking a pointer with a literal.
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::and64): Added to handle masking a pointer with a literal.
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compileExceptionHandlers):
(JSC::DFG::JITCompiler::compileFunction):
(JSC::DFG::JITCompiler::linkFunction):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::exceptionCheckWithCallFrameRollback):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperationWithCallFrameRollbackOnException):
(JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheck):
(JSC::DFG::SpeculativeJIT::appendCallWithCallFrameRollbackOnException):
(JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheckSetResult):
(JSC::DFG::SpeculativeJIT::appendCallWithCallFrameRollbackOnExceptionSetResult):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* interpreter/CallFrame.h:
(JSC::ExecState::hostCallFrameFlag):
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::jitAssertIsNull):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::jitAssertIsNull):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
(JSC::JIT::privateCompileExceptionHandlers):
* jit/JIT.h:
(JSC::JIT::exceptionCheckWithCallFrameRollback):
* jit/JITInlines.h:
(JSC::JIT::appendCallWithCallFrameRollbackOnException):
(JSC::JIT::callOperationWithCallFrameRollbackOnException):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITStubs.cpp:
* jit/JITStubs.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@157050 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index c2d393d..013d11b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,54 @@
+2013-10-04  Michael Saboff  <msaboff@apple.com>
+
+        Transition stack check JITStubs to CCallHelper functions
+        https://bugs.webkit.org/show_bug.cgi?id=122289
+
+        Reviewed by Filip Pizlo.
+
+        Replaced jit stubs cti_stack_check, cti_op_call_arityCheck and cti_op_construct_arityCheck with
+        jit operations operationStackCheck, operationCallArityCheck & operationConstructArityCheck.
+        Added new callOperationWithCallFrameRollbackOnException() in baseline and DFG JITs to call
+        these new functions.  Added code to unwind one frame in JIT::privateCompileExceptionHandlers() 
+        and JITCompiler::compileExceptionHandlers() for these cases that need to throw exceptions in
+        their caller frame when the stack is exhausted.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::andPtr): Added to handle masking a pointer with a literal.
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::and64): Added to handle masking a pointer with a literal.
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::compileExceptionHandlers):
+        (JSC::DFG::JITCompiler::compileFunction):
+        (JSC::DFG::JITCompiler::linkFunction):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::exceptionCheckWithCallFrameRollback):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperationWithCallFrameRollbackOnException):
+        (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheck):
+        (JSC::DFG::SpeculativeJIT::appendCallWithCallFrameRollbackOnException):
+        (JSC::DFG::SpeculativeJIT::appendCallWithExceptionCheckSetResult):
+        (JSC::DFG::SpeculativeJIT::appendCallWithCallFrameRollbackOnExceptionSetResult):
+        * ftl/FTLLink.cpp:
+        (JSC::FTL::link):
+        * interpreter/CallFrame.h:
+        (JSC::ExecState::hostCallFrameFlag):
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::jitAssertIsNull):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::jitAssertIsNull):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        (JSC::JIT::privateCompileExceptionHandlers):
+        * jit/JIT.h:
+        (JSC::JIT::exceptionCheckWithCallFrameRollback):
+        * jit/JITInlines.h:
+        (JSC::JIT::appendCallWithCallFrameRollbackOnException):
+        (JSC::JIT::callOperationWithCallFrameRollbackOnException):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITStubs.cpp:
+        * jit/JITStubs.h:
+
 2013-10-07  Filip Pizlo  <fpizlo@apple.com>
 
         ASSERTION FAILED: isUInt32() in jsc-layout-tests.yaml/js/script-tests/dfg-uint32-to-number-in-middle-of-copy-propagation.js.layout-dfg-eager-no-cjit
diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.h b/Source/JavaScriptCore/assembler/MacroAssembler.h
index d05edeb..d775f82 100644
--- a/Source/JavaScriptCore/assembler/MacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/MacroAssembler.h
@@ -374,7 +374,12 @@
     {
         and32(imm, srcDest);
     }
-    
+
+    void andPtr(TrustedImmPtr imm, RegisterID srcDest)
+    {
+        and32(TrustedImm32(imm), srcDest);
+    }
+
     void negPtr(RegisterID dest)
     {
         neg32(dest);
@@ -633,6 +638,11 @@
         and64(imm, srcDest);
     }
     
+    void andPtr(TrustedImmPtr imm, RegisterID srcDest)
+    {
+        and64(imm, srcDest);
+    }
+    
     void lshiftPtr(Imm32 imm, RegisterID srcDest)
     {
         lshift64(trustedImm32ForShift(imm), srcDest);
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
index 29d34f2..f0f4616 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
@@ -224,7 +224,13 @@
     {
         m_assembler.andq_ir(imm.m_value, srcDest);
     }
-    
+
+    void and64(TrustedImmPtr imm, RegisterID srcDest)
+    {
+        move(imm, scratchRegister);
+        and64(scratchRegister, srcDest);
+    }
+
     void lshift64(TrustedImm32 imm, RegisterID dest)
     {
         m_assembler.shlq_i8r(imm.m_value, dest);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 2809295..b0adef1 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -119,13 +119,28 @@
 
 void JITCompiler::compileExceptionHandlers()
 {
-    if (m_exceptionChecks.empty())
+    if (m_exceptionChecks.empty() && m_exceptionChecksWithCallFrameRollback.empty())
         return;
-    
-    m_exceptionChecks.link(this);
+
+    Jump doLookup;
+
+    if (!m_exceptionChecksWithCallFrameRollback.empty()) {
+        // Remove hostCallFrameFlag from caller.
+        m_exceptionChecksWithCallFrameRollback.link(this);
+        emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, GPRInfo::argumentGPR0);
+        andPtr(TrustedImmPtr(reinterpret_cast<void*>(~CallFrame::hostCallFrameFlag())), GPRInfo::argumentGPR0);
+        doLookup = jump();
+    }
+
+    if (!m_exceptionChecks.empty())
+        m_exceptionChecks.link(this);
 
     // lookupExceptionHandler is passed one argument, the exec (the CallFrame*).
     move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+    if (doLookup.isSet())
+        doLookup.link(this);
+
 #if CPU(X86)
     // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer!
     poke(GPRInfo::argumentGPR0);
@@ -371,7 +386,7 @@
     poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
 
     emitStoreCodeOrigin(CodeOrigin(0));
-    m_callStackCheck = call();
+    m_speculative->callOperationWithCallFrameRollbackOnException(operationStackCheck, m_codeBlock);
     jump(fromStackCheck);
     
     // The fast entry point into a function does not check the correct number of arguments
@@ -387,7 +402,7 @@
     move(stackPointerRegister, GPRInfo::argumentGPR0);
     poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
     emitStoreCodeOrigin(CodeOrigin(0));
-    m_callArityCheck = call();
+    m_speculative->callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck, GPRInfo::regT0);
     branchTest32(Zero, GPRInfo::regT0).linkTo(fromArityCheck, this);
     emitStoreCodeOrigin(CodeOrigin(0));
     m_callArityFixup = call();
@@ -418,9 +433,6 @@
     m_jitCode->shrinkToFit();
     codeBlock()->shrinkToFit(CodeBlock::LateShrink);
     
-    // FIXME: switch the stack check & arity check over to DFGOpertaion style calls, not JIT stubs.
-    linkBuffer->link(m_callStackCheck, cti_stack_check);
-    linkBuffer->link(m_callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
     linkBuffer->link(m_callArityFixup, FunctionPtr((m_vm->getCTIStub(arityFixup)).code().executableAddress()));
     
     disassemble(*linkBuffer);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index 36445f9..34eb981 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -265,7 +265,12 @@
     {
         m_exceptionChecks.append(emitExceptionCheck());
     }
-    
+
+    void exceptionCheckWithCallFrameRollback()
+    {
+        m_exceptionChecksWithCallFrameRollback.append(emitExceptionCheck());
+    }
+
     // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
     void fastExceptionCheck()
     {
@@ -396,6 +401,7 @@
     // Count of the number of CallRecords with exception handlers.
     Vector<CallLinkRecord> m_calls;
     JumpList m_exceptionChecks;
+    JumpList m_exceptionChecksWithCallFrameRollback;
     
     Vector<Label> m_blockHeads;
 
@@ -424,8 +430,6 @@
     Vector<OSRExitCompilationInfo> m_exitCompilationInfo;
     Vector<Vector<Label> > m_exitSiteLabels;
     
-    Call m_callStackCheck;
-    Call m_callArityCheck;
     Call m_callArityFixup;
     Label m_arityCheck;
     OwnPtr<SpeculativeJIT> m_speculative;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index d79a98a..2f454fe 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1110,6 +1110,18 @@
         return appendCall(operation);
     }
 
+    JITCompiler::Call callOperationWithCallFrameRollbackOnException(V_JITOperation_ECb operation, void* pointer)
+    {
+        m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer));
+        return appendCallWithCallFrameRollbackOnException(operation);
+    }
+
+    JITCompiler::Call callOperationWithCallFrameRollbackOnException(Z_JITOperation_E operation, GPRReg result)
+    {
+        m_jit.setupArgumentsExecState();
+        return appendCallWithCallFrameRollbackOnExceptionSetResult(operation, result);
+    }
+
     template<typename FunctionType, typename ArgumentType1>
     JITCompiler::Call callOperation(FunctionType operation, NoResultTag, ArgumentType1 arg1)
     {
@@ -1721,10 +1733,25 @@
         m_jit.exceptionCheck();
         return call;
     }
+    JITCompiler::Call appendCallWithCallFrameRollbackOnException(const FunctionPtr& function)
+    {
+        prepareForExternalCall();
+        m_jit.emitStoreCodeOrigin(m_currentNode->codeOrigin);
+        JITCompiler::Call call = m_jit.appendCall(function);
+        m_jit.exceptionCheckWithCallFrameRollback();
+        return call;
+    }
     JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result)
     {
         JITCompiler::Call call = appendCallWithExceptionCheck(function);
-        if (result != InvalidGPRReg)
+        if ((result != InvalidGPRReg) && (result != GPRInfo::returnValueGPR))
+            m_jit.move(GPRInfo::returnValueGPR, result);
+        return call;
+    }
+    JITCompiler::Call appendCallWithCallFrameRollbackOnExceptionSetResult(const FunctionPtr& function, GPRReg result)
+    {
+        JITCompiler::Call call = appendCallWithCallFrameRollbackOnException(function);
+        if ((result != InvalidGPRReg) && (result != GPRInfo::returnValueGPR))
             m_jit.move(GPRInfo::returnValueGPR, result);
         return call;
     }
diff --git a/Source/JavaScriptCore/ftl/FTLLink.cpp b/Source/JavaScriptCore/ftl/FTLLink.cpp
index bc37b74..e150416 100644
--- a/Source/JavaScriptCore/ftl/FTLLink.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLink.cpp
@@ -33,6 +33,7 @@
 #include "CodeBlockWithJITType.h"
 #include "DFGCommon.h"
 #include "FTLJITCode.h"
+#include "JITOperations.h"
 #include "JITStubs.h"
 #include "LinkBuffer.h"
 #include "VirtualRegister.h"
@@ -95,18 +96,21 @@
         jit.ret();
         
         stackCheck.link(&jit);
-        jit.move(CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
-        jit.poke(
-            GPRInfo::callFrameRegister,
-            OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
-        
+        jit.move(CCallHelpers::TrustedImmPtr(codeBlock), GPRInfo::argumentGPR1);
+        jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
         jit.store32(
             CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
             CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
+        jit.storePtr(GPRInfo::callFrameRegister, &state.graph.m_vm.topCallFrame);
         CCallHelpers::Call callStackCheck = jit.call();
+#if !ASSERT_DISABLED
         // FIXME: need to make this call register with exception handling somehow. This is
         // part of a bigger problem: FTL should be able to handle exceptions.
         // https://bugs.webkit.org/show_bug.cgi?id=113622
+        // Until then, use a JIT ASSERT.
+        jit.load64(state.graph.m_vm.addressOfException(), GPRInfo::regT0);
+        jit.jitAssertIsNull(GPRInfo::regT0);
+#endif
         jit.jump(fromStackCheck);
         
         arityCheck = jit.label();
@@ -118,24 +122,29 @@
             CCallHelpers::AboveOrEqual, GPRInfo::regT1,
             CCallHelpers::TrustedImm32(codeBlock->numParameters()))
             .linkTo(fromArityCheck, &jit);
-        jit.move(CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
-        jit.poke(
-            GPRInfo::callFrameRegister,
-            OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+        jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
         jit.store32(
             CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)),
             CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
+        jit.storePtr(GPRInfo::callFrameRegister, &state.graph.m_vm.topCallFrame);
         CCallHelpers::Call callArityCheck = jit.call();
+#if !ASSERT_DISABLED
         // FIXME: need to make this call register with exception handling somehow. This is
         // part of a bigger problem: FTL should be able to handle exceptions.
         // https://bugs.webkit.org/show_bug.cgi?id=113622
+        // Until then, use a JIT ASSERT.
+        jit.load64(state.graph.m_vm.addressOfException(), GPRInfo::regT1);
+        jit.jitAssertIsNull(GPRInfo::regT1);
+#endif
+        if (GPRInfo::returnValueGPR != GPRInfo::regT0)
+            jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0);
         jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0).linkTo(fromArityCheck, &jit);
         CCallHelpers::Call callArityFixup = jit.call();
         jit.jump(fromArityCheck);
         
         linkBuffer = adoptPtr(new LinkBuffer(state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed));
-        linkBuffer->link(callStackCheck, cti_stack_check);
-        linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
+        linkBuffer->link(callStackCheck, operationStackCheck);
+        linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
         linkBuffer->link(callArityFixup, FunctionPtr((state.graph.m_vm.getCTIStub(arityFixup)).code().executableAddress()));
         break;
     }
diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h
index d53b6aa..7a97d45 100644
--- a/Source/JavaScriptCore/interpreter/CallFrame.h
+++ b/Source/JavaScriptCore/interpreter/CallFrame.h
@@ -269,6 +269,7 @@
         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; }
 
         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); }
diff --git a/Source/JavaScriptCore/jit/AssemblyHelpers.cpp b/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
index 2240143..bc44d9f 100644
--- a/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
+++ b/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
@@ -153,6 +153,13 @@
     breakpoint();
     checkCFR.link(this);
 }
+
+void AssemblyHelpers::jitAssertIsNull(GPRReg gpr)
+{
+    Jump checkNull = branchTestPtr(Zero, gpr);
+    breakpoint();
+    checkNull.link(this);
+}
 #endif // !ASSERT_DISABLED
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/jit/AssemblyHelpers.h b/Source/JavaScriptCore/jit/AssemblyHelpers.h
index 06e7ec7..10c809d 100644
--- a/Source/JavaScriptCore/jit/AssemblyHelpers.h
+++ b/Source/JavaScriptCore/jit/AssemblyHelpers.h
@@ -270,6 +270,7 @@
     void jitAssertIsJSDouble(GPRReg);
     void jitAssertIsCell(GPRReg);
     void jitAssertHasValidCallFrame();
+    void jitAssertIsNull(GPRReg);
 #else
     void jitAssertIsInt32(GPRReg) { }
     void jitAssertIsJSInt32(GPRReg) { }
@@ -277,6 +278,7 @@
     void jitAssertIsJSDouble(GPRReg) { }
     void jitAssertIsCell(GPRReg) { }
     void jitAssertHasValidCallFrame() { }
+    void jitAssertIsNull(GPRReg) { }
 #endif
 
     // These methods convert between doubles, and doubles boxed and JSValues.
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index ed158ac..c6dc90f 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -634,7 +634,7 @@
     if (m_codeBlock->codeType() == FunctionCode) {
         stackCheck.link(this);
         m_bytecodeOffset = 0;
-        JITStubCall(this, cti_stack_check).call();
+        callOperationWithCallFrameRollbackOnException(operationStackCheck, m_codeBlock);
 #ifndef NDEBUG
         m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
 #endif
@@ -651,7 +651,9 @@
 
         m_bytecodeOffset = 0;
 
-        JITStubCall(this, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck).call(regT0);
+        callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
+        if (returnValueRegister != regT0)
+            move(returnValueRegister, regT0);
         branchTest32(Zero, regT0).linkTo(beginLabel, this);
         emitNakedCall(m_vm->getCTIStub(arityFixup).code());
 
@@ -821,13 +823,28 @@
 
 void JIT::privateCompileExceptionHandlers()
 {
-    if (m_exceptionChecks.empty())
+    if (m_exceptionChecks.empty() && m_exceptionChecksWithCallFrameRollback.empty())
         return;
-    
-    m_exceptionChecks.link(this);
+
+    Jump doLookup;
+
+    if (!m_exceptionChecksWithCallFrameRollback.empty()) {
+        // Remove hostCallFlag from caller
+        m_exceptionChecksWithCallFrameRollback.link(this);
+        emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, GPRInfo::argumentGPR0);
+        andPtr(TrustedImmPtr(reinterpret_cast<void *>(~CallFrame::hostCallFrameFlag())), GPRInfo::argumentGPR0);
+        doLookup = jump();
+    }
+
+    if (!m_exceptionChecks.empty())
+        m_exceptionChecks.link(this);
     
     // lookupExceptionHandler is passed one argument, the exec (the CallFrame*).
     move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+    if (doLookup.isSet())
+        doLookup.link(this);
+
 #if CPU(X86)
     // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer!
     poke(GPRInfo::argumentGPR0);
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 8093a48..f6dc030 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -439,6 +439,11 @@
             m_exceptionChecks.append(emitExceptionCheck());
         }
 
+        void exceptionCheckWithCallFrameRollback()
+        {
+            m_exceptionChecksWithCallFrameRollback.append(emitExceptionCheck());
+        }
+
         void privateCompileExceptionHandlers();
 
         static bool isDirectPutById(StructureStubInfo*);
@@ -859,10 +864,12 @@
         void linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator&, int virtualRegisterIndex);
 
         MacroAssembler::Call appendCallWithExceptionCheck(const FunctionPtr&);
+        MacroAssembler::Call appendCallWithCallFrameRollbackOnException(const FunctionPtr&);
         MacroAssembler::Call appendCallWithExceptionCheckSetJSValueResult(const FunctionPtr&, int);
         MacroAssembler::Call callOperation(J_JITOperation_E, int);
         MacroAssembler::Call callOperation(J_JITOperation_EP, int, void*);
-        MacroAssembler::Call callOperation(V_JITOperation_EP, void*);
+        MacroAssembler::Call callOperationWithCallFrameRollbackOnException(V_JITOperation_ECb, CodeBlock*);
+        MacroAssembler::Call callOperationWithCallFrameRollbackOnException(Z_JITOperation_E);
 
         Jump checkStructure(RegisterID reg, Structure* structure);
 
@@ -929,6 +936,7 @@
         Vector<SwitchRecord> m_switches;
 
         JumpList m_exceptionChecks;
+        JumpList m_exceptionChecksWithCallFrameRollback;
 
         unsigned m_propertyAccessInstructionIndex;
         unsigned m_byValInstructionIndex;
diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h
index 2ed28bd..34039ee 100644
--- a/Source/JavaScriptCore/jit/JITInlines.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -212,6 +212,14 @@
     return call;
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithCallFrameRollbackOnException(const FunctionPtr& function)
+{
+    updateTopCallFrame(); // The callee is responsible for setting topCallFrame to their caller
+    MacroAssembler::Call call = appendCall(function);
+    exceptionCheckWithCallFrameRollback();
+    return call;
+}
+
 ALWAYS_INLINE MacroAssembler::Call JIT::appendCallWithExceptionCheckSetJSValueResult(const FunctionPtr& function, int dst)
 {
     MacroAssembler::Call call = appendCallWithExceptionCheck(function);
@@ -235,12 +243,18 @@
     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
 }
 
-ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EP operation, void* pointer)
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperationWithCallFrameRollbackOnException(V_JITOperation_ECb operation, CodeBlock* pointer)
 {
     setupArgumentsWithExecState(TrustedImmPtr(pointer));
-    return appendCallWithExceptionCheck(operation);
+    return appendCallWithCallFrameRollbackOnException(operation);
 }
-    
+
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperationWithCallFrameRollbackOnException(Z_JITOperation_E operation)
+{
+    setupArgumentsExecState();
+    return appendCallWithCallFrameRollbackOnException(operation);
+}
+
 ALWAYS_INLINE JIT::Jump JIT::checkStructure(RegisterID reg, Structure* structure)
 {
     return branchPtr(NotEqual, Address(reg, JSCell::structureOffset()), TrustedImmPtr(structure));
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index a87be25..676b6ea 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -38,6 +38,49 @@
 
 extern "C" {
 
+void JIT_OPERATION operationStackCheck(ExecState* exec, CodeBlock* codeBlock)
+{
+    // 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());
+
+    JSStack& stack = vm->interpreter->stack();
+
+    if (UNLIKELY(!stack.grow(&exec->registers()[-codeBlock->m_numCalleeRegisters])))
+        vm->throwException(callerFrame, createStackOverflowError(callerFrame));
+}
+
+int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec)
+{
+    VM* vm = &exec->vm();
+    CallFrame* callerFrame = exec->callerFrame();
+    NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
+
+    JSStack& stack = vm->interpreter->stack();
+
+    int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall);
+    if (missingArgCount < 0)
+        vm->throwException(callerFrame, createStackOverflowError(callerFrame));
+
+    return missingArgCount;
+}
+
+int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec)
+{
+    VM* vm = &exec->vm();
+    CallFrame* callerFrame = exec->callerFrame();
+    NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
+
+    JSStack& stack = vm->interpreter->stack();
+
+    int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct);
+    if (missingArgCount < 0)
+        vm->throwException(callerFrame, createStackOverflowError(callerFrame));
+
+    return missingArgCount;
+}
+
 EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, StringImpl* uid)
 {
     VM* vm = &exec->vm();
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index e014236..90eaa8a 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -50,6 +50,7 @@
     J: JSValue
     P: pointer (void*)
     C: JSCell*
+    Cb: CodeBlock*
     A: JSArray*
     S: size_t
     Z: int32_t
@@ -94,6 +95,7 @@
 typedef double JIT_OPERATION (*D_JITOperation_ZZ)(int32_t, int32_t);
 typedef double JIT_OPERATION (*D_JITOperation_EJ)(ExecState*, EncodedJSValue);
 typedef int32_t JIT_OPERATION (*Z_JITOperation_D)(double);
+typedef int32_t JIT_OPERATION (*Z_JITOperation_E)(ExecState*);
 typedef size_t JIT_OPERATION (*S_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef size_t JIT_OPERATION (*S_JITOperation_EJ)(ExecState*, EncodedJSValue);
 typedef size_t JIT_OPERATION (*S_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -101,7 +103,7 @@
 typedef void JIT_OPERATION (*V_JITOperation_E)(ExecState*);
 typedef void JIT_OPERATION (*V_JITOperation_EOZD)(ExecState*, JSObject*, int32_t, double);
 typedef void JIT_OPERATION (*V_JITOperation_EOZJ)(ExecState*, JSObject*, int32_t, EncodedJSValue);
-typedef void JIT_OPERATION (*V_JITOperation_EP)(ExecState*, void*);
+typedef void JIT_OPERATION (*V_JITOperation_ECb)(ExecState*, CodeBlock*);
 typedef void JIT_OPERATION (*V_JITOperation_EC)(ExecState*, JSCell*);
 typedef void JIT_OPERATION (*V_JITOperation_ECIcf)(ExecState*, JSCell*, InlineCallFrame*);
 typedef void JIT_OPERATION (*V_JITOperation_ECCIcf)(ExecState*, JSCell*, JSCell*, InlineCallFrame*);
@@ -173,6 +175,9 @@
 #endif
 JITHandlerEncoded JIT_OPERATION lookupExceptionHandler(ExecState*) WTF_INTERNAL;
 
+void JIT_OPERATION operationStackCheck(ExecState*, CodeBlock*) WTF_INTERNAL;
+int32_t JIT_OPERATION operationCallArityCheck(ExecState*) WTF_INTERNAL;
+int32_t JIT_OPERATION operationConstructArityCheck(ExecState*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetById(ExecState*, EncodedJSValue, StringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue, StringImpl*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState*, EncodedJSValue, StringImpl*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 3f3297c..f599acb 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -436,19 +436,6 @@
     }
 }
 
-DEFINE_STUB_FUNCTION(void*, stack_check)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
-    CallFrame* callFrame = stackFrame.callFrame;
-
-    if (UNLIKELY(!stackFrame.stack->grow(&callFrame->registers()[-callFrame->codeBlock()->m_numCalleeRegisters]))) {
-        ErrorWithExecFunctor functor = ErrorWithExecFunctor(createStackOverflowError);
-        return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS, &functor);
-    }
-
-    return callFrame;
-}
-
 DEFINE_STUB_FUNCTION(JSObject*, op_new_object)
 {
     STUB_INIT_STACK_FRAME(stackFrame);
@@ -1224,34 +1211,6 @@
     return result;
 }
 
-DEFINE_STUB_FUNCTION(int, op_call_arityCheck)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
-
-    CallFrame* callFrame = stackFrame.callFrame;
-
-    int missingArgCount = CommonSlowPaths::arityCheckFor(callFrame, stackFrame.stack, CodeForCall);
-    if (missingArgCount < 0) {
-        ErrorWithExecFunctor functor = ErrorWithExecFunctor(createStackOverflowError);
-        return throwExceptionFromOpCall<int>(stackFrame, callFrame, STUB_RETURN_ADDRESS, &functor);
-    }
-    return missingArgCount;
-}
-
-DEFINE_STUB_FUNCTION(int, op_construct_arityCheck)
-{
-    STUB_INIT_STACK_FRAME(stackFrame);
-
-    CallFrame* callFrame = stackFrame.callFrame;
-
-    int missingArgCount = CommonSlowPaths::arityCheckFor(callFrame, stackFrame.stack, CodeForConstruct);
-    if (missingArgCount < 0) {
-        ErrorWithExecFunctor functor = ErrorWithExecFunctor(createStackOverflowError);
-        return throwExceptionFromOpCall<int>(stackFrame, callFrame, STUB_RETURN_ADDRESS, &functor);
-    }
-    return missingArgCount;
-}
-
 inline void* lazyLinkFor(CallFrame* callFrame, CodeSpecializationKind kind)
 {
     JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h
index 0949f44..3949c65 100644
--- a/Source/JavaScriptCore/jit/JITStubs.h
+++ b/Source/JavaScriptCore/jit/JITStubs.h
@@ -392,15 +392,12 @@
 #if ENABLE(DFG_JIT)
 void JIT_STUB cti_optimize(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 #endif
-int JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION) WTF_INTERNAL;
-int JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_call_jitCompile(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_construct_jitCompile(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_switch_char(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_switch_imm(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_switch_string(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_op_throw(STUB_ARGS_DECLARATION) WTF_INTERNAL;
-void* JIT_STUB cti_stack_check(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_vm_lazyLinkCall(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_vm_lazyLinkClosureCall(STUB_ARGS_DECLARATION) WTF_INTERNAL;
 void* JIT_STUB cti_vm_lazyLinkConstruct(STUB_ARGS_DECLARATION) WTF_INTERNAL;