summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/jit
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/jit')
-rw-r--r--JavaScriptCore/jit/JIT.cpp38
-rw-r--r--JavaScriptCore/jit/JIT.h27
-rw-r--r--JavaScriptCore/jit/JITCall.cpp112
-rw-r--r--JavaScriptCore/jit/JITCall32_64.cpp102
-rw-r--r--JavaScriptCore/jit/JITInlineMethods.h67
-rw-r--r--JavaScriptCore/jit/JITOpcodes.cpp487
-rw-r--r--JavaScriptCore/jit/JITOpcodes32_64.cpp647
-rw-r--r--JavaScriptCore/jit/JITStubs.cpp218
-rw-r--r--JavaScriptCore/jit/JITStubs.h25
9 files changed, 406 insertions, 1317 deletions
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index eeffd5c..5d96847 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -221,6 +221,8 @@ void JIT::privateCompileMainPass()
DEFINE_OP(op_call_varargs)
DEFINE_OP(op_catch)
DEFINE_OP(op_construct)
+ DEFINE_OP(op_get_callee)
+ DEFINE_OP(op_create_this)
DEFINE_OP(op_convert_this)
DEFINE_OP(op_init_arguments)
DEFINE_OP(op_create_arguments)
@@ -454,17 +456,19 @@ void JIT::privateCompileSlowCases()
#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.
@@ -481,6 +485,8 @@ JITCode JIT::privateCompile()
privateCompileLinkPass();
privateCompileSlowCases();
+ Label arityCheck;
+ Call callArityCheck;
if (m_codeBlock->codeType() == FunctionCode) {
registerFileCheck.link(this);
m_bytecodeOffset = 0;
@@ -489,6 +495,15 @@ JITCode JIT::privateCompile()
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());
@@ -567,6 +582,11 @@ JITCode JIT::privateCompile()
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();
}
@@ -600,7 +620,7 @@ void JIT::unlinkCallOrConstruct(CallLinkInfo* callLinkInfo)
#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);
@@ -613,14 +633,14 @@ void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* ca
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);
@@ -633,7 +653,7 @@ void JIT::linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBloc
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 928c80b..529a1d6 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -178,9 +178,9 @@ namespace JSC {
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 @@ namespace JSC {
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 @@ namespace JSC {
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);
@@ -269,6 +269,7 @@ namespace JSC {
void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress);
void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, TrampolineStructure *trampolines);
+ Label privateCompileCTINativeCall(JSGlobalData*, bool isConstruct = false);
CodePtr privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* data, NativeFunction func);
void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress);
@@ -280,11 +281,8 @@ namespace JSC {
void compileOpCall(OpcodeID, Instruction* instruction, unsigned callLinkInfoIndex);
void compileOpCallVarargs(Instruction* instruction);
void compileOpCallInitializeCallFrame();
- void compileOpCallSetupArgs(Instruction*);
- void compileOpCallVarargsSetupArgs(Instruction*);
void compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID);
void compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter);
- void compileOpConstructSetupArgs(Instruction*);
enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type);
@@ -654,6 +652,8 @@ namespace JSC {
void emit_op_call_put_result(Instruction*);
void emit_op_catch(Instruction*);
void emit_op_construct(Instruction*);
+ void emit_op_get_callee(Instruction*);
+ void emit_op_create_this(Instruction*);
void emit_op_convert_this(Instruction*);
void emit_op_create_arguments(Instruction*);
void emit_op_debug(Instruction*);
@@ -803,16 +803,7 @@ namespace JSC {
void emitRightShift(Instruction*, bool isUnsigned);
void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned);
- /* These functions are deprecated: Please use JITStubCall instead. */
- void emitPutJITStubArg(RegisterID src, unsigned argumentNumber);
-#if USE(JSVALUE32_64)
- void emitPutJITStubArg(RegisterID tag, RegisterID payload, unsigned argumentNumber);
- void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2);
-#else
- void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch);
-#endif
- void emitPutJITStubArgConstant(unsigned value, unsigned argumentNumber);
- void emitPutJITStubArgConstant(void* value, unsigned argumentNumber);
+ /* This function is deprecated. */
void emitGetJITStubArg(unsigned argumentNumber, RegisterID dst);
void emitInitRegister(unsigned dst);
diff --git a/JavaScriptCore/jit/JITCall.cpp b/JavaScriptCore/jit/JITCall.cpp
index c0de9d1..5c2b308 100644
--- a/JavaScriptCore/jit/JITCall.cpp
+++ b/JavaScriptCore/jit/JITCall.cpp
@@ -49,48 +49,9 @@ namespace JSC {
void JIT::compileOpCallInitializeCallFrame()
{
store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
-
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT3); // newScopeChain
storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
- storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
-}
-
-void JIT::compileOpCallSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[2].u.operand;
- int registerOffset = instruction[3].u.operand;
-
- // ecx holds func
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArgConstant(argCount, 2);
- emitPutJITStubArgConstant(registerOffset, 1);
-}
-
-void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
-{
- int registerOffset = instruction[3].u.operand;
-
- // ecx holds func
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArg(regT1, 2);
- addPtr(Imm32(registerOffset), regT1, regT2);
- emitPutJITStubArg(regT2, 1);
-}
-
-void JIT::compileOpConstructSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[2].u.operand;
- int registerOffset = instruction[3].u.operand;
- int proto = instruction[4].u.operand;
- int thisRegister = instruction[5].u.operand;
-
- // ecx holds func
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArgConstant(registerOffset, 1);
- emitPutJITStubArgConstant(argCount, 2);
- emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
- emitPutJITStubArgConstant(thisRegister, 4);
+ storePtr(regT3, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
}
void JIT::emit_op_call_put_result(Instruction* instruction)
@@ -103,10 +64,11 @@ void JIT::compileOpCallVarargs(Instruction* instruction)
{
int callee = instruction[1].u.operand;
int argCountRegister = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
emitGetVirtualRegister(argCountRegister, regT1);
emitGetVirtualRegister(callee, regT0);
- compileOpCallVarargsSetupArgs(instruction);
+ addPtr(Imm32(registerOffset), regT1, regT2);
// Check for JSFunctions.
emitJumpSlowCaseIfNotJSCell(regT0);
@@ -128,7 +90,11 @@ void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iter
{
linkSlowCase(iter);
linkSlowCase(iter);
+
JITStubCall stubCall(this, cti_op_call_NotJSFunction);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(regT2);
+ stubCall.addArgument(regT1);
stubCall.call();
sampleCodeBlock(m_codeBlock);
@@ -156,22 +122,11 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
}
emitGetVirtualRegister(callee, regT0);
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
// Check for JSFunctions.
emitJumpSlowCaseIfNotJSCell(regT0);
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitGetVirtualRegister(callee, regT0);
- }
-
// Speculatively roll the callframe, assuming argCount will match the arity.
storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
@@ -187,9 +142,16 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
{
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
+
linkSlowCase(iter);
linkSlowCase(iter);
+
JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
stubCall.call();
sampleCodeBlock(m_codeBlock);
@@ -233,18 +195,6 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
// The following is the fast case, only used whan a callee can be linked.
- // In the case of OpConstruct, call out to a cti_ function to create the new object.
- if (opcodeID == op_construct) {
- int proto = instruction[4].u.operand;
- int thisRegister = instruction[5].u.operand;
-
- emitPutJITStubArg(regT0, 0);
- emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
- JITStubCall stubCall(this, cti_op_construct_JSConstruct);
- stubCall.call(thisRegister);
- emitGetVirtualRegister(callee, regT0);
- }
-
// Fast version of stack frame initialization, directly relative to edi.
// Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
@@ -267,50 +217,36 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
{
- int callee = instruction[1].u.operand;
int argCount = instruction[2].u.operand;
int registerOffset = instruction[3].u.operand;
linkSlowCase(iter);
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
-
// Fast check for JS function.
Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitGetVirtualRegister(callee, regT0);
- }
-
// Speculatively roll the callframe, assuming argCount will match the arity.
storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
move(Imm32(argCount), regT1);
- move(regT0, regT2);
-
m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs.ctiVirtualConstructLink() : m_globalData->jitStubs.ctiVirtualCallLink());
- // If not, we need an extra case in the if below!
- ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
-
// Done! - return back to the hot path.
- if (opcodeID == op_construct)
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
- else
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
+ emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
// This handles host functions
callLinkFailNotObject.link(this);
callLinkFailNotJSFunction.link(this);
- JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
+
+ JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
sampleCodeBlock(m_codeBlock);
}
diff --git a/JavaScriptCore/jit/JITCall32_64.cpp b/JavaScriptCore/jit/JITCall32_64.cpp
index 9b5451a..5f551cc 100644
--- a/JavaScriptCore/jit/JITCall32_64.cpp
+++ b/JavaScriptCore/jit/JITCall32_64.cpp
@@ -50,42 +50,9 @@ void JIT::compileOpCallInitializeCallFrame()
{
// regT0 holds callee, regT1 holds argCount
store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // scopeChain
-
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT3); // scopeChain
storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); // callee
- storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); // scopeChain
-}
-
-void JIT::compileOpCallSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[2].u.operand;
- int registerOffset = instruction[3].u.operand;
-
- emitPutJITStubArg(regT1, regT0, 0);
- emitPutJITStubArgConstant(registerOffset, 1);
- emitPutJITStubArgConstant(argCount, 2);
-}
-
-void JIT::compileOpConstructSetupArgs(Instruction* instruction)
-{
- int argCount = instruction[2].u.operand;
- int registerOffset = instruction[3].u.operand;
- int proto = instruction[4].u.operand;
- int thisRegister = instruction[5].u.operand;
-
- emitPutJITStubArg(regT1, regT0, 0);
- emitPutJITStubArgConstant(registerOffset, 1);
- emitPutJITStubArgConstant(argCount, 2);
- emitPutJITStubArgFromVirtualRegister(proto, 3, regT2, regT3);
- emitPutJITStubArgConstant(thisRegister, 4);
-}
-
-void JIT::compileOpCallVarargsSetupArgs(Instruction*)
-{
- emitPutJITStubArg(regT1, regT0, 0);
- emitPutJITStubArg(regT3, 1); // registerOffset
- emitPutJITStubArg(regT2, 2); // argCount
+ storePtr(regT3, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); // scopeChain
}
void JIT::emit_op_call_put_result(Instruction* instruction)
@@ -104,8 +71,6 @@ void JIT::compileOpCallVarargs(Instruction* instruction)
emitLoadPayload(argCountRegister, regT2); // argCount
addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
- compileOpCallVarargsSetupArgs(instruction);
-
emitJumpSlowCaseIfNotJSCell(callee, regT1);
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
@@ -130,6 +95,9 @@ void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCase
linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_call_NotJSFunction);
+ stubCall.addArgument(regT1, regT0);
+ stubCall.addArgument(regT3);
+ stubCall.addArgument(regT2);
stubCall.call();
sampleCodeBlock(m_codeBlock);
@@ -256,20 +224,9 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
emitLoad(callee, regT1, regT0);
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
-
emitJumpSlowCaseIfNotJSCell(callee, regT1);
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitLoad(callee, regT1, regT0);
- }
-
// Speculatively roll the callframe, assuming argCount will match the arity.
storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
@@ -286,11 +243,16 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
{
int callee = instruction[1].u.operand;
+ int argCount = instruction[2].u.operand;
+ int registerOffset = instruction[3].u.operand;
linkSlowCaseIfNotJSCell(iter, callee);
linkSlowCase(iter);
JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(callee);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
stubCall.call();
sampleCodeBlock(m_codeBlock);
@@ -334,21 +296,6 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca
// The following is the fast case, only used whan a callee can be linked.
- // In the case of OpConstruct, call out to a cti_ function to create the new object.
- if (opcodeID == op_construct) {
- int proto = instruction[4].u.operand;
- int thisRegister = instruction[5].u.operand;
-
- JITStubCall stubCall(this, cti_op_construct_JSConstruct);
- stubCall.addArgument(regT1, regT0);
- stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
- stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
- stubCall.addArgument(proto);
- stubCall.call(thisRegister);
-
- emitLoad(callee, regT1, regT0);
- }
-
// Fast version of stack frame initialization, directly relative to edi.
// Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT2);
@@ -377,22 +324,10 @@ void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>:
linkSlowCase(iter);
linkSlowCase(iter);
- // The arguments have been set up on the hot path for op_call_eval
- if (opcodeID == op_call)
- compileOpCallSetupArgs(instruction);
- else if (opcodeID == op_construct)
- compileOpConstructSetupArgs(instruction);
-
// Fast check for JS function.
Jump callLinkFailNotObject = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
- // First, in the case of a construct, allocate the new object.
- if (opcodeID == op_construct) {
- JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
- emitLoad(callee, regT1, regT0);
- }
-
// Speculatively roll the callframe, assuming argCount will match the arity.
storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
@@ -400,19 +335,20 @@ void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>:
m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs.ctiVirtualConstructLink() : m_globalData->jitStubs.ctiVirtualCallLink());
- // If not, we need an extra case in the if below!
- ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
-
// Done! - return back to the hot path.
- if (opcodeID == op_construct)
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
- else
- emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
+ emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
// This handles host functions
callLinkFailNotObject.link(this);
callLinkFailNotJSFunction.link(this);
- JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
+
+ JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
+ stubCall.addArgument(callee);
+ stubCall.addArgument(JIT::Imm32(registerOffset));
+ stubCall.addArgument(JIT::Imm32(argCount));
+ stubCall.call();
sampleCodeBlock(m_codeBlock);
}
diff --git a/JavaScriptCore/jit/JITInlineMethods.h b/JavaScriptCore/jit/JITInlineMethods.h
index 89faa00..cba290b 100644
--- a/JavaScriptCore/jit/JITInlineMethods.h
+++ b/JavaScriptCore/jit/JITInlineMethods.h
@@ -33,31 +33,6 @@ namespace JSC {
/* Deprecated: Please use JITStubCall instead. */
-// puts an arg onto the stack, as an arg to a context threaded function.
-ALWAYS_INLINE void JIT::emitPutJITStubArg(RegisterID src, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(src, argumentStackOffset);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArgConstant(unsigned value, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(Imm32(value), argumentStackOffset);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArgConstant(void* value, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(ImmPtr(value), argumentStackOffset);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
ALWAYS_INLINE void JIT::emitGetJITStubArg(unsigned argumentNumber, RegisterID dst)
{
unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
@@ -605,31 +580,6 @@ ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(unsigned op1, unsigned op
return false;
}
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArg(RegisterID tag, RegisterID payload, unsigned argumentNumber)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- poke(payload, argumentStackOffset);
- poke(tag, argumentStackOffset + 1);
-}
-
-/* Deprecated: Please use JITStubCall instead. */
-
-ALWAYS_INLINE void JIT::emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- if (m_codeBlock->isConstantRegisterIndex(src)) {
- JSValue constant = m_codeBlock->getConstant(src);
- poke(Imm32(constant.payload()), argumentStackOffset);
- poke(Imm32(constant.tag()), argumentStackOffset + 1);
- } else {
- emitLoad(src, scratch1, scratch2);
- poke(scratch2, argumentStackOffset);
- poke(scratch1, argumentStackOffset + 1);
- }
-}
-
#else // USE(JSVALUE32_64)
ALWAYS_INLINE void JIT::killLastResultRegister()
@@ -848,23 +798,6 @@ ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg)
or32(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), reg);
}
-/* Deprecated: Please use JITStubCall instead. */
-
-// get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
-ALWAYS_INLINE void JIT::emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch)
-{
- unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX;
- if (m_codeBlock->isConstantRegisterIndex(src)) {
- JSValue value = m_codeBlock->getConstant(src);
- poke(ImmPtr(JSValue::encode(value)), argumentStackOffset);
- } else {
- loadPtr(Address(callFrameRegister, src * sizeof(Register)), scratch);
- poke(scratch, argumentStackOffset);
- }
-
- killLastResultRegister();
-}
-
#endif // USE(JSVALUE32_64)
} // namespace JSC
diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp
index f8be135..64e1f3c 100644
--- a/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/JavaScriptCore/jit/JITOpcodes.cpp
@@ -74,404 +74,135 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
// VirtualCallLink Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallLinkBegin = align();
- 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));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction1 = call();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- hasCodeBlock1.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck1 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay1.link(this);
-
- isNativeFunc1.link(this);
-
compileOpCallInitializeCallFrame();
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callLazyLinkCall1 = call();
+ Call callLazyLinkCall = call();
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
// VirtualConstructLink Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualConstructLinkBegin = align();
- 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));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction2 = call();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- hasCodeBlock2.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck2 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay2.link(this);
-
- isNativeFunc2.link(this);
-
compileOpCallInitializeCallFrame();
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callLazyLinkCall2 = call();
+ Call callLazyLinkConstruct = call();
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
// VirtualCall Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ compileOpCallInitializeCallFrame();
- Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- 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();
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileCall = call();
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
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);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck3 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay3.link(this);
-
- isNativeFunc3.link(this);
- compileOpCallInitializeCallFrame();
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCall)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
jump(regT0);
// VirtualConstruct Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualConstructBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
+ compileOpCallInitializeCallFrame();
- Jump isNativeFunc4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- 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();
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileConstruct = call();
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
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);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck4 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay4.link(this);
-
- isNativeFunc4.link(this);
- compileOpCallInitializeCallFrame();
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstruct)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
jump(regT0);
- // NativCall Trampoline
- Label nativeCallThunk = align();
- preserveReturnAddressAfterCall(regT0);
- emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address
-
- // Load caller frame's scope chain into this callframe so that whatever we call can
- // get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1);
- emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
-
-#if CPU(X86_64)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, X86Registers::ecx);
-
- // Allocate stack space for our arglist
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
- COMPILE_ASSERT((sizeof(ArgList) & 0xf) == 0, ArgList_should_by_16byte_aligned);
-
- // Set up arguments
- subPtr(Imm32(1), X86Registers::ecx); // Don't include 'this' in argcount
-
- // Push argcount
- storePtr(X86Registers::ecx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in edx
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), callFrameRegister, X86Registers::edx);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (ecx)
- mul32(Imm32(sizeof(Register)), X86Registers::ecx, X86Registers::ecx);
- subPtr(X86Registers::ecx, X86Registers::edx);
-
- // push pointer to arguments
- storePtr(X86Registers::edx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
-
- // ArgList is passed by reference so is stackPointerRegister
- move(stackPointerRegister, X86Registers::ecx);
-
- // edx currently points to the first argument, edx-sizeof(Register) points to 'this'
- loadPtr(Address(X86Registers::edx, -(int32_t)sizeof(Register)), X86Registers::edx);
-
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi);
-
- move(callFrameRegister, X86Registers::edi);
+ // NativeCall Trampoline
+ Label nativeCallThunk = privateCompileCTINativeCall(globalData);
+ Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true);
- loadPtr(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::r9);
- call(Address(X86Registers::r9, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- addPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-#elif CPU(X86)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- /* We have two structs that we use to describe the stackframe we set up for our
- * call to native code. NativeCallFrameStructure describes the how we set up the stack
- * in advance of the call. NativeFunctionCalleeSignature describes the callframe
- * as the native code expects it. We do this as we are using the fastcall calling
- * convention which results in the callee popping its arguments off the stack, but
- * not the rest of the callframe so we need a nice way to ensure we increment the
- * stack pointer by the right amount after the call.
- */
-#if COMPILER(MSVC) || OS(LINUX)
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in EDX
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- JSValue result;
- };
- struct NativeFunctionCalleeSignature {
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- };
-#else
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in ECX
- // JSObject* callee; // passed in EDX
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- };
- struct NativeFunctionCalleeSignature {
- JSValue thisValue;
- ArgList* argPointer;
- };
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
+ Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
+ Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
#endif
- const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15;
- // Allocate system stack frame
- subPtr(Imm32(NativeCallFrameSize), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args)));
-
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0);
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer)));
- // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int)sizeof(Register)), regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue)));
-
-#if COMPILER(MSVC) || OS(LINUX)
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx);
-
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax);
- storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee)));
-
- // Plant callframe
- move(callFrameRegister, X86Registers::edx);
-
- loadPtr(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::ebx);
- call(Address(X86Registers::ebx, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- // JSValue is a non-POD type
- loadPtr(Address(X86Registers::eax), X86Registers::eax);
-#else
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx);
+ // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
+ LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()));
- // Plant callframe
- move(callFrameRegister, X86Registers::ecx);
- loadPtr(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::ebx);
- call(Address(X86Registers::ebx, OBJECT_OFFSETOF(NativeExecutable, m_function)));
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
+ patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
+ patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
#endif
+#if ENABLE(JIT_OPTIMIZE_CALL)
+ patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
+ patchBuffer.link(callLazyLinkConstruct, FunctionPtr(cti_vm_lazyLinkConstruct));
+#endif
+ patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile));
+ patchBuffer.link(callCompileConstruct, FunctionPtr(cti_op_construct_jitCompile));
- // We've put a few temporaries on the stack in addition to the actual arguments
- // so pull them off now
- addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister);
-
-#elif CPU(ARM)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- // Allocate stack space for our arglist
- COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0, ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // Push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
-
- // push pointer to arguments
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
-
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
-
-#if OS(WINCE)
- // Setup arg3:
- loadPtr(Address(regT1, -(int32_t)sizeof(Register)), ARMRegisters::r3);
-
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
-
- // Setup arg1:
- move(callFrameRegister, regT1);
-
- // Setup arg0:
- move(stackPointerRegister, regT0);
- subPtr(Imm32(sizeof(Register)), stackPointerRegister);
- storePtr(regT0, Address(stackPointerRegister));
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT3);
- call(Address(regT3, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- loadPtr(Address(regT0), regT0);
-
- addPtr(Imm32(sizeof(Register) + sizeof(ArgList)), stackPointerRegister);
-#else // OS(WINCE)
- // Setup arg3:
- loadPtr(Address(regT1, -(int32_t)sizeof(Register)), regT2);
-
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1);
-
- // Setup arg1:
- move(callFrameRegister, regT0);
-
- // Setup arg4: This is a plain hack
- move(stackPointerRegister, ARMRegisters::r3);
-
- loadPtr(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT3);
- call(Address(regT3, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- addPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-#endif // OS(WINCE)
-
-#elif CPU(MIPS)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- // Allocate stack space for our arglist
- COMPILE_ASSERT(!(sizeof(ArgList) & 0x7), ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList) + 24), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // Push argcount to 24 + offset($sp)
- storePtr(regT0, Address(stackPointerRegister, 24 + OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
+ CodeRef finalCode = patchBuffer.finalizeCode();
+ *executablePool = finalCode.m_executablePool;
- // push pointer to arguments to 24 + offset($sp)
- storePtr(regT1, Address(stackPointerRegister, 24 + OBJECT_OFFSETOF(ArgList, m_args)));
+ trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin);
+ trampolines->ctiVirtualConstructLink = trampolineAt(finalCode, virtualConstructLinkBegin);
+ trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin);
+ trampolines->ctiVirtualConstruct = trampolineAt(finalCode, virtualConstructBegin);
+ trampolines->ctiNativeCall = trampolineAt(finalCode, nativeCallThunk);
+ trampolines->ctiNativeConstruct = trampolineAt(finalCode, nativeConstructThunk);
+#if ENABLE(JIT_OPTIMIZE_MOD)
+ trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin);
+#endif
+#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+ trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin);
+#endif
+}
- // Setup arg3: regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int32_t)sizeof(Register)), MIPSRegisters::a3);
+JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct)
+{
+ int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function);
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
+ Label nativeCallThunk = align();
- // Setup arg1:
- move(callFrameRegister, MIPSRegisters::a1);
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Setup arg4: ArgList is passed by reference. At 16($sp), store ($sp + 24)
- addPtr(Imm32(24), stackPointerRegister, regT2);
- storePtr(regT2, Address(stackPointerRegister, 16));
+ peek(regT1);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
- // Setup arg0 as 20($sp) to hold the returned structure.
- ASSERT(sizeof(JSValue) == 4);
- addPtr(Imm32(20), stackPointerRegister, MIPSRegisters::a0);
+#if CPU(X86_64)
+ // Calling convention: f(edi, esi, edx, ecx, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, X86Registers::edi);
- // Call
- loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- call(Address(regT2, OBJECT_OFFSETOF(NativeExecutable, m_function)));
+ subPtr(Imm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
- // Get returned value from 0($v0) which is the same as 20($sp)
- loadPtr(Address(returnValueRegister, 0), returnValueRegister);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi);
+ loadPtr(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::r9);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ call(Address(X86Registers::r9, executableOffsetToFunction));
- // Restore stack space
- addPtr(Imm32(sizeof(ArgList) + 24), stackPointerRegister);
+ addPtr(Imm32(16 - sizeof(void*)), stackPointerRegister);
#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
@@ -483,70 +214,20 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
loadPtr(&(globalData->exception), regT2);
Jump exceptionHandler = branchTestPtr(NonZero, regT2);
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
-
- // Restore our caller's "r".
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
-
// Return.
- restoreReturnAddressBeforeReturn(regT1);
ret();
// Handle an exception
exceptionHandler.link(this);
// Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
+ peek(regT1);
move(ImmPtr(&globalData->exceptionLocation), regT2);
storePtr(regT1, regT2);
- move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*));
- restoreReturnAddressBeforeReturn(regT2);
+ poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*));
+ poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()));
ret();
-
-
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
- Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
- Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
-#endif
-
- // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()));
-
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
- patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
- 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();
- *executablePool = finalCode.m_executablePool;
- trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin);
- trampolines->ctiVirtualConstructLink = trampolineAt(finalCode, virtualConstructLinkBegin);
- trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin);
- trampolines->ctiVirtualConstruct = trampolineAt(finalCode, virtualConstructBegin);
- trampolines->ctiNativeCall = trampolineAt(finalCode, nativeCallThunk);
-#if ENABLE(JIT_OPTIMIZE_MOD)
- trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin);
-#endif
-#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin);
-#endif
+ return nativeCallThunk;
}
JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool>, JSGlobalData* globalData, NativeFunction)
@@ -1430,7 +1111,6 @@ void JIT::emit_op_neq_null(Instruction* currentInstruction)
emitTagAsBoolImmediate(regT0);
emitPutVirtualRegister(dst);
-
}
void JIT::emit_op_enter(Instruction*)
@@ -1485,7 +1165,20 @@ void JIT::emit_op_convert_this(Instruction* currentInstruction)
emitJumpSlowCaseIfNotJSCell(regT0);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1);
addSlowCase(branchTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion)));
+}
+void JIT::emit_op_get_callee(Instruction* currentInstruction)
+{
+ unsigned result = currentInstruction[1].u.operand;
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
+ emitPutVirtualRegister(result);
+}
+
+void JIT::emit_op_create_this(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, cti_op_create_this);
+ stubCall.addArgument(currentInstruction[2].u.operand, regT1);
+ stubCall.call(currentInstruction[1].u.operand);
}
void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp
index b814801..a730b67 100644
--- a/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -71,383 +71,69 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
// VirtualCallLink Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallLinkBegin = align();
- 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));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction1 = call();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- hasCodeBlock1.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck1 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay1.link(this);
-
- isNativeFunc1.link(this);
-
compileOpCallInitializeCallFrame();
-
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callLazyLinkCall1 = call();
+ Call callLazyLinkCall = call();
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
// VirtualConstructLink Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualConstructLinkBegin = align();
- 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));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction2 = call();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- hasCodeBlock2.link(this);
-
- // Check argCount matches callee arity.
- Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
- preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
- restoreArgumentReference();
- Call callArityCheck2 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
- restoreReturnAddressBeforeReturn(regT3);
- arityCheckOkay2.link(this);
-
- isNativeFunc2.link(this);
-
compileOpCallInitializeCallFrame();
-
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
+ emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
restoreArgumentReference();
- Call callLazyLinkCall2 = call();
+ Call callLazyLinkConstruct = call();
restoreReturnAddressBeforeReturn(regT3);
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
jump(regT0);
#endif // ENABLE(JIT_OPTIMIZE_CALL)
// VirtualCall Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualCallBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+ compileOpCallInitializeCallFrame();
- Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction3 = call();
- emitGetJITStubArg(2, regT1); // argCount
- 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);
+ Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
restoreArgumentReference();
- Call callArityCheck3 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileCall = call();
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay3.link(this);
-
- isNativeFunc3.link(this);
+ hasCodeBlock3.link(this);
- compileOpCallInitializeCallFrame();
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCall)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
jump(regT0);
// VirtualConstruct Trampoline
// regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
Label virtualConstructBegin = align();
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- Jump isNativeFunc4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+ compileOpCallInitializeCallFrame();
- Jump hasCodeBlock4 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
- preserveReturnAddressAfterCall(regT3);
- restoreArgumentReference();
- Call callJSFunction4 = call();
- emitGetJITStubArg(2, regT1); // argCount
- 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);
+ Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
preserveReturnAddressAfterCall(regT3);
- emitPutJITStubArg(regT3, 1); // return address
restoreArgumentReference();
- Call callArityCheck4 = call();
- move(regT1, callFrameRegister);
- emitGetJITStubArg(2, regT1); // argCount
+ Call callCompileCconstruct = call();
+ emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
restoreReturnAddressBeforeReturn(regT3);
loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- arityCheckOkay4.link(this);
-
- isNativeFunc4.link(this);
+ hasCodeBlock4.link(this);
- compileOpCallInitializeCallFrame();
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstruct)), regT0);
+ loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
jump(regT0);
-#if CPU(X86) || CPU(ARM_TRADITIONAL)
- Label nativeCallThunk = align();
- preserveReturnAddressAfterCall(regT0);
- emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address
-
- // Load caller frame's scope chain into this callframe so that whatever we call can
- // get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1);
- emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
-#if CPU(X86)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- /* We have two structs that we use to describe the stackframe we set up for our
- * call to native code. NativeCallFrameStructure describes the how we set up the stack
- * in advance of the call. NativeFunctionCalleeSignature describes the callframe
- * as the native code expects it. We do this as we are using the fastcall calling
- * convention which results in the callee popping its arguments off the stack, but
- * not the rest of the callframe so we need a nice way to ensure we increment the
- * stack pointer by the right amount after the call.
- */
-
-#if COMPILER(MSVC) || OS(LINUX)
-#if COMPILER(MSVC)
-#pragma pack(push)
-#pragma pack(4)
-#endif // COMPILER(MSVC)
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in EDX
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- JSValue result;
- };
- struct NativeFunctionCalleeSignature {
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- };
-#if COMPILER(MSVC)
-#pragma pack(pop)
-#endif // COMPILER(MSVC)
-#else
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in ECX
- // JSObject* callee; // passed in EDX
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- };
- struct NativeFunctionCalleeSignature {
- JSValue thisValue;
- ArgList* argPointer;
- };
-#endif
-
- const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15;
- // Allocate system stack frame
- subPtr(Imm32(NativeCallFrameSize), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args)));
-
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0);
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer)));
-
- // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
- loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT3);
- storePtr(regT2, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- storePtr(regT3, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-
-#if COMPILER(MSVC) || OS(LINUX)
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx);
-
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax);
- storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee)));
-
- // Plant callframe
- move(callFrameRegister, X86Registers::edx);
-
- loadPtr(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::ebx);
- call(Address(X86Registers::ebx, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- // JSValue is a non-POD type, so eax points to it
- emitLoad(0, regT1, regT0, X86Registers::eax);
-#else
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // callee
- move(callFrameRegister, X86Registers::ecx); // callFrame
- loadPtr(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_executable)), X86Registers::ebx);
- call(Address(X86Registers::ebx, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-#endif
-
- // We've put a few temporaries on the stack in addition to the actual arguments
- // so pull them off now
- addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister);
-
-#elif CPU(ARM_TRADITIONAL)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- // Allocate stack space for our arglist
- COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0 && sizeof(JSValue) == 8 && sizeof(Register) == 8, ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // Push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
-
- // push pointer to arguments
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
-
- // Argument passing method:
- // r0 - points to return value
- // r1 - callFrame
- // r2 - callee
- // stack: this(JSValue) and a pointer to ArgList
-
-#if OS(WINCE)
- // Setup arg4:
- push(stackPointerRegister);
-
- // Setup arg3:
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- load32(Address(regT1, -(int32_t)sizeof(void*) * 2), ARMRegisters::r3);
- push(ARMRegisters::r3);
- load32(Address(regT1, -(int32_t)sizeof(void*)), regT3);
- storePtr(regT3, Address(stackPointerRegister));
-
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
-
- // Setup arg1:
- move(callFrameRegister, regT1);
-
- // Setup arg0:
- move(stackPointerRegister, regT0);
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT3);
- call(Address(regT3, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- load32(Address(stackPointerRegister, 0), regT0);
- load32(Address(stackPointerRegister, 4), regT1);
-
- addPtr(Imm32(sizeof(ArgList) + 8), stackPointerRegister);
-#else // OS(WINCE)
- move(stackPointerRegister, regT3);
- subPtr(Imm32(8), stackPointerRegister);
- move(stackPointerRegister, regT0);
- subPtr(Imm32(8 + 4 + 4 /* padding */), stackPointerRegister);
-
- // Setup arg4:
- storePtr(regT3, Address(stackPointerRegister, 8));
-
- // Setup arg3:
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- load32(Address(regT1, -(int32_t)sizeof(void*) * 2), regT3);
- storePtr(regT3, Address(stackPointerRegister, 0));
- load32(Address(regT1, -(int32_t)sizeof(void*)), regT3);
- storePtr(regT3, Address(stackPointerRegister, 4));
-
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
-
- // Setup arg1:
- move(callFrameRegister, regT1);
-
- loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT3);
- call(Address(regT3, OBJECT_OFFSETOF(NativeExecutable, m_function)));
-
- // Load return value
- load32(Address(stackPointerRegister, 16), regT0);
- load32(Address(stackPointerRegister, 20), regT1);
-
- addPtr(Imm32(sizeof(ArgList) + 16 + 8), stackPointerRegister);
-#endif // OS(WINCE)
-
-#endif
-
- // Check for an exception
- move(ImmPtr(&globalData->exception), regT2);
- Jump sawException = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::EmptyValueTag));
-
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3);
-
- // Restore our caller's "r".
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
-
- // Return.
- restoreReturnAddressBeforeReturn(regT3);
- ret();
-
- // Handle an exception
- sawException.link(this);
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
- move(ImmPtr(&globalData->exceptionLocation), regT2);
- storePtr(regT1, regT2);
- move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
- restoreReturnAddressBeforeReturn(regT2);
- ret();
-
-#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
-#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
-#else
- breakpoint();
-#endif
+ // NativeCall Trampoline
+ Label nativeCallThunk = privateCompileCTINativeCall(globalData);
+ Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true);
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
@@ -464,17 +150,11 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
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));
+ patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
+ patchBuffer.link(callLazyLinkConstruct, 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));
+ patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile));
+ patchBuffer.link(callCompileCconstruct, FunctionPtr(cti_op_construct_jitCompile));
CodeRef finalCode = patchBuffer.finalizeCode();
*executablePool = finalCode.m_executablePool;
@@ -482,6 +162,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin);
trampolines->ctiVirtualConstruct = trampolineAt(finalCode, virtualConstructBegin);
trampolines->ctiNativeCall = trampolineAt(finalCode, nativeCallThunk);
+ trampolines->ctiNativeConstruct = trampolineAt(finalCode, nativeConstructThunk);
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin);
#endif
@@ -494,246 +175,112 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
#endif
}
-JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* globalData, NativeFunction func)
+JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct)
{
-#if CPU(X86) || CPU(ARM_TRADITIONAL)
+ int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function);
+
Label nativeCallThunk = align();
- preserveReturnAddressAfterCall(regT0);
- emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address
// Load caller frame's scope chain into this callframe so that whatever we call can
// get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-#if CPU(X86)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- /* We have two structs that we use to describe the stackframe we set up for our
- * call to native code. NativeCallFrameStructure describes the how we set up the stack
- * in advance of the call. NativeFunctionCalleeSignature describes the callframe
- * as the native code expects it. We do this as we are using the fastcall calling
- * convention which results in the callee popping its arguments off the stack, but
- * not the rest of the callframe so we need a nice way to ensure we increment the
- * stack pointer by the right amount after the call.
- */
-
-#if COMPILER(MSVC) || OS(LINUX)
-#if COMPILER(MSVC)
-#pragma pack(push)
-#pragma pack(4)
-#endif // COMPILER(MSVC)
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in EDX
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- JSValue result;
- };
- struct NativeFunctionCalleeSignature {
- JSObject* callee;
- JSValue thisValue;
- ArgList* argPointer;
- };
-#if COMPILER(MSVC)
-#pragma pack(pop)
-#endif // COMPILER(MSVC)
-#else
- struct NativeCallFrameStructure {
- // CallFrame* callFrame; // passed in ECX
- // JSObject* callee; // passed in EDX
- JSValue thisValue;
- ArgList* argPointer;
- ArgList args;
- };
- struct NativeFunctionCalleeSignature {
- JSValue thisValue;
- ArgList* argPointer;
- };
-#endif
-
- const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15;
- // Allocate system stack frame
- subPtr(Imm32(NativeCallFrameSize), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount)));
+ peek(regT1);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
- // Calculate the start of the callframe header, and store in regT1
- addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args)));
-
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0);
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer)));
-
- // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this'
- loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
- loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT3);
- storePtr(regT2, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
- storePtr(regT3, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
-
-#if COMPILER(MSVC) || OS(LINUX)
- // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register)
- addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx);
+#if CPU(X86)
+ // Calling convention: f(ecx, edx, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, X86Registers::ecx);
- // Plant callee
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax);
- storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee)));
+ subPtr(Imm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
- // Plant callframe
- move(callFrameRegister, X86Registers::edx);
+ // call the function
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1);
+ loadPtr(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT1);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ call(Address(regT1, executableOffsetToFunction));
- Call nativeCall = call();
+ addPtr(Imm32(16 - sizeof(void*)), stackPointerRegister);
- // JSValue is a non-POD type, so eax points to it
- emitLoad(0, regT1, regT0, X86Registers::eax);
+#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
+#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
#else
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // callee
- move(callFrameRegister, X86Registers::ecx); // callFrame
- Call nativeCall = call();
-#endif
-
- // We've put a few temporaries on the stack in addition to the actual arguments
- // so pull them off now
- addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister);
-
-#elif CPU(ARM_TRADITIONAL)
- emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
-
- // Allocate stack space for our arglist
- COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0 && sizeof(JSValue) == 8 && sizeof(Register) == 8, ArgList_should_by_8byte_aligned);
- subPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
-
- // Set up arguments
- subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
-
- // Push argcount
- storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount)));
-
- // Calculate the start of the callframe header, and store in regT1
- move(callFrameRegister, regT1);
- sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
-
- // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
- mul32(Imm32(sizeof(Register)), regT0, regT0);
- subPtr(regT0, regT1);
-
- // push pointer to arguments
- storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args)));
-
- // Argument passing method:
- // r0 - points to return value
- // r1 - callFrame
- // r2 - callee
- // stack: this(JSValue) and a pointer to ArgList
-
-#if OS(WINCE)
- // Setup arg4:
- push(stackPointerRegister);
-
- // Setup arg3:
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- load32(Address(regT1, -(int32_t)sizeof(void*) * 2), ARMRegisters::r3);
- push(ARMRegisters::r3);
- load32(Address(regT1, -(int32_t)sizeof(void*)), regT3);
- storePtr(regT3, Address(stackPointerRegister));
+ breakpoint();
+#endif // CPU(X86)
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
+ // Check for an exception
+ Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag));
- // Setup arg1:
- move(callFrameRegister, regT1);
+ // Return.
+ ret();
- // Setup arg0:
- move(stackPointerRegister, regT0);
+ // Handle an exception
+ sawException.link(this);
+ peek(regT1);
+ move(ImmPtr(&globalData->exceptionLocation), regT2);
+ storePtr(regT1, regT2);
+ poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()));
+ ret();
- Call nativeCall = call();
+ return nativeCallThunk;
+}
- load32(Address(stackPointerRegister, 0), regT0);
- load32(Address(stackPointerRegister, 4), regT1);
+JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* globalData, NativeFunction func)
+{
+ Label nativeCallThunk = align();
- addPtr(Imm32(sizeof(ArgList) + 8), stackPointerRegister);
-#else // OS(WINCE)
- move(stackPointerRegister, regT3);
- subPtr(Imm32(8), stackPointerRegister);
- move(stackPointerRegister, regT0);
- subPtr(Imm32(8 + 4 + 4 /* padding */), stackPointerRegister);
+#if CPU(X86)
+ // Load caller frame's scope chain into this callframe so that whatever we call can
+ // get to its global data.
+ emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
- // Setup arg4:
- storePtr(regT3, Address(stackPointerRegister, 8));
+ peek(regT1);
+ emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
- // Setup arg3:
- // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
- load32(Address(regT1, -(int32_t)sizeof(void*) * 2), regT3);
- storePtr(regT3, Address(stackPointerRegister, 0));
- load32(Address(regT1, -(int32_t)sizeof(void*)), regT3);
- storePtr(regT3, Address(stackPointerRegister, 4));
+ // Calling convention: f(ecx, edx, ...);
+ // Host function signature: f(ExecState*);
+ move(callFrameRegister, X86Registers::ecx);
- // Setup arg2:
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2);
+ subPtr(Imm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
- // Setup arg1:
- move(callFrameRegister, regT1);
+ move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ // call the function
Call nativeCall = call();
- // Load return value
- load32(Address(stackPointerRegister, 16), regT0);
- load32(Address(stackPointerRegister, 20), regT1);
-
- addPtr(Imm32(sizeof(ArgList) + 16 + 8), stackPointerRegister);
-#endif // OS(WINCE)
+ addPtr(Imm32(16 - sizeof(void*)), stackPointerRegister);
-#endif
+#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
+#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
+#else
+ breakpoint();
+#endif // CPU(X86)
// Check for an exception
- move(ImmPtr(&globalData->exception), regT2);
- Jump sawException = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::EmptyValueTag));
-
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3);
-
- // Restore our caller's "r".
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
+ Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag));
// Return.
- restoreReturnAddressBeforeReturn(regT3);
ret();
// Handle an exception
sawException.link(this);
- // Grab the return address.
- emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
+ peek(regT1);
move(ImmPtr(&globalData->exceptionLocation), regT2);
storePtr(regT1, regT2);
- move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
- restoreReturnAddressBeforeReturn(regT2);
+ poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ poke(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()));
ret();
-#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
-#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
-#else
- breakpoint();
-#endif
-
// All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
LinkBuffer patchBuffer(this, executablePool);
-#if ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
patchBuffer.link(nativeCall, FunctionPtr(func));
-#endif
CodeRef finalCode = patchBuffer.finalizeCode();
return trampolineAt(finalCode, nativeCallThunk);
@@ -1814,6 +1361,22 @@ void JIT::emit_op_init_arguments(Instruction* currentInstruction)
emitStore(unmodifiedArgumentsRegister(dst), JSValue());
}
+void JIT::emit_op_get_callee(Instruction* currentInstruction)
+{
+ int dst = currentInstruction[1].u.operand;
+ emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
+ emitStoreCell(dst, regT0);
+}
+
+void JIT::emit_op_create_this(Instruction* currentInstruction)
+{
+ unsigned protoRegister = currentInstruction[2].u.operand;
+ emitLoad(protoRegister, regT1, regT0);
+ JITStubCall stubCall(this, cti_op_create_this);
+ stubCall.addArgument(regT1, regT0);
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
void JIT::emit_op_convert_this(Instruction* currentInstruction)
{
unsigned thisRegister = currentInstruction[1].u.operand;
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index aea80a7..9da3c40 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -1202,6 +1202,28 @@ RVCT()
#define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
#endif
+DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this)
+{
+ STUB_INIT_STACK_FRAME(stackFrame);
+ CallFrame* callFrame = stackFrame.callFrame;
+
+ JSFunction* constructor = asFunction(callFrame->callee());
+#if !ASSERT_DISABLED
+ ConstructData constructData;
+ ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
+#endif
+
+ Structure* structure;
+ JSValue proto = stackFrame.args[0].jsValue();
+ if (proto.isObject())
+ structure = asObject(proto)->inheritorID();
+ else
+ structure = constructor->scope().node()->globalObject->emptyObjectStructure();
+ JSValue result = new (&callFrame->globalData()) JSObject(structure);
+
+ return JSValue::encode(result);
+}
+
DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this)
{
STUB_INIT_STACK_FRAME(stackFrame);
@@ -1783,10 +1805,10 @@ DEFINE_STUB_FUNCTION(void*, op_call_jitCompile)
#if !ASSERT_DISABLED
CallData callData;
- ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS);
+ ASSERT(stackFrame.callFrame->callee()->getCallData(callData) == CallTypeJS);
#endif
- JSFunction* function = asFunction(stackFrame.args[0].jsValue());
+ JSFunction* function = asFunction(stackFrame.callFrame->callee());
ASSERT(!function->isHostFunction());
FunctionExecutable* executable = function->jsExecutable();
ScopeChainNode* callDataScopeChain = function->scope().node();
@@ -1800,11 +1822,11 @@ DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile)
STUB_INIT_STACK_FRAME(stackFrame);
#if !ASSERT_DISABLED
- CallData callData;
- ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS);
+ ConstructData constructData;
+ ASSERT(asFunction(stackFrame.callFrame->callee())->getConstructData(constructData) == ConstructTypeJS);
#endif
- JSFunction* function = asFunction(stackFrame.args[0].jsValue());
+ JSFunction* function = asFunction(stackFrame.callFrame->callee());
ASSERT(!function->isHostFunction());
FunctionExecutable* executable = function->jsExecutable();
ScopeChainNode* callDataScopeChain = function->scope().node();
@@ -1813,139 +1835,183 @@ DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile)
return function;
}
-DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck)
+DEFINE_STUB_FUNCTION(void*, op_call_arityCheck)
{
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
- JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
+ JSFunction* callee = asFunction(callFrame->callee());
ASSERT(!callee->isHostFunction());
CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForCall();
- int argCount = stackFrame.args[2].int32();
+ int argCount = callFrame->argumentCountIncludingThis();
+ ReturnAddressPtr pc = callFrame->returnPC();
ASSERT(argCount != newCodeBlock->m_numParameters);
CallFrame* oldCallFrame = callFrame->callerFrame();
+ Register* r;
if (argCount > newCodeBlock->m_numParameters) {
size_t numParameters = newCodeBlock->m_numParameters;
- Register* r = callFrame->registers() + numParameters;
+ r = callFrame->registers() + numParameters;
+ Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
+ if (!stackFrame.registerFile->grow(newEnd)) {
+ // Rewind to the previous call frame because op_call already optimistically
+ // moved the call frame forward.
+ stackFrame.callFrame = oldCallFrame;
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
+ return 0;
+ }
Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
for (size_t i = 0; i < numParameters; ++i)
argv[i + argCount] = argv[i];
-
- callFrame = CallFrame::create(r);
- callFrame->setCallerFrame(oldCallFrame);
} else {
size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
- Register* r = callFrame->registers() + omittedArgCount;
+ r = callFrame->registers() + omittedArgCount;
Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
if (!stackFrame.registerFile->grow(newEnd)) {
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
- RETURN_POINTER_PAIR(0, 0);
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
+ return 0;
}
Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
for (size_t i = 0; i < omittedArgCount; ++i)
argv[i] = jsUndefined();
-
- callFrame = CallFrame::create(r);
- callFrame->setCallerFrame(oldCallFrame);
}
- RETURN_POINTER_PAIR(callee, callFrame);
+ callFrame = CallFrame::create(r);
+ callFrame->setCallerFrame(oldCallFrame);
+ callFrame->setArgumentCountIncludingThis(argCount);
+ callFrame->setCallee(callee);
+ callFrame->setScopeChain(callee->scope().node());
+ callFrame->setReturnPC(pc.value());
+
+ ASSERT((void*)callFrame <= stackFrame.registerFile->end());
+ return callFrame;
}
-DEFINE_STUB_FUNCTION(VoidPtrPair, op_construct_arityCheck)
+DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck)
{
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
- JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
+ JSFunction* callee = asFunction(callFrame->callee());
ASSERT(!callee->isHostFunction());
CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForConstruct();
- int argCount = stackFrame.args[2].int32();
+ int argCount = callFrame->argumentCountIncludingThis();
+ ReturnAddressPtr pc = callFrame->returnPC();
ASSERT(argCount != newCodeBlock->m_numParameters);
CallFrame* oldCallFrame = callFrame->callerFrame();
+ Register* r;
if (argCount > newCodeBlock->m_numParameters) {
size_t numParameters = newCodeBlock->m_numParameters;
- Register* r = callFrame->registers() + numParameters;
+ r = callFrame->registers() + numParameters;
+ Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
+ if (!stackFrame.registerFile->grow(newEnd)) {
+ // Rewind to the previous call frame because op_call already optimistically
+ // moved the call frame forward.
+ stackFrame.callFrame = oldCallFrame;
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
+ return 0;
+ }
Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
for (size_t i = 0; i < numParameters; ++i)
argv[i + argCount] = argv[i];
-
- callFrame = CallFrame::create(r);
- callFrame->setCallerFrame(oldCallFrame);
} else {
size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
- Register* r = callFrame->registers() + omittedArgCount;
+ r = callFrame->registers() + omittedArgCount;
Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
if (!stackFrame.registerFile->grow(newEnd)) {
// Rewind to the previous call frame because op_call already optimistically
// moved the call frame forward.
stackFrame.callFrame = oldCallFrame;
- throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
- RETURN_POINTER_PAIR(0, 0);
+ throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
+ return 0;
}
Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
for (size_t i = 0; i < omittedArgCount; ++i)
argv[i] = jsUndefined();
-
- callFrame = CallFrame::create(r);
- callFrame->setCallerFrame(oldCallFrame);
}
- RETURN_POINTER_PAIR(callee, callFrame);
+ callFrame = CallFrame::create(r);
+ callFrame->setCallerFrame(oldCallFrame);
+ callFrame->setArgumentCountIncludingThis(argCount);
+ callFrame->setCallee(callee);
+ callFrame->setScopeChain(callee->scope().node());
+ callFrame->setReturnPC(pc.value());
+
+ ASSERT((void*)callFrame <= stackFrame.registerFile->end());
+ return callFrame;
}
#if ENABLE(JIT_OPTIMIZE_CALL)
DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall)
{
STUB_INIT_STACK_FRAME(stackFrame);
- JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
+ CallFrame* callFrame = stackFrame.callFrame;
+ JSFunction* callee = asFunction(callFrame->callee());
ExecutableBase* executable = callee->executable();
- JITCode& jitCode = executable->generatedJITCodeForCall();
-
+
+ MacroAssemblerCodePtr codePtr;
CodeBlock* codeBlock = 0;
- if (!executable->isHostFunction())
- codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecodeForCall(stackFrame.callFrame, callee->scope().node());
- CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress());
+ if (executable->isHostFunction())
+ codePtr = executable->generatedJITCodeForCall().addressForCall();
+ else {
+ FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
+ codeBlock = &functionExecutable->bytecodeForCall(stackFrame.callFrame, callee->scope().node());
+ functionExecutable->jitCodeForCall(callFrame, callee->scope().node());
+ if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
+ codePtr = functionExecutable->generatedJITCodeForCall().addressForCall();
+ else
+ codePtr = functionExecutable->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, stackFrame.args[2].int32(), stackFrame.globalData);
+ JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData);
- return jitCode.addressForCall().executableAddress();
+ return codePtr.executableAddress();
}
DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct)
{
STUB_INIT_STACK_FRAME(stackFrame);
- JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
+ CallFrame* callFrame = stackFrame.callFrame;
+ JSFunction* callee = asFunction(callFrame->callee());
ExecutableBase* executable = callee->executable();
- JITCode& jitCode = executable->generatedJITCodeForConstruct();
-
+
+ MacroAssemblerCodePtr codePtr;
CodeBlock* codeBlock = 0;
- if (!executable->isHostFunction())
- codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecodeForConstruct(stackFrame.callFrame, callee->scope().node());
- CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress());
+ if (executable->isHostFunction())
+ codePtr = executable->generatedJITCodeForConstruct().addressForCall();
+ else {
+ FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
+ codeBlock = &functionExecutable->bytecodeForConstruct(stackFrame.callFrame, callee->scope().node());
+ functionExecutable->jitCodeForConstruct(callFrame, callee->scope().node());
+ if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
+ codePtr = functionExecutable->generatedJITCodeForConstruct().addressForCall();
+ else
+ codePtr = functionExecutable->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, stackFrame.args[2].int32(), stackFrame.globalData);
+ JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData);
- return jitCode.addressForCall().executableAddress();
+ return codePtr.executableAddress();
}
#endif // !ENABLE(JIT_OPTIMIZE_CALL)
@@ -1975,22 +2041,13 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction)
CallFrame* previousCallFrame = stackFrame.callFrame;
CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
- callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0);
+ callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal));
stackFrame.callFrame = callFrame;
- Register* argv = stackFrame.callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
- ArgList argList(argv + 1, argCount - 1);
-
JSValue returnValue;
{
SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
-
- // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
- JSValue thisValue = argv[0].jsValue();
- if (thisValue == jsNull())
- thisValue = callFrame->globalThisValue();
-
- returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList);
+ returnValue = callData.native.function(callFrame);
}
stackFrame.callFrame = previousCallFrame;
CHECK_FOR_EXCEPTION();
@@ -2102,32 +2159,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
VM_THROW_EXCEPTION();
}
-DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct)
-{
- STUB_INIT_STACK_FRAME(stackFrame);
-
- JSFunction* constructor = asFunction(stackFrame.args[0].jsValue());
- if (constructor->isHostFunction()) {
- CallFrame* callFrame = stackFrame.callFrame;
- CodeBlock* codeBlock = callFrame->codeBlock();
- unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock);
- VM_THROW_EXCEPTION();
- }
-
-#if !ASSERT_DISABLED
- ConstructData constructData;
- ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
-#endif
-
- Structure* structure;
- if (stackFrame.args[3].jsValue().isObject())
- structure = asObject(stackFrame.args[3].jsValue())->inheritorID();
- else
- structure = constructor->scope().node()->globalObject->emptyObjectStructure();
- return new (stackFrame.globalData) JSObject(structure);
-}
-
DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
{
STUB_INIT_STACK_FRAME(stackFrame);
@@ -2136,13 +2167,14 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
JSValue constrVal = stackFrame.args[0].jsValue();
int argCount = stackFrame.args[2].int32();
- int thisRegister = stackFrame.args[4].int32();
ConstructData constructData;
ConstructType constructType = constrVal.getConstructData(constructData);
if (constructType == ConstructTypeHost) {
- ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
+ int registerOffset = stackFrame.args[1].int32();
+ Register* thisRegister = callFrame->registers() + registerOffset - RegisterFile::CallFrameHeaderSize - argCount;
+ ArgList argList(thisRegister + 1, argCount - 1);
JSValue returnValue;
{
@@ -2406,7 +2438,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs)
stackFrame.globalData->exception = createStackOverflowError(callFrame);
VM_THROW_EXCEPTION();
}
- int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
+ int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
int32_t inplaceArgs = min(providedParams, expectedParams);
Register* inplaceArgsDst = callFrame->registers() + argsOffset;
@@ -2993,10 +3025,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
Register* newCallFrame = callFrame->registers() + registerOffset;
Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
- JSValue thisValue = argv[0].jsValue();
+ JSValue baseValue = argv[0].jsValue();
JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
- if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
+ if (baseValue == globalObject && funcVal == globalObject->evalFunction()) {
JSValue exceptionValue;
JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
if (UNLIKELY(exceptionValue)) {
@@ -3426,7 +3458,7 @@ PassRefPtr<NativeExecutable> JITThunks::hostFunctionStub(JSGlobalData* globalDat
{
std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap.add(function, 0);
if (entry.second)
- entry.first->second = NativeExecutable::create(JIT::compileCTINativeCall(globalData, m_executablePool, function), function);
+ entry.first->second = NativeExecutable::create(JIT::compileCTINativeCall(globalData, m_executablePool, function), function, ctiNativeConstruct(), callHostFunctionAsConstructor);
return entry.first->second;
}
@@ -3434,7 +3466,7 @@ PassRefPtr<NativeExecutable> JITThunks::hostFunctionStub(JSGlobalData* globalDat
{
std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap.add(function, 0);
if (entry.second)
- entry.first->second = NativeExecutable::create(generator(globalData, m_executablePool.get()), function);
+ entry.first->second = NativeExecutable::create(generator(globalData, m_executablePool.get()), function, ctiNativeConstruct(), callHostFunctionAsConstructor);
return entry.first->second;
}
diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h
index e5d1419..bfed811 100644
--- a/JavaScriptCore/jit/JITStubs.h
+++ b/JavaScriptCore/jit/JITStubs.h
@@ -82,6 +82,7 @@ namespace JSC {
MacroAssemblerCodePtr ctiVirtualCall;
MacroAssemblerCodePtr ctiVirtualConstruct;
MacroAssemblerCodePtr ctiNativeCall;
+ MacroAssemblerCodePtr ctiNativeConstruct;
MacroAssemblerCodePtr ctiSoftModulo;
};
@@ -245,23 +246,6 @@ namespace JSC {
#endif
#endif
-#if CPU(X86_64)
- struct VoidPtrPair {
- void* first;
- void* second;
- };
- #define RETURN_POINTER_PAIR(a,b) VoidPtrPair pair = { a, b }; return pair
-#else
- // MSVC doesn't support returning a two-value struct in two registers, so
- // we cast the struct to int64_t instead.
- typedef uint64_t VoidPtrPair;
- union VoidPtrPairUnion {
- struct { void* first; void* second; } s;
- VoidPtrPair i;
- };
- #define RETURN_POINTER_PAIR(a,b) VoidPtrPairUnion pair = {{ a, b }}; return pair.i
-#endif
-
extern "C" void ctiVMThrowTrampoline();
extern "C" void ctiOpThrowNotCaught();
extern "C" EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*);
@@ -280,6 +264,7 @@ namespace JSC {
MacroAssemblerCodePtr ctiVirtualCall() { return m_trampolineStructure.ctiVirtualCall; }
MacroAssemblerCodePtr ctiVirtualConstruct() { return m_trampolineStructure.ctiVirtualConstruct; }
MacroAssemblerCodePtr ctiNativeCall() { return m_trampolineStructure.ctiNativeCall; }
+ MacroAssemblerCodePtr ctiNativeConstruct() { return m_trampolineStructure.ctiNativeConstruct; }
MacroAssemblerCodePtr ctiSoftModulo() { return m_trampolineStructure.ctiSoftModulo; }
MacroAssemblerCodePtr ctiStub(JSGlobalData* globalData, ThunkGenerator generator);
@@ -305,6 +290,7 @@ extern "C" {
EncodedJSValue JIT_STUB cti_op_call_NotJSFunction(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_call_eval(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_construct_NotJSConstruct(STUB_ARGS_DECLARATION);
+ EncodedJSValue JIT_STUB cti_op_create_this(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_convert_this(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION);
@@ -362,7 +348,6 @@ extern "C" {
EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION);
EncodedJSValue JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION);
- JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_error(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_new_func(STUB_ARGS_DECLARATION);
@@ -374,8 +359,6 @@ extern "C" {
JSObject* JIT_STUB cti_op_push_scope(STUB_ARGS_DECLARATION);
JSObject* JIT_STUB cti_op_put_by_id_transition_realloc(STUB_ARGS_DECLARATION);
JSPropertyNameIterator* JIT_STUB cti_op_get_pnames(STUB_ARGS_DECLARATION);
- VoidPtrPair JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION);
- VoidPtrPair JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_eq(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_eq_strings(STUB_ARGS_DECLARATION);
int JIT_STUB cti_op_jless(STUB_ARGS_DECLARATION);
@@ -403,6 +386,8 @@ extern "C" {
void JIT_STUB cti_op_tear_off_activation(STUB_ARGS_DECLARATION);
void JIT_STUB cti_op_tear_off_arguments(STUB_ARGS_DECLARATION);
void JIT_STUB cti_register_file_check(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_call_arityCheck(STUB_ARGS_DECLARATION);
+ void* JIT_STUB cti_op_construct_arityCheck(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_op_call_jitCompile(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_op_construct_jitCompile(STUB_ARGS_DECLARATION);
void* JIT_STUB cti_op_switch_char(STUB_ARGS_DECLARATION);