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;