bool run() { RELEASE_ASSERT(m_graph.m_plan.mode == DFGMode); if (!Options::useFTLJIT()) return false; if (m_graph.m_profiledBlock->m_didFailFTLCompilation) return false; if (!Options::bytecodeRangeToFTLCompile().isInRange(m_graph.m_profiledBlock->instructionCount())) return false; #if ENABLE(FTL_JIT) FTL::CapabilityLevel level = FTL::canCompile(m_graph); if (level == FTL::CannotCompile) return false; if (!Options::useOSREntryToFTL()) level = FTL::CanCompile; // First we find all the loops that contain a LoopHint for which we cannot OSR enter. // We use that information to decide if we need CheckTierUpAndOSREnter or CheckTierUpWithNestedTriggerAndOSREnter. m_graph.ensureNaturalLoops(); NaturalLoops& naturalLoops = *m_graph.m_naturalLoops; HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter = findLoopsContainingLoopHintWithoutOSREnter(naturalLoops, level); InsertionSet insertionSet(m_graph); for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { Node* node = block->at(nodeIndex); if (node->op() != LoopHint) continue; NodeOrigin origin = node->origin; if (canOSREnterAtLoopHint(level, block, nodeIndex)) { const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block); if (loop && loopsContainingLoopHintWithoutOSREnter.contains(loop)) insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpWithNestedTriggerAndOSREnter, origin); else insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpAndOSREnter, origin); } else insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin); break; } NodeAndIndex terminal = block->findTerminal(); if (terminal.node->isFunctionTerminal()) { insertionSet.insertNode( terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin); } insertionSet.execute(block); } m_graph.m_plan.willTryToTierUp = true; return true; #else // ENABLE(FTL_JIT) RELEASE_ASSERT_NOT_REACHED(); return false; #endif // ENABLE(FTL_JIT) }
bool run() { RELEASE_ASSERT(m_graph.m_plan.mode == DFGMode); if (!Options::useFTLJIT()) return false; if (m_graph.m_profiledBlock->m_didFailFTLCompilation) return false; if (!Options::bytecodeRangeToFTLCompile().isInRange(m_graph.m_profiledBlock->instructionCount())) return false; #if ENABLE(FTL_JIT) FTL::CapabilityLevel level = FTL::canCompile(m_graph); if (level == FTL::CannotCompile) return false; if (!Options::useOSREntryToFTL()) level = FTL::CanCompile; m_graph.ensureNaturalLoops(); NaturalLoops& naturalLoops = *m_graph.m_naturalLoops; HashMap<const NaturalLoop*, unsigned> naturalLoopToLoopHint = buildNaturalLoopToLoopHintMap(naturalLoops); HashMap<unsigned, LoopHintDescriptor> tierUpHierarchy; InsertionSet insertionSet(m_graph); for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { Node* node = block->at(nodeIndex); if (node->op() != LoopHint) continue; NodeOrigin origin = node->origin; bool canOSREnter = canOSREnterAtLoopHint(level, block, nodeIndex); NodeType tierUpType = CheckTierUpAndOSREnter; if (!canOSREnter) tierUpType = CheckTierUpInLoop; insertionSet.insertNode(nodeIndex + 1, SpecNone, tierUpType, origin); unsigned bytecodeIndex = origin.semantic.bytecodeIndex; if (canOSREnter) m_graph.m_plan.tierUpAndOSREnterBytecodes.append(bytecodeIndex); if (const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block)) { LoopHintDescriptor descriptor; descriptor.canOSREnter = canOSREnter; const NaturalLoop* outerLoop = loop; while ((outerLoop = naturalLoops.innerMostOuterLoop(*outerLoop))) { auto it = naturalLoopToLoopHint.find(outerLoop); if (it != naturalLoopToLoopHint.end()) descriptor.osrEntryCandidates.append(it->value); } if (!descriptor.osrEntryCandidates.isEmpty()) tierUpHierarchy.add(bytecodeIndex, WTFMove(descriptor)); } break; } NodeAndIndex terminal = block->findTerminal(); if (terminal.node->isFunctionTerminal()) { insertionSet.insertNode( terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin); } insertionSet.execute(block); } // Add all the candidates that can be OSR Entered. for (auto entry : tierUpHierarchy) { Vector<unsigned> tierUpCandidates; for (unsigned bytecodeIndex : entry.value.osrEntryCandidates) { auto descriptorIt = tierUpHierarchy.find(bytecodeIndex); if (descriptorIt != tierUpHierarchy.end() && descriptorIt->value.canOSREnter) tierUpCandidates.append(bytecodeIndex); } if (!tierUpCandidates.isEmpty()) m_graph.m_plan.tierUpInLoopHierarchy.add(entry.key, WTFMove(tierUpCandidates)); } m_graph.m_plan.willTryToTierUp = true; return true; #else // ENABLE(FTL_JIT) RELEASE_ASSERT_NOT_REACHED(); return false; #endif // ENABLE(FTL_JIT) }