diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp')
| -rw-r--r-- | Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp | 100 |
1 files changed, 86 insertions, 14 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp b/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp index d51a1f0d8..9b14a9820 100644 --- a/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,9 +30,10 @@ #include "DFGGraph.h" #include "DFGInsertionSet.h" +#include "DFGNaturalLoops.h" #include "DFGPhase.h" #include "FTLCapabilities.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace DFG { @@ -47,7 +48,13 @@ public: { RELEASE_ASSERT(m_graph.m_plan.mode == DFGMode); - if (!Options::useExperimentalFTL()) + 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) @@ -55,37 +62,102 @@ public: 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); + + bool canTierUpAndOSREnter = false; + InsertionSet insertionSet(m_graph); for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { BasicBlock* block = m_graph.block(blockIndex); if (!block) continue; - if (block->at(0)->op() == LoopHint) { - CodeOrigin codeOrigin = block->at(0)->codeOrigin; - NodeType nodeType; - if (level == FTL::CanCompileAndOSREnter && !codeOrigin.inlineCallFrame) { - nodeType = CheckTierUpAndOSREnter; - RELEASE_ASSERT(block->bytecodeBegin == codeOrigin.bytecodeIndex); + 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)) { + canTierUpAndOSREnter = true; + 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 - nodeType = CheckTierUpInLoop; - insertionSet.insertNode(1, SpecNone, nodeType, codeOrigin); + insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin); + break; } - if (block->last()->op() == Return) { + NodeAndIndex terminal = block->findTerminal(); + if (terminal.node->isFunctionTerminal()) { insertionSet.insertNode( - block->size() - 1, SpecNone, CheckTierUpAtReturn, block->last()->codeOrigin); + terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin); } insertionSet.execute(block); } - + + m_graph.m_plan.canTierUpAndOSREnter = canTierUpAndOSREnter; + m_graph.m_plan.willTryToTierUp = true; return true; #else // ENABLE(FTL_JIT) RELEASE_ASSERT_NOT_REACHED(); return false; #endif // ENABLE(FTL_JIT) } + +private: +#if ENABLE(FTL_JIT) + bool canOSREnterAtLoopHint(FTL::CapabilityLevel level, const BasicBlock* block, unsigned nodeIndex) + { + Node* node = block->at(nodeIndex); + ASSERT(node->op() == LoopHint); + + NodeOrigin origin = node->origin; + if (level != FTL::CanCompileAndOSREnter || origin.semantic.inlineCallFrame) + return false; + + // We only put OSR checks for the first LoopHint in the block. Note that + // more than one LoopHint could happen in cases where we did a lot of CFG + // simplification in the bytecode parser, but it should be very rare. + for (unsigned subNodeIndex = nodeIndex; subNodeIndex--;) { + if (!block->at(subNodeIndex)->isSemanticallySkippable()) + return false; + } + return true; + } + + HashSet<const NaturalLoop*> findLoopsContainingLoopHintWithoutOSREnter(const NaturalLoops& naturalLoops, FTL::CapabilityLevel level) + { + HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter; + for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { + for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { + Node* node = block->at(nodeIndex); + if (node->op() != LoopHint) + continue; + + if (!canOSREnterAtLoopHint(level, block, nodeIndex)) { + const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block); + while (loop) { + loopsContainingLoopHintWithoutOSREnter.add(loop); + loop = naturalLoops.innerMostOuterLoop(*loop); + } + } + } + } + return loopsContainingLoopHintWithoutOSREnter; + } +#endif }; bool performTierUpCheckInjection(Graph& graph) |
