]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGTierUpCheckInjectionPhase.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGTierUpCheckInjectionPhase.cpp
1 /*
2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "DFGTierUpCheckInjectionPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGGraph.h"
32 #include "DFGInsertionSet.h"
33 #include "DFGPhase.h"
34 #include "FTLCapabilities.h"
35 #include "JSCInlines.h"
36
37 namespace JSC { namespace DFG {
38
39 class TierUpCheckInjectionPhase : public Phase {
40 public:
41 TierUpCheckInjectionPhase(Graph& graph)
42 : Phase(graph, "tier-up check injection")
43 {
44 }
45
46 bool run()
47 {
48 RELEASE_ASSERT(m_graph.m_plan.mode == DFGMode);
49
50 if (!Options::useFTLJIT())
51 return false;
52
53 if (m_graph.m_profiledBlock->m_didFailFTLCompilation)
54 return false;
55
56 #if ENABLE(FTL_JIT)
57 FTL::CapabilityLevel level = FTL::canCompile(m_graph);
58 if (level == FTL::CannotCompile)
59 return false;
60
61 if (!Options::enableOSREntryToFTL())
62 level = FTL::CanCompile;
63
64 // First we find all the loops that contain a LoopHint for which we cannot OSR enter.
65 // We use that information to decide if we need CheckTierUpAndOSREnter or CheckTierUpWithNestedTriggerAndOSREnter.
66 NaturalLoops& naturalLoops = m_graph.m_naturalLoops;
67 naturalLoops.computeIfNecessary(m_graph);
68
69 HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter = findLoopsContainingLoopHintWithoutOSREnter(naturalLoops, level);
70
71 InsertionSet insertionSet(m_graph);
72 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
73 BasicBlock* block = m_graph.block(blockIndex);
74 if (!block)
75 continue;
76
77 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
78 Node* node = block->at(nodeIndex);
79 if (node->op() != LoopHint)
80 continue;
81
82 NodeOrigin origin = node->origin;
83 if (canOSREnterAtLoopHint(level, block, nodeIndex)) {
84 const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block);
85 if (loop && loopsContainingLoopHintWithoutOSREnter.contains(loop))
86 insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpWithNestedTriggerAndOSREnter, origin);
87 else
88 insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpAndOSREnter, origin);
89 } else
90 insertionSet.insertNode(nodeIndex + 1, SpecNone, CheckTierUpInLoop, origin);
91 break;
92 }
93
94 NodeAndIndex terminal = block->findTerminal();
95 if (terminal.node->op() == Return) {
96 insertionSet.insertNode(
97 terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin);
98 }
99
100 insertionSet.execute(block);
101 }
102
103 m_graph.m_plan.willTryToTierUp = true;
104 return true;
105 #else // ENABLE(FTL_JIT)
106 RELEASE_ASSERT_NOT_REACHED();
107 return false;
108 #endif // ENABLE(FTL_JIT)
109 }
110
111 private:
112 #if ENABLE(FTL_JIT)
113 bool canOSREnterAtLoopHint(FTL::CapabilityLevel level, const BasicBlock* block, unsigned nodeIndex)
114 {
115 Node* node = block->at(nodeIndex);
116 ASSERT(node->op() == LoopHint);
117
118 NodeOrigin origin = node->origin;
119 if (level != FTL::CanCompileAndOSREnter || origin.semantic.inlineCallFrame)
120 return false;
121
122 // We only put OSR checks for the first LoopHint in the block. Note that
123 // more than one LoopHint could happen in cases where we did a lot of CFG
124 // simplification in the bytecode parser, but it should be very rare.
125 for (unsigned subNodeIndex = nodeIndex; subNodeIndex--;) {
126 if (!block->at(subNodeIndex)->isSemanticallySkippable())
127 return false;
128 }
129 return true;
130 }
131
132 HashSet<const NaturalLoop*> findLoopsContainingLoopHintWithoutOSREnter(const NaturalLoops& naturalLoops, FTL::CapabilityLevel level)
133 {
134 HashSet<const NaturalLoop*> loopsContainingLoopHintWithoutOSREnter;
135 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
136 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
137 Node* node = block->at(nodeIndex);
138 if (node->op() != LoopHint)
139 continue;
140
141 if (!canOSREnterAtLoopHint(level, block, nodeIndex)) {
142 const NaturalLoop* loop = naturalLoops.innerMostLoopOf(block);
143 while (loop) {
144 loopsContainingLoopHintWithoutOSREnter.add(loop);
145 loop = naturalLoops.innerMostOuterLoop(*loop);
146 }
147 }
148 }
149 }
150 return loopsContainingLoopHintWithoutOSREnter;
151 }
152 #endif
153 };
154
155 bool performTierUpCheckInjection(Graph& graph)
156 {
157 SamplingRegion samplingRegion("DFG Tier-up Check Injection");
158 return runPhase<TierUpCheckInjectionPhase>(graph);
159 }
160
161 } } // namespace JSC::DFG
162
163 #endif // ENABLE(DFG_JIT)
164
165