-PassRefPtr<ExecutableMemoryHandle> JIT::privateCompileCTIMachineTrampolines(JSGlobalData* globalData, TrampolineStructure *trampolines)
-{
- // (1) This function provides fast property access for string length
- Label stringLengthBegin = align();
-
- // regT0 holds payload, regT1 holds tag
-
- Jump string_failureCases1 = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
- Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info));
-
- // Checks out okay! - get the length from the Ustring.
- load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT2);
-
- Jump string_failureCases3 = branch32(Above, regT2, TrustedImm32(INT_MAX));
- move(regT2, regT0);
- move(TrustedImm32(JSValue::Int32Tag), regT1);
-
- ret();
-
- JumpList callSlowCase;
- JumpList constructSlowCase;
-
- // VirtualCallLink Trampoline
- // regT1, regT0 holds callee; callFrame is moved and partially initialized.
- Label virtualCallLinkBegin = align();
- callSlowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- callSlowCase.append(emitJumpIfNotType(regT0, regT1, JSFunctionType));
-
- // Finish canonical initialization before JS function call.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- // Also initialize ReturnPC for use by lazy linking and exceptions.
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- restoreArgumentReference();
- Call callLazyLinkCall = call();
- restoreReturnAddressBeforeReturn(regT3);
- jump(regT0);
-
- // VirtualConstructLink Trampoline
- // regT1, regT0 holds callee; callFrame is moved and partially initialized.
- Label virtualConstructLinkBegin = align();
- constructSlowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- constructSlowCase.append(emitJumpIfNotType(regT0, regT1, JSFunctionType));
-
- // Finish canonical initialization before JS function call.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- // Also initialize ReturnPC for use by lazy linking and exeptions.
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- restoreArgumentReference();
- Call callLazyLinkConstruct = call();
- restoreReturnAddressBeforeReturn(regT3);
- jump(regT0);
-
- // VirtualCall Trampoline
- // regT1, regT0 holds callee; regT2 will hold the FunctionExecutable.
- Label virtualCallBegin = align();
- callSlowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- callSlowCase.append(emitJumpIfNotType(regT0, regT1, JSFunctionType));
-
- // Finish canonical initialization before JS function call.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump hasCodeBlock1 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), TrustedImm32(0));
- preserveReturnAddressAfterCall(regT3);
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- restoreArgumentReference();
- Call callCompileCall = call();
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- hasCodeBlock1.link(this);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
- jump(regT0);
-
- // VirtualConstruct Trampoline
- // regT1, regT0 holds callee; regT2 will hold the FunctionExecutable.
- Label virtualConstructBegin = align();
- constructSlowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
- constructSlowCase.append(emitJumpIfNotType(regT0, regT1, JSFunctionType));
-
- // Finish canonical initialization before JS function call.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- Jump hasCodeBlock2 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), TrustedImm32(0));
- preserveReturnAddressAfterCall(regT3);
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- restoreArgumentReference();
- Call callCompileConstruct = call();
- restoreReturnAddressBeforeReturn(regT3);
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- hasCodeBlock2.link(this);
- loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
- jump(regT0);
-
- callSlowCase.link(this);
- // Finish canonical initialization before JS function call.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2, regT2);
- emitPutCellToCallFrameHeader(regT2, RegisterFile::ScopeChain);
-
- // Also initialize ReturnPC and CodeBlock, like a JS function would.
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- restoreArgumentReference();
- Call callCallNotJSFunction = call();
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
- restoreReturnAddressBeforeReturn(regT3);
- ret();
-
- constructSlowCase.link(this);
- // Finish canonical initialization before JS function call.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2, regT2);
- emitPutCellToCallFrameHeader(regT2, RegisterFile::ScopeChain);
-
- // Also initialize ReturnPC and CodeBlock, like a JS function would.
- preserveReturnAddressAfterCall(regT3);
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
- emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- restoreArgumentReference();
- Call callConstructNotJSFunction = call();
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
- restoreReturnAddressBeforeReturn(regT3);
- ret();
-
- // NativeCall Trampoline
- Label nativeCallThunk = privateCompileCTINativeCall(globalData);
- Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true);
-
- Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
- Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
- Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
-
- // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(*m_globalData, this, GLOBAL_THUNK_ID);
-
- 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));
- patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
- patchBuffer.link(callLazyLinkConstruct, FunctionPtr(cti_vm_lazyLinkConstruct));
- patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile));
- patchBuffer.link(callCompileConstruct, FunctionPtr(cti_op_construct_jitCompile));
- patchBuffer.link(callCallNotJSFunction, FunctionPtr(cti_op_call_NotJSFunction));
- patchBuffer.link(callConstructNotJSFunction, FunctionPtr(cti_op_construct_NotJSConstruct));
-
- CodeRef finalCode = patchBuffer.finalizeCode();
- RefPtr<ExecutableMemoryHandle> executableMemory = finalCode.executableMemory();
-
- trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
- trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin);
- trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
- trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin);
- trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk);
- trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk);
- trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
-
- return executableMemory.release();
-}
-
-JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct)
-{
- int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function);
-
- Label nativeCallThunk = align();
-
- emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
-
-#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);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- peek(regT1);
- emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
-
- // Calling convention: f(ecx, edx, ...);
- // Host function signature: f(ExecState*);
- move(callFrameRegister, X86Registers::ecx);
-
- subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
-
- // 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));
-
- addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
-
-#elif CPU(ARM)
- // Load caller frame's scope chain into this callframe so that whatever we call can
- // get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- preserveReturnAddressAfterCall(regT3); // Callee preserved
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-
- // Calling convention: f(r0 == regT0, r1 == regT1, ...);
- // Host function signature: f(ExecState*);
- move(callFrameRegister, ARMRegisters::r0);
-
- // call the function
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1);
- move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
- loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- call(Address(regT2, executableOffsetToFunction));
-
- restoreReturnAddressBeforeReturn(regT3);
-#elif CPU(SH4)
- // Load caller frame's scope chain into this callframe so that whatever we call can
- // get to its global data.
- emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
- emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- preserveReturnAddressAfterCall(regT3); // Callee preserved
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-
- // Calling convention: f(r0 == regT4, r1 == regT5, ...);
- // Host function signature: f(ExecState*);
- move(callFrameRegister, regT4);
-
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5);
- move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
- loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-
- call(Address(regT2, executableOffsetToFunction), regT0);
- restoreReturnAddressBeforeReturn(regT3);
-#elif CPU(MIPS)
- // 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);
- emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
-
- preserveReturnAddressAfterCall(regT3); // Callee preserved
- emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-
- // Calling convention: f(a0, a1, a2, a3);
- // Host function signature: f(ExecState*);
-
- // Allocate stack space for 16 bytes (8-byte aligned)
- // 16 bytes (unused) for 4 arguments
- subPtr(TrustedImm32(16), stackPointerRegister);
-
- // Setup arg0
- move(callFrameRegister, MIPSRegisters::a0);
-
- // Call
- emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
- loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
- move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
- call(Address(regT2, executableOffsetToFunction));
-
- // Restore stack space
- addPtr(TrustedImm32(16), stackPointerRegister);
-
- restoreReturnAddressBeforeReturn(regT3);
-
-#else
-#error "JIT not supported on this platform."
- UNUSED_PARAM(executableOffsetToFunction);
- breakpoint();
-#endif // CPU(X86)
-
- // Check for an exception
- Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
-
- // Return.
- ret();
-
- // Handle an exception
- sawException.link(this);
-
- // Grab the return address.
- preserveReturnAddressAfterCall(regT1);
-
- move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
- storePtr(regT1, regT2);
- poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
-
- storePtr(callFrameRegister, &m_globalData->topCallFrame);
- // Set the return address.
- move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
- restoreReturnAddressBeforeReturn(regT1);
-
- ret();
-
- return nativeCallThunk;
-}
-
-JIT::CodeRef JIT::privateCompileCTINativeCall(JSGlobalData* globalData, NativeFunction func)