void compileOSRExit(ExecState* exec) { SamplingRegion samplingRegion("DFG OSR Exit Compilation"); CodeBlock* codeBlock = exec->codeBlock(); ASSERT(codeBlock); ASSERT(codeBlock->getJITType() == JITCode::DFGJIT); JSGlobalData* globalData = &exec->globalData(); uint32_t exitIndex = globalData->osrExitIndex; OSRExit& exit = codeBlock->osrExit(exitIndex); // Make sure all code on our inline stack is JIT compiled. This is necessary since // we may opt to inline a code block even before it had ever been compiled by the // JIT, but our OSR exit infrastructure currently only works if the target of the // OSR exit is JIT code. This could be changed since there is nothing particularly // hard about doing an OSR exit into the interpreter, but for now this seems to make // sense in that if we're OSR exiting from inlined code of a DFG code block, then // probably it's a good sign that the thing we're exiting into is hot. Even more // interestingly, since the code was inlined, it may never otherwise get JIT // compiled since the act of inlining it may ensure that it otherwise never runs. for (CodeOrigin codeOrigin = exit.m_codeOrigin; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) { static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get()) ->baselineCodeBlockFor(codeOrigin.inlineCallFrame->isCall ? CodeForCall : CodeForConstruct) ->jitCompile(exec); } // Compute the value recoveries. Operands<ValueRecovery> operands; codeBlock->variableEventStream().reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->minifiedDFG(), exit.m_streamIndex, operands); // There may be an override, for forward speculations. if (!!exit.m_valueRecoveryOverride) { operands.setOperand( exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery); } SpeculationRecovery* recovery = 0; if (exit.m_recoveryIndex) recovery = &codeBlock->speculationRecovery(exit.m_recoveryIndex - 1); #if DFG_ENABLE(DEBUG_VERBOSE) dataLog( "Generating OSR exit #", exitIndex, " (seq#", exit.m_streamIndex, ", bc#", exit.m_codeOrigin.bytecodeIndex, ", @", exit.m_nodeIndex, ", ", exit.m_kind, ") for ", *codeBlock, ".\n"); #endif { CCallHelpers jit(globalData, codeBlock); OSRExitCompiler exitCompiler(jit); jit.jitAssertHasValidCallFrame(); if (globalData->m_perBytecodeProfiler && codeBlock->compilation()) { Profiler::Database& database = *globalData->m_perBytecodeProfiler; Profiler::Compilation* compilation = codeBlock->compilation(); Profiler::OSRExit* profilerExit = compilation->addOSRExit( exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin), exit.m_kind, exit.m_watchpointIndex != std::numeric_limits<unsigned>::max()); jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress())); } exitCompiler.compileExit(exit, operands, recovery); LinkBuffer patchBuffer(*globalData, &jit, codeBlock); exit.m_code = FINALIZE_CODE_IF( shouldShowDisassembly(), patchBuffer, ("DFG OSR exit #%u (bc#%u, @%u, %s) from %s", exitIndex, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, exitKindToString(exit.m_kind), toCString(*codeBlock).data())); } { RepatchBuffer repatchBuffer(codeBlock); repatchBuffer.relink(exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code())); } globalData->osrExitJumpDestination = exit.m_code.code().executableAddress(); }
void compileOSRExit(ExecState* exec) { SamplingRegion samplingRegion("DFG OSR Exit Compilation"); CodeBlock* codeBlock = exec->codeBlock(); ASSERT(codeBlock); ASSERT(codeBlock->jitType() == JITCode::DFGJIT); VM* vm = &exec->vm(); // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't // really be profitable. DeferGCForAWhile deferGC(vm->heap); uint32_t exitIndex = vm->osrExitIndex; OSRExit& exit = codeBlock->jitCode()->dfg()->osrExit[exitIndex]; prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin); // Compute the value recoveries. Operands<ValueRecovery> operands; codeBlock->jitCode()->dfg()->variableEventStream.reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->jitCode()->dfg()->minifiedDFG, exit.m_streamIndex, operands); // There may be an override, for forward speculations. if (!!exit.m_valueRecoveryOverride) { operands.setOperand( exit.m_valueRecoveryOverride->operand, exit.m_valueRecoveryOverride->recovery); } SpeculationRecovery* recovery = 0; if (exit.m_recoveryIndex != UINT_MAX) recovery = &codeBlock->jitCode()->dfg()->speculationRecovery[exit.m_recoveryIndex]; { CCallHelpers jit(vm, codeBlock); OSRExitCompiler exitCompiler(jit); jit.jitAssertHasValidCallFrame(); if (vm->m_perBytecodeProfiler && codeBlock->jitCode()->dfgCommon()->compilation) { Profiler::Database& database = *vm->m_perBytecodeProfiler; Profiler::Compilation* compilation = codeBlock->jitCode()->dfgCommon()->compilation.get(); Profiler::OSRExit* profilerExit = compilation->addOSRExit( exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin), exit.m_kind, exit.m_kind == UncountableInvalidation); jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress())); } exitCompiler.compileExit(exit, operands, recovery); LinkBuffer patchBuffer(*vm, jit, codeBlock); exit.m_code = FINALIZE_CODE_IF( shouldShowDisassembly() || Options::verboseOSR(), patchBuffer, ("DFG OSR exit #%u (%s, %s) from %s, with operands = %s", exitIndex, toCString(exit.m_codeOrigin).data(), exitKindToString(exit.m_kind), toCString(*codeBlock).data(), toCString(ignoringContext<DumpContext>(operands)).data())); } { RepatchBuffer repatchBuffer(codeBlock); repatchBuffer.relink(exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code())); } vm->osrExitJumpDestination = exit.m_code.code().executableAddress(); }