diff options
Diffstat (limited to 'JavaScriptCore/jit')
| -rw-r--r-- | JavaScriptCore/jit/JIT.cpp | 38 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JIT.h | 27 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITCall.cpp | 112 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITCall32_64.cpp | 102 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITInlineMethods.h | 67 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITOpcodes.cpp | 487 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITOpcodes32_64.cpp | 647 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITStubs.cpp | 218 | ||||
| -rw-r--r-- | JavaScriptCore/jit/JITStubs.h | 25 |
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); |
