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/JITOpcodes32_64.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/JITOpcodes32_64.cpp')
-rw-r--r-- | JavaScriptCore/jit/JITOpcodes32_64.cpp | 647 |
1 files changed, 105 insertions, 542 deletions
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; |