}
}
-static char* tierUpCommon(ExecState* exec, unsigned originBytecodeIndex, unsigned osrEntryBytecodeIndex)
+static char* tierUpCommon(ExecState* exec, unsigned originBytecodeIndex, bool canOSREnterHere)
{
VM* vm = &exec->vm();
CodeBlock* codeBlock = exec->codeBlock();
worklistState = Worklist::NotKnown;
JITCode* jitCode = codeBlock->jitCode()->dfg();
-
- // The following is only true for triggerTierUpNowInLoop, which can never
- // be an OSR entry.
- bool canOSRFromHere = originBytecodeIndex == osrEntryBytecodeIndex;
bool triggeredSlowPathToStartCompilation = false;
auto tierUpEntryTriggers = jitCode->tierUpEntryTriggers.find(originBytecodeIndex);
case JITCode::TriggerReason::CompilationDone:
// The trigger was set because compilation completed. Don't unset it
- // so that further DFG executions OSR enters as well.
- RELEASE_ASSERT(canOSRFromHere);
+ // so that further DFG executions OSR enter as well.
break;
case JITCode::TriggerReason::StartCompilation:
// We were asked to enter as soon as possible and start compiling an
// entry for the current bytecode location. Unset this trigger so we
// don't continually enter.
- RELEASE_ASSERT(canOSRFromHere);
tierUpEntryTriggers->value = JITCode::TriggerReason::DontTrigger;
triggeredSlowPathToStartCompilation = true;
break;
if (worklistState == Worklist::Compiling) {
CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling"));
- jitCode->setOptimizationThresholdBasedOnCompilationResult(
- codeBlock, CompilationDeferred);
+ jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
return nullptr;
}
+ // If we can OSR Enter, do it right away.
+ if (canOSREnterHere) {
+ auto iter = jitCode->bytecodeIndexToStreamIndex.find(originBytecodeIndex);
+ if (iter != jitCode->bytecodeIndexToStreamIndex.end()) {
+ unsigned streamIndex = iter->value;
+ if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
+ if (Options::verboseOSR())
+ dataLog("OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(entryBlock), "\n");
+ if (void* address = FTL::prepareOSREntry(exec, codeBlock, entryBlock, originBytecodeIndex, streamIndex)) {
+ CODEBLOCK_LOG_EVENT(entryBlock, "osrEntry", ("at bc#", originBytecodeIndex));
+ return retagCodePtr<char*>(address, JSEntryPtrTag, bitwise_cast<PtrTag>(exec));
+ }
+ }
+ }
+ }
+
if (worklistState == Worklist::Compiled) {
CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("compiled and failed"));
// This means that compilation failed and we already set the thresholds.
return nullptr;
}
- // If we can OSR Enter, do it right away.
- if (canOSRFromHere) {
- unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(originBytecodeIndex);
- if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
- if (Options::verboseOSR())
- dataLog("OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(entryBlock), "\n");
- if (void* address = FTL::prepareOSREntry(exec, codeBlock, entryBlock, originBytecodeIndex, streamIndex)) {
- CODEBLOCK_LOG_EVENT(entryBlock, "osrEntry", ("at bc#", originBytecodeIndex));
- return retagCodePtr<char*>(address, JSEntryPtrTag, bitwise_cast<PtrTag>(exec));
- }
- }
- }
-
// - If we don't have an FTL code block, then try to compile one.
// - If we do have an FTL code block, then try to enter for a while.
// - If we couldn't enter for a while, then trigger OSR entry.
} else
CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("avoiding replacement compile"));
- // It's time to try to compile code for OSR entry.
if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed, OSR entry threshold not met"));
return nullptr;
}
- if (!canOSRFromHere) {
- // We can't OSR from here, or even start a compilation because doing so
- // calls jitCode->reconstruct which would get the wrong state.
- if (Options::verboseOSR())
- dataLog("Non-OSR-able bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryBytecodeIndex, "'s trigger and backing off.\n");
- jitCode->tierUpEntryTriggers.set(osrEntryBytecodeIndex, JITCode::TriggerReason::StartCompilation);
- jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
- return nullptr;
- }
-
- unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(osrEntryBytecodeIndex);
+ // It's time to try to compile code for OSR entry.
if (!triggeredSlowPathToStartCompilation) {
- auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(osrEntryBytecodeIndex);
- if (tierUpHierarchyEntry != jitCode->tierUpInLoopHierarchy.end()) {
- for (unsigned osrEntryCandidate : tierUpHierarchyEntry->value) {
- if (jitCode->tierUpEntrySeen.contains(osrEntryCandidate)) {
- // Ask an enclosing loop to compile, instead of doing so here.
- if (Options::verboseOSR())
- dataLog("Inner-loop bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryCandidate, "'s trigger and backing off.\n");
- jitCode->tierUpEntryTriggers.set(osrEntryCandidate, JITCode::TriggerReason::StartCompilation);
- jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
- return nullptr;
+
+ // An inner loop didn't specifically ask for us to kick off a compilation. This means the counter
+ // crossed its threshold. We either fall through and kick off a compile for originBytecodeIndex,
+ // or we flag an outer loop to immediately try to compile itself. If there are outer loops,
+ // we first try to make them compile themselves. But we will eventually fall back to compiling
+ // a progressively inner loop if it takes too long for control to reach an outer loop.
+
+ auto tryTriggerOuterLoopToCompile = [&] {
+ auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(originBytecodeIndex);
+ if (tierUpHierarchyEntry == jitCode->tierUpInLoopHierarchy.end())
+ return false;
+
+ // This vector is ordered from innermost to outermost loop. Every bytecode entry in this vector is
+ // allowed to do OSR entry. We start with the outermost loop and make our way inwards (hence why we
+ // iterate the vector in reverse). Our policy is that we will trigger an outer loop to compile
+ // immediately when program control reaches it. If program control is taking too long to reach that
+ // outer loop, we progressively move inwards, meaning, we'll eventually trigger some loop that is
+ // executing to compile. We start with trying to compile outer loops since we believe outer loop
+ // compilations reveal the best opportunities for optimizing code.
+ for (auto iter = tierUpHierarchyEntry->value.rbegin(), end = tierUpHierarchyEntry->value.rend(); iter != end; ++iter) {
+ unsigned osrEntryCandidate = *iter;
+
+ if (jitCode->tierUpEntryTriggers.get(osrEntryCandidate) == JITCode::TriggerReason::StartCompilation) {
+ // This means that we already asked this loop to compile. If we've reached here, it
+ // means program control has not yet reached that loop. So it's taking too long to compile.
+ // So we move on to asking the inner loop of this loop to compile itself.
+ continue;
}
+
+ // This is where we ask the outer to loop to immediately compile itself if program
+ // control reaches it.
+ if (Options::verboseOSR())
+ dataLog("Inner-loop bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryCandidate, "'s trigger and backing off.\n");
+ jitCode->tierUpEntryTriggers.set(osrEntryCandidate, JITCode::TriggerReason::StartCompilation);
+ return true;
}
+
+ return false;
+ };
+
+ if (tryTriggerOuterLoopToCompile()) {
+ jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
+ return nullptr;
}
}
+ if (!canOSREnterHere) {
+ jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
+ return nullptr;
+ }
+
// We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
// something.
- auto triggerIterator = jitCode->tierUpEntryTriggers.find(osrEntryBytecodeIndex);
- RELEASE_ASSERT(triggerIterator != jitCode->tierUpEntryTriggers.end());
+
+ auto triggerIterator = jitCode->tierUpEntryTriggers.find(originBytecodeIndex);
+ if (triggerIterator == jitCode->tierUpEntryTriggers.end()) {
+ jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred);
+ return nullptr;
+ }
+
JITCode::TriggerReason* triggerAddress = &(triggerIterator->value);
Operands<JSValue> mustHandleValues;
+ unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(originBytecodeIndex);
jitCode->reconstruct(
- exec, codeBlock, CodeOrigin(osrEntryBytecodeIndex), streamIndex, mustHandleValues);
+ exec, codeBlock, CodeOrigin(originBytecodeIndex), streamIndex, mustHandleValues);
CodeBlock* replacementCodeBlock = codeBlock->newReplacement();
CODEBLOCK_LOG_EVENT(codeBlock, "triggerFTLOSR", ());
CompilationResult forEntryResult = compile(
- *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, osrEntryBytecodeIndex,
+ *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, originBytecodeIndex,
mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(triggerAddress));
if (jitCode->neverExecutedEntry)
// We signal to try again after a while if that happens.
if (Options::verboseOSR())
dataLog("Immediate OSR entry: From ", RawPointer(jitCode), " got entry block ", RawPointer(jitCode->osrEntryBlock()), "\n");
+
void* address = FTL::prepareOSREntry(
exec, codeBlock, jitCode->osrEntryBlock(), originBytecodeIndex, streamIndex);
if (!address)
sanitizeStackForVM(vm);
if (codeBlock->jitType() != JITCode::DFGJIT) {
- dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n");
+ dataLog("Unexpected code block in DFG->FTL trigger tier up now in loop: ", *codeBlock, "\n");
RELEASE_ASSERT_NOT_REACHED();
}
jitCode->tierUpCounter, "\n");
}
- auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(bytecodeIndex);
- if (tierUpHierarchyEntry != jitCode->tierUpInLoopHierarchy.end()
- && !tierUpHierarchyEntry->value.isEmpty()) {
- tierUpCommon(exec, bytecodeIndex, tierUpHierarchyEntry->value.first());
- } else if (shouldTriggerFTLCompile(codeBlock, jitCode))
+ if (jitCode->tierUpInLoopHierarchy.contains(bytecodeIndex))
+ tierUpCommon(exec, bytecodeIndex, false);
+ else if (shouldTriggerFTLCompile(codeBlock, jitCode))
triggerFTLReplacementCompile(vm, codeBlock, jitCode);
// Since we cannot OSR Enter here, the default "optimizeSoon()" is not useful.
jitCode->tierUpCounter, "\n");
}
- return tierUpCommon(exec, bytecodeIndex, bytecodeIndex);
+ return tierUpCommon(exec, bytecodeIndex, true);
}
#endif // ENABLE(FTL_JIT)