diff options
author | Leon Clarke <leonclarke@google.com> | 2010-06-03 14:33:32 +0100 |
---|---|---|
committer | Leon Clarke <leonclarke@google.com> | 2010-06-08 12:24:51 +0100 |
commit | 5af96e2c7b73ebc627c6894727826a7576d31758 (patch) | |
tree | f9d5e6f6175ccd7e3d14de9b290f08937a0d17ba /JavaScriptCore/jit/JITOpcodes.cpp | |
parent | 8cc4fcf4f6adcbc0e0aebfc24fbad9a4cddf2cfb (diff) | |
download | external_webkit-5af96e2c7b73ebc627c6894727826a7576d31758.zip external_webkit-5af96e2c7b73ebc627c6894727826a7576d31758.tar.gz external_webkit-5af96e2c7b73ebc627c6894727826a7576d31758.tar.bz2 |
Merge webkit.org at r60469 : Initial merge by git.
Change-Id: I66a0047aa2af802f66bb0c7f2a8b02247a596234
Diffstat (limited to 'JavaScriptCore/jit/JITOpcodes.cpp')
-rw-r--r-- | JavaScriptCore/jit/JITOpcodes.cpp | 487 |
1 files changed, 90 insertions, 397 deletions
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) |