MacroAssemblerCodeRef osrExitGenerationThunkGenerator(VM* vm) { MacroAssembler jit; // This needs to happen before we use the scratch buffer because this function also uses the scratch buffer. adjustFrameAndStackInOSRExitCompilerThunk<DFG::JITCode>(jit, vm, JITCode::DFGJIT); size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters); ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(scratchSize); EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()); for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) { #if USE(JSVALUE64) jit.store64(GPRInfo::toRegister(i), buffer + i); #else jit.store32(GPRInfo::toRegister(i), buffer + i); #endif } for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0); jit.storeDouble(FPRInfo::toRegister(i), MacroAssembler::Address(GPRInfo::regT0)); } // Tell GC mark phase how much of the scratch buffer is active during call. jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0); jit.storePtr(MacroAssembler::TrustedImmPtr(scratchSize), MacroAssembler::Address(GPRInfo::regT0)); // Set up one argument. #if CPU(X86) jit.poke(GPRInfo::callFrameRegister, 0); #else jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); #endif MacroAssembler::Call functionCall = jit.call(); jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0); jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(GPRInfo::regT0)); for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0); jit.loadDouble(MacroAssembler::Address(GPRInfo::regT0), FPRInfo::toRegister(i)); } for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) { #if USE(JSVALUE64) jit.load64(buffer + i, GPRInfo::toRegister(i)); #else jit.load32(buffer + i, GPRInfo::toRegister(i)); #endif } jit.jump(MacroAssembler::AbsoluteAddress(&vm->osrExitJumpDestination)); LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID); patchBuffer.link(functionCall, compileOSRExit); return FINALIZE_CODE(patchBuffer, ("DFG OSR exit generation thunk")); }
MacroAssemblerCodeRef osrExitGenerationThunkGenerator(JSGlobalData* globalData) { MacroAssembler jit; size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters); ScratchBuffer* scratchBuffer = globalData->scratchBufferForSize(scratchSize); EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()); for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) jit.storePtr(GPRInfo::toRegister(i), buffer + i); for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0); jit.storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0); } // Tell GC mark phase how much of the scratch buffer is active during call. jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0); jit.storePtr(MacroAssembler::TrustedImmPtr(scratchSize), GPRInfo::regT0); // Set up one argument. #if CPU(X86) jit.poke(GPRInfo::callFrameRegister, 0); #else jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); #endif MacroAssembler::Call functionCall = jit.call(); jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0); jit.storePtr(MacroAssembler::TrustedImmPtr(0), GPRInfo::regT0); for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { jit.move(MacroAssembler::TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0); jit.loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i)); } for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) jit.loadPtr(buffer + i, GPRInfo::toRegister(i)); jit.jump(MacroAssembler::AbsoluteAddress(&globalData->osrExitJumpDestination)); LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID); patchBuffer.link(functionCall, compileOSRExit); return FINALIZE_CODE(patchBuffer, ("DFG OSR exit generation thunk")); }
MacroAssemblerCodeRef osrExitGenerationThunkGenerator(VM* vm) { AssemblyHelpers jit(vm, 0); // Note that the "return address" will be the OSR exit ID. ptrdiff_t stackMisalignment = MacroAssembler::pushToSaveByteOffset(); // Pretend that we're a C call frame. jit.pushToSave(MacroAssembler::framePointerRegister); jit.move(MacroAssembler::stackPointerRegister, MacroAssembler::framePointerRegister); stackMisalignment += MacroAssembler::pushToSaveByteOffset(); // Now create ourselves enough stack space to give saveAllRegisters() a scratch slot. unsigned numberOfRequiredPops = 0; do { jit.pushToSave(GPRInfo::regT0); stackMisalignment += MacroAssembler::pushToSaveByteOffset(); numberOfRequiredPops++; } while (stackMisalignment % stackAlignmentBytes()); ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(requiredScratchMemorySizeInBytes()); char* buffer = static_cast<char*>(scratchBuffer->dataBuffer()); saveAllRegisters(jit, buffer); // Tell GC mark phase how much of the scratch buffer is active during call. jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::nonArgGPR1); jit.storePtr(MacroAssembler::TrustedImmPtr(requiredScratchMemorySizeInBytes()), GPRInfo::nonArgGPR1); jit.loadPtr(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); jit.peek( GPRInfo::argumentGPR1, (stackMisalignment - MacroAssembler::pushToSaveByteOffset()) / sizeof(void*)); MacroAssembler::Call functionCall = jit.call(); // At this point we want to make a tail call to what was returned to us in the // returnValueGPR. But at the same time as we do this, we must restore all registers. // The way we will accomplish this is by arranging to have the tail call target in the // return address "slot" (be it a register or the stack). jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); // Make sure we tell the GC that we're not using the scratch buffer anymore. jit.move(MacroAssembler::TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT1); jit.storePtr(MacroAssembler::TrustedImmPtr(0), GPRInfo::regT1); // Prepare for tail call. while (numberOfRequiredPops--) jit.popToRestore(GPRInfo::regT1); jit.popToRestore(MacroAssembler::framePointerRegister); // At this point we're sitting on the return address - so if we did a jump right now, the // tail-callee would be happy. Instead we'll stash the callee in the return address and then // restore all registers. jit.restoreReturnAddressBeforeReturn(GPRInfo::regT0); restoreAllRegisters(jit, buffer); jit.ret(); LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID); patchBuffer.link(functionCall, compileFTLOSRExit); return FINALIZE_CODE(patchBuffer, ("FTL OSR exit generation thunk")); }