Bug 39898 - Move arity check into callee.
Reviewed by Sam Weinig.
We can reduce the size of the virtual call trampolines by moving the arity check
into the callee functions. As a following step we will be able to remove the
check for native function / codeblocks by performing translation in a lazy stub.
* interpreter/CallFrame.h:
(JSC::ExecState::init):
(JSC::ExecState::setReturnPC):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
(JSC::JIT::linkCall):
(JSC::JIT::linkConstruct):
* jit/JIT.h:
(JSC::JIT::compile):
* jit/JITOpcodes.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.cpp:
(JSC::FunctionExecutable::generateJITCodeForCall):
(JSC::FunctionExecutable::generateJITCodeForConstruct):
(JSC::FunctionExecutable::reparseExceptionInfo):
* runtime/Executable.h:
(JSC::NativeExecutable::NativeExecutable):
(JSC::FunctionExecutable::generatedJITCodeForCallWithArityCheck):
(JSC::FunctionExecutable::generatedJITCodeForConstructWithArityCheck):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@60376 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 46027b0..30491e2 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,37 @@
+2010-05-28 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Bug 39898 - Move arity check into callee.
+
+ We can reduce the size of the virtual call trampolines by moving the arity check
+ into the callee functions. As a following step we will be able to remove the
+ check for native function / codeblocks by performing translation in a lazy stub.
+
+ * interpreter/CallFrame.h:
+ (JSC::ExecState::init):
+ (JSC::ExecState::setReturnPC):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompile):
+ (JSC::JIT::linkCall):
+ (JSC::JIT::linkConstruct):
+ * jit/JIT.h:
+ (JSC::JIT::compile):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::privateCompileCTIMachineTrampolines):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::privateCompileCTIMachineTrampolines):
+ * jit/JITStubs.cpp:
+ (JSC::DEFINE_STUB_FUNCTION):
+ * runtime/Executable.cpp:
+ (JSC::FunctionExecutable::generateJITCodeForCall):
+ (JSC::FunctionExecutable::generateJITCodeForConstruct):
+ (JSC::FunctionExecutable::reparseExceptionInfo):
+ * runtime/Executable.h:
+ (JSC::NativeExecutable::NativeExecutable):
+ (JSC::FunctionExecutable::generatedJITCodeForCallWithArityCheck):
+ (JSC::FunctionExecutable::generatedJITCodeForConstructWithArityCheck):
+
2010-05-27 Luiz Agostini <luiz.agostini@openbossa.org>
Reviewed by Darin Adler.
diff --git a/JavaScriptCore/interpreter/CallFrame.h b/JavaScriptCore/interpreter/CallFrame.h
index bde4072..66045e2 100644
--- a/JavaScriptCore/interpreter/CallFrame.h
+++ b/JavaScriptCore/interpreter/CallFrame.h
@@ -125,7 +125,7 @@
setCodeBlock(codeBlock);
setScopeChain(scopeChain);
setCallerFrame(callerFrame);
- static_cast<Register*>(this)[RegisterFile::ReturnPC] = vPC; // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
+ setReturnPC(vPC); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
setArgumentCount(argc); // original argument count (for the sake of the "arguments" object)
setCallee(function);
}
@@ -142,6 +142,7 @@
void setArgumentCount(int count) { static_cast<Register*>(this)[RegisterFile::ArgumentCount] = Register::withInt(count); }
void setCallee(JSFunction* callee) { static_cast<Register*>(this)[RegisterFile::Callee] = callee; }
void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[RegisterFile::CodeBlock] = codeBlock; }
+ void setReturnPC(void* value) { static_cast<Register*>(this)[RegisterFile::ReturnPC] = (Instruction*)value; }
private:
static const intptr_t HostCallFrameFlag = 1;
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index a6d817a..5d96847 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -456,17 +456,19 @@
#endif
}
-JITCode JIT::privateCompile()
+JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck)
{
+ // Could use a pop_m, but would need to offset the following instruction if so.
+ preserveReturnAddressAfterCall(regT2);
+ emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
+
+ Label beginLabel(this);
+
sampleCodeBlock(m_codeBlock);
#if ENABLE(OPCODE_SAMPLING)
sampleInstruction(m_codeBlock->instructions().begin());
#endif
- // Could use a pop_m, but would need to offset the following instruction if so.
- preserveReturnAddressAfterCall(regT2);
- emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
-
Jump registerFileCheck;
if (m_codeBlock->codeType() == FunctionCode) {
// In the case of a fast linked call, we do not set this up in the caller.
@@ -483,6 +485,8 @@
privateCompileLinkPass();
privateCompileSlowCases();
+ Label arityCheck;
+ Call callArityCheck;
if (m_codeBlock->codeType() == FunctionCode) {
registerFileCheck.link(this);
m_bytecodeOffset = 0;
@@ -491,6 +495,15 @@
m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
#endif
jump(functionBody);
+
+ arityCheck = label();
+ preserveReturnAddressAfterCall(regT2);
+ emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
+ branch32(Equal, regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(beginLabel, this);
+ restoreArgumentReference();
+ callArityCheck = call();
+ move(regT0, callFrameRegister);
+ jump(beginLabel);
}
ASSERT(m_jmpTable.isEmpty());
@@ -569,6 +582,11 @@
info.callReturnLocation = m_codeBlock->structureStubInfo(m_methodCallCompilationInfo[i].propertyAccessIndex).callReturnLocation;
}
+ if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck) {
+ patchBuffer.link(callArityCheck, FunctionPtr(m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck));
+ *functionEntryArityCheck = patchBuffer.locationOf(arityCheck);
+ }
+
return patchBuffer.finalizeCode();
}
@@ -602,7 +620,7 @@
#endif
}
-void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
+void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
{
RepatchBuffer repatchBuffer(callerCodeBlock);
@@ -615,14 +633,14 @@
calleeCodeBlock->addCaller(callLinkInfo);
repatchBuffer.repatch(callLinkInfo->hotPathBegin, callee);
- repatchBuffer.relink(callLinkInfo->hotPathOther, code.addressForCall());
+ repatchBuffer.relink(callLinkInfo->hotPathOther, code);
}
// patch the call so we do not continue to try to link.
repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs.ctiVirtualCall());
}
-void JIT::linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
+void JIT::linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
{
RepatchBuffer repatchBuffer(callerCodeBlock);
@@ -635,7 +653,7 @@
calleeCodeBlock->addCaller(callLinkInfo);
repatchBuffer.repatch(callLinkInfo->hotPathBegin, callee);
- repatchBuffer.relink(callLinkInfo->hotPathOther, code.addressForCall());
+ repatchBuffer.relink(callLinkInfo->hotPathOther, code);
}
// patch the call so we do not continue to try to link.
diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h
index da4c98b..529a1d6 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -178,9 +178,9 @@
static const int patchGetByIdDefaultOffset = 256;
public:
- static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock)
+ static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock, CodePtr* functionEntryArityCheck = 0)
{
- return JIT(globalData, codeBlock).privateCompile();
+ return JIT(globalData, codeBlock).privateCompile(functionEntryArityCheck);
}
static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
@@ -239,8 +239,8 @@
return jit.privateCompilePatchGetArrayLength(returnAddress);
}
- static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode&, CallLinkInfo*, int callerArgCount, JSGlobalData*);
- static void linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode&, CallLinkInfo*, int callerArgCount, JSGlobalData*);
+ static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
+ static void linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
static void unlinkCallOrConstruct(CallLinkInfo*);
private:
@@ -260,7 +260,7 @@
void privateCompileMainPass();
void privateCompileLinkPass();
void privateCompileSlowCases();
- JITCode privateCompile();
+ JITCode privateCompile(CodePtr* functionEntryArityCheck);
void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp
index 6534901..2d938d0 100644
--- a/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/JavaScriptCore/jit/JITOpcodes.cpp
@@ -78,9 +78,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
- Jump hasCodeBlock1 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+ Jump hasCodeBlock1 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction1 = call();
@@ -89,20 +87,6 @@
restoreReturnAddressBeforeReturn(regT3);
hasCodeBlock1.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck1 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay1.link(this);
-
- isNativeFunc1.link(this);
-
preserveReturnAddressAfterCall(regT3);
emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
@@ -117,9 +101,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
- Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+ Jump hasCodeBlock2 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction2 = call();
@@ -128,20 +110,6 @@
restoreReturnAddressBeforeReturn(regT3);
hasCodeBlock2.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck2 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay2.link(this);
-
- isNativeFunc2.link(this);
-
preserveReturnAddressAfterCall(regT3);
emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
@@ -156,9 +124,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
- Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+ Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction3 = call();
@@ -166,23 +132,8 @@
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
hasCodeBlock3.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck3 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay3.link(this);
- isNativeFunc3.link(this);
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCall)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
jump(regT0);
// VirtualConstruct Trampoline
@@ -192,9 +143,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
- Jump hasCodeBlock4 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+ Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction4 = call();
@@ -202,23 +151,8 @@
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
hasCodeBlock4.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck4 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay4.link(this);
- isNativeFunc4.link(this);
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstruct)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
jump(regT0);
// NativeCall Trampoline
@@ -240,16 +174,12 @@
patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
#endif
#if ENABLE(JIT_OPTIMIZE_CALL)
- patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck));
patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_jitCompile));
patchBuffer.link(callLazyLinkCall1, FunctionPtr(cti_vm_lazyLinkCall));
- patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_construct_arityCheck));
patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_construct_jitCompile));
patchBuffer.link(callLazyLinkCall2, FunctionPtr(cti_vm_lazyLinkConstruct));
#endif
- patchBuffer.link(callArityCheck3, FunctionPtr(cti_op_call_arityCheck));
patchBuffer.link(callJSFunction3, FunctionPtr(cti_op_call_jitCompile));
- patchBuffer.link(callArityCheck4, FunctionPtr(cti_op_construct_arityCheck));
patchBuffer.link(callJSFunction4, FunctionPtr(cti_op_construct_jitCompile));
CodeRef finalCode = patchBuffer.finalizeCode();
diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp
index f254c7e..f2bb351 100644
--- a/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -75,9 +75,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
- Jump hasCodeBlock1 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+ Jump hasCodeBlock1 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction1 = call();
@@ -86,25 +84,12 @@
restoreReturnAddressBeforeReturn(regT3);
hasCodeBlock1.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck1 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay1.link(this);
-
- isNativeFunc1.link(this);
-
preserveReturnAddressAfterCall(regT3);
emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
Call callLazyLinkCall1 = call();
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
// VirtualConstructLink Trampoline
@@ -114,9 +99,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
- Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+ Jump hasCodeBlock2 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction2 = call();
@@ -125,25 +108,12 @@
restoreReturnAddressBeforeReturn(regT3);
hasCodeBlock2.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck2 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay2.link(this);
-
- isNativeFunc2.link(this);
-
preserveReturnAddressAfterCall(regT3);
emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
Call callLazyLinkCall2 = call();
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
#endif // ENABLE(JIT_OPTIMIZE_CALL)
@@ -154,9 +124,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
- Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+ Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction3 = call();
@@ -165,22 +133,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
hasCodeBlock3.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck3 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay3.link(this);
-
- isNativeFunc3.link(this);
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCall)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
jump(regT0);
// VirtualConstruct Trampoline
@@ -190,9 +143,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump isNativeFunc4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
- Jump hasCodeBlock4 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+ Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
restoreArgumentReference();
Call callJSFunction4 = call();
@@ -201,22 +152,7 @@
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
hasCodeBlock4.link(this);
- // Check argCount matches callee arity.
- Jump arityCheckOkay4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- restoreArgumentReference();
- Call callArityCheck4 = call();
- move(regT0, callFrameRegister);
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay4.link(this);
-
- isNativeFunc4.link(this);
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstruct)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
jump(regT0);
// NativeCall Trampoline
@@ -238,16 +174,12 @@
patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
#endif
#if ENABLE(JIT_OPTIMIZE_CALL)
- patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck));
patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_jitCompile));
patchBuffer.link(callLazyLinkCall1, FunctionPtr(cti_vm_lazyLinkCall));
- patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_construct_arityCheck));
patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_construct_jitCompile));
patchBuffer.link(callLazyLinkCall2, FunctionPtr(cti_vm_lazyLinkConstruct));
#endif
- patchBuffer.link(callArityCheck3, FunctionPtr(cti_op_call_arityCheck));
patchBuffer.link(callJSFunction3, FunctionPtr(cti_op_call_jitCompile));
- patchBuffer.link(callArityCheck4, FunctionPtr(cti_op_construct_arityCheck));
patchBuffer.link(callJSFunction4, FunctionPtr(cti_op_construct_jitCompile));
CodeRef finalCode = patchBuffer.finalizeCode();
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index d5141eb..86aeefd 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -1844,6 +1844,7 @@
ASSERT(!callee->isHostFunction());
CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForCall();
int argCount = callFrame->argumentCount();
+ ReturnAddressPtr pc = callFrame->returnPC();
ASSERT(argCount != newCodeBlock->m_numParameters);
@@ -1858,7 +1859,7 @@
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
return 0;
}
@@ -1873,7 +1874,7 @@
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
return 0;
}
@@ -1887,6 +1888,7 @@
callFrame->setArgumentCount(argCount);
callFrame->setCallee(callee);
callFrame->setScopeChain(callee->scope().node());
+ callFrame->setReturnPC(pc.value());
ASSERT((void*)callFrame <= stackFrame.registerFile->end());
return callFrame;
@@ -1901,6 +1903,7 @@
ASSERT(!callee->isHostFunction());
CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForConstruct();
int argCount = callFrame->argumentCount();
+ ReturnAddressPtr pc = callFrame->returnPC();
ASSERT(argCount != newCodeBlock->m_numParameters);
@@ -1915,7 +1918,7 @@
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
return 0;
}
@@ -1930,7 +1933,7 @@
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
return 0;
}
@@ -1944,6 +1947,7 @@
callFrame->setArgumentCount(argCount);
callFrame->setCallee(callee);
callFrame->setScopeChain(callee->scope().node());
+ callFrame->setReturnPC(pc.value());
ASSERT((void*)callFrame <= stackFrame.registerFile->end());
return callFrame;
@@ -1956,19 +1960,26 @@
CallFrame* callFrame = stackFrame.callFrame;
JSFunction* callee = callFrame->callee();
ExecutableBase* executable = callee->executable();
- JITCode& jitCode = executable->generatedJITCodeForCall();
-
+
+ MacroAssemblerCodePtr codePtr;
CodeBlock* codeBlock = 0;
- if (!executable->isHostFunction())
+ if (executable->isHostFunction())
+ codePtr = executable->generatedJITCodeForCall().addressForCall();
+ else {
codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecodeForCall(stackFrame.callFrame, callee->scope().node());
+ if (callFrame->argumentCount() == codeBlock->m_numParameters)
+ codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForCall().addressForCall();
+ else
+ codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForCallWithArityCheck();
+ }
CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
if (!callLinkInfo->seenOnce())
callLinkInfo->setSeen();
else
- JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
+ JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
- return jitCode.addressForCall().executableAddress();
+ return codePtr.executableAddress();
}
DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct)
@@ -1977,19 +1988,26 @@
CallFrame* callFrame = stackFrame.callFrame;
JSFunction* callee = callFrame->callee();
ExecutableBase* executable = callee->executable();
- JITCode& jitCode = executable->generatedJITCodeForConstruct();
-
+
+ MacroAssemblerCodePtr codePtr;
CodeBlock* codeBlock = 0;
- if (!executable->isHostFunction())
+ if (executable->isHostFunction())
+ codePtr = executable->generatedJITCodeForConstruct().addressForCall();
+ else {
codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecodeForConstruct(stackFrame.callFrame, callee->scope().node());
+ if (callFrame->argumentCount() == codeBlock->m_numParameters)
+ codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForConstruct().addressForCall();
+ else
+ codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForConstructWithArityCheck();
+ }
CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
if (!callLinkInfo->seenOnce())
callLinkInfo->setSeen();
else
- JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
+ JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
- return jitCode.addressForCall().executableAddress();
+ return codePtr.executableAddress();
}
#endif // !ENABLE(JIT_OPTIMIZE_CALL)
diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp
index 8cb3c56..2176e36 100644
--- a/JavaScriptCore/runtime/Executable.cpp
+++ b/JavaScriptCore/runtime/Executable.cpp
@@ -188,7 +188,7 @@
void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
{
CodeBlock* codeBlock = &bytecodeForCall(exec, scopeChainNode);
- m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock);
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForCallWithArityCheck);
#if !ENABLE(OPCODE_SAMPLING)
if (!BytecodeGenerator::dumpsGeneratedCode())
@@ -199,7 +199,7 @@
void FunctionExecutable::generateJITCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
{
CodeBlock* codeBlock = &bytecodeForConstruct(exec, scopeChainNode);
- m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock);
+ m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForConstructWithArityCheck);
#if !ENABLE(OPCODE_SAMPLING)
if (!BytecodeGenerator::dumpsGeneratedCode())
diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h
index 146cd00..39ddf49 100644
--- a/JavaScriptCore/runtime/Executable.h
+++ b/JavaScriptCore/runtime/Executable.h
@@ -86,6 +86,8 @@
protected:
JITCode m_jitCodeForCall;
JITCode m_jitCodeForConstruct;
+ MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+ MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
#endif
};
@@ -110,6 +112,8 @@
{
m_jitCodeForCall = callThunk;
m_jitCodeForConstruct = constructThunk;
+ m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
+ m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
}
NativeFunction m_function;
@@ -407,6 +411,20 @@
return m_jitCodeForConstruct;
}
+ MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
+ {
+ ASSERT(m_jitCodeForCall);
+ ASSERT(m_jitCodeForCallWithArityCheck);
+ return m_jitCodeForCallWithArityCheck;
+ }
+
+ MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
+ {
+ ASSERT(m_jitCodeForConstruct);
+ ASSERT(m_jitCodeForConstructWithArityCheck);
+ return m_jitCodeForConstructWithArityCheck;
+ }
+
private:
void generateJITCodeForCall(ExecState*, ScopeChainNode*);
void generateJITCodeForConstruct(ExecState*, ScopeChainNode*);