2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGPropagator.h"
29 #if ENABLE(DFG_JIT) && ENABLE(DYNAMIC_OPTIMIZATION)
33 namespace JSC { namespace DFG {
37 Propagator(Graph& graph, JSGlobalData& globalData, CodeBlock* codeBlock, CodeBlock* profiledBlock)
39 , m_globalData(globalData)
40 , m_codeBlock(codeBlock)
41 , m_profiledBlock(profiledBlock)
43 // Predictions is a forward flow property that propagates the values seen at
44 // a particular value source to their various uses, ensuring that uses perform
45 // speculation that does not contravene the expected values.
46 m_predictions.resize(m_graph.size());
48 // Uses is a backward flow property that propagates the hard expectations at
49 // certain uses to their value sources, ensuring that predictions about
50 // values do not contravene the code itself. This comes up only in the
51 // cases of obvious cell uses, like GetById and friends as well as Call.
52 // We're essentially statically speculating that if the value profile indicates
53 // that only booleans (for example) flow into a GetById, then the value
54 // profile is simply wrong due to insufficient coverage and needs to be
55 // adjusted accordingly. The alternatives would be to assume either
56 // that the GetById never executes, or always executes on a boolean leading
57 // to whatever bizarre behavior that's supposed to cause.
58 m_uses.resize(m_graph.size());
59 m_variableUses.initializeSimilarTo(m_graph.predictions());
61 for (unsigned i = 0; i < m_graph.size(); ++i) {
62 m_predictions[i] = PredictNone;
63 m_uses[i] = PredictNone;
69 #if ENABLE(DFG_DEBUG_VERBOSE)
75 // Forward propagation is near-optimal for both topologically-sorted and
81 // Backward propagation reduces the likelihood that pathological code will
82 // cause slowness. Loops (especially nested ones) resemble backward flow.
83 // This pass captures two cases: (1) it detects if the forward fixpoint
84 // found a sound solution and (2) short-circuits backward flow.
93 bool setPrediction(PredictedType prediction)
95 ASSERT(m_graph[m_compileIndex].hasResult());
97 if (m_predictions[m_compileIndex] == prediction)
100 m_predictions[m_compileIndex] = prediction;
104 bool mergeUse(NodeIndex nodeIndex, PredictedType prediction)
106 ASSERT(m_graph[nodeIndex].hasResult());
108 return JSC::mergePrediction(m_uses[nodeIndex], prediction);
111 bool mergePrediction(PredictedType prediction)
113 ASSERT(m_graph[m_compileIndex].hasResult());
115 return JSC::mergePrediction(m_predictions[m_compileIndex], prediction);
118 void propagateNode(Node& node)
120 if (!node.shouldGenerate())
123 NodeType op = node.op;
125 #if ENABLE(DFG_DEBUG_VERBOSE)
126 printf(" %s[%u]: ", Graph::opName(op), m_compileIndex);
129 bool changed = false;
133 changed |= setPrediction(makePrediction(predictionFromValue(node.valueOfJSConstant(m_codeBlock)), StrongPrediction));
138 changed |= m_graph.predict(node.local(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
139 changed |= m_variableUses.predict(node.local(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
141 PredictedType prediction = m_graph.getPrediction(node.local());
142 if (isStrongPrediction(prediction))
143 changed |= mergePrediction(prediction);
148 changed |= m_graph.predict(node.local(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction);
149 changed |= mergeUse(node.child1(), m_variableUses.getPrediction(node.local()));
162 changed |= setPrediction(makePrediction(PredictInt32, StrongPrediction));
166 case ValueToNumber: {
167 PredictedType prediction = m_predictions[node.child1()];
169 if (isStrongPrediction(prediction)) {
170 if (isNumberPrediction(prediction))
171 changed |= mergePrediction(prediction);
173 changed |= mergePrediction(makePrediction(PredictNumber, StrongPrediction));
180 PredictedType left = m_predictions[node.child1()];
181 PredictedType right = m_predictions[node.child2()];
183 if (isStrongPrediction(left) && isStrongPrediction(right)) {
184 if (isNumberPrediction(left) && isNumberPrediction(right)) {
185 if (isInt32Prediction(mergePredictions(left, right)))
186 changed |= mergePrediction(makePrediction(PredictInt32, StrongPrediction));
188 changed |= mergePrediction(makePrediction(PredictDouble, StrongPrediction));
189 } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
190 // left or right is definitely something other than a number.
191 changed |= mergePrediction(makePrediction(PredictString, StrongPrediction));
193 changed |= mergePrediction(makePrediction(PredictString | PredictInt32 | PredictDouble, StrongPrediction));
201 PredictedType left = m_predictions[node.child1()];
202 PredictedType right = m_predictions[node.child2()];
204 if (isStrongPrediction(left) && isStrongPrediction(right)) {
205 if (isInt32Prediction(mergePredictions(left, right)))
206 changed |= mergePrediction(makePrediction(PredictInt32, StrongPrediction));
208 changed |= mergePrediction(makePrediction(PredictDouble, StrongPrediction));
214 changed |= setPrediction(makePrediction(PredictDouble, StrongPrediction));
222 case CompareGreaterEq:
224 case CompareStrictEq:
226 changed |= setPrediction(makePrediction(PredictBoolean, StrongPrediction));
233 changed |= mergeUse(node.child1(), PredictObjectUnknown | StrongPredictionTag);
234 changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
235 if (isStrongPrediction(node.getPrediction()))
236 changed |= setPrediction(node.getPrediction());
242 changed |= mergeUse(m_graph.m_varArgChildren[node.firstChild()], PredictObjectUnknown | StrongPredictionTag);
243 changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
244 if (isStrongPrediction(node.getPrediction()))
245 changed |= setPrediction(node.getPrediction());
250 changed |= setPrediction(makePrediction(PredictObjectUnknown, StrongPrediction));
255 changed |= m_variableUses.predictGlobalVar(node.varNumber(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
256 PredictedType prediction = m_graph.getGlobalVarPrediction(node.varNumber());
257 if (isStrongPrediction(prediction))
258 changed |= mergePrediction(prediction);
263 changed |= m_graph.predictGlobalVar(node.varNumber(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction);
264 changed |= mergeUse(node.child1(), m_variableUses.getGlobalVarPrediction(node.varNumber()));
271 case PutByIdDirect: {
272 changed |= mergeUse(node.child1(), PredictObjectUnknown | StrongPredictionTag);
277 // These get ignored because they don't return anything.
281 case CheckHasInstance:
285 // These get ignored because we don't have profiling for them, yet.
288 case ResolveBaseStrictPut:
292 ASSERT_NOT_REACHED();
300 #if ENABLE(DFG_DEBUG_VERBOSE)
301 printf("expect(%s) ", predictionToString(m_predictions[m_compileIndex]));
302 printf("use(%s) %s\n", predictionToString(m_uses[m_compileIndex]), changed ? "CHANGED" : "");
305 m_changed |= changed;
308 void propagateForward()
310 #if ENABLE(DFG_DEBUG_VERBOSE)
311 printf("Propagating forward [%u]\n", ++m_count);
313 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
314 propagateNode(m_graph[m_compileIndex]);
317 void propagateBackward()
319 #if ENABLE(DFG_DEBUG_VERBOSE)
320 printf("Propagating backward [%u]\n", ++m_count);
322 for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
323 propagateNode(m_graph[m_compileIndex]);
326 void toDouble(NodeIndex nodeIndex)
328 if (m_graph[nodeIndex].op == ValueToNumber) {
329 #if ENABLE(DFG_DEBUG_VERBOSE)
330 printf(" @%u -> ValueToDouble", nodeIndex);
332 m_graph[nodeIndex].op = ValueToDouble;
336 void fixupNode(Node& node)
338 if (!node.shouldGenerate())
341 NodeType op = node.op;
343 #if ENABLE(DFG_DEBUG_VERBOSE)
344 printf(" %s[%u]: ", Graph::opName(op), m_compileIndex);
349 PredictedType left = m_predictions[node.child1()];
350 PredictedType right = m_predictions[node.child2()];
352 if (isStrongPrediction(left) && isStrongPrediction(right) && isNumberPrediction(left) && isNumberPrediction(right)) {
353 if (left & PredictDouble)
354 toDouble(node.child2());
355 if (right & PredictDouble)
356 toDouble(node.child1());
364 PredictedType left = m_predictions[node.child1()];
365 PredictedType right = m_predictions[node.child2()];
367 if (isStrongPrediction(left) && isStrongPrediction(right)) {
368 if (left & PredictDouble)
369 toDouble(node.child2());
370 if (right & PredictDouble)
371 toDouble(node.child1());
377 toDouble(node.child1());
378 toDouble(node.child2());
386 #if ENABLE(DFG_DEBUG_VERBOSE)
393 #if ENABLE(DFG_DEBUG_VERBOSE)
394 printf("Performing Fixup\n");
396 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
397 fixupNode(m_graph[m_compileIndex]);
401 JSGlobalData& m_globalData;
402 CodeBlock* m_codeBlock;
403 CodeBlock* m_profiledBlock;
405 NodeIndex m_compileIndex;
407 Vector<PredictedType, 16> m_predictions;
408 Vector<PredictedType, 16> m_uses;
410 PredictionTracker m_variableUses;
412 #if ENABLE(DFG_DEBUG_VERBOSE)
419 void propagate(Graph& graph, JSGlobalData* globalData, CodeBlock* codeBlock)
422 CodeBlock* profiledBlock = codeBlock->alternative();
423 ASSERT(profiledBlock);
425 Propagator propagator(graph, *globalData, codeBlock, profiledBlock);
426 propagator.fixpoint();
428 #if ENABLE(DFG_DEBUG_VERBOSE)
429 graph.dump(codeBlock);
433 } } // namespace JSC::DFG
435 #endif // ENABLE(DFG_JIT) && ENABLE(DYNAMIC_OPTIMIZATION)