2 * Copyright (C) 2011, 2012 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 "DFGPredictionPropagationPhase.h"
34 namespace JSC
{ namespace DFG
{
36 class PredictionPropagationPhase
: public Phase
{
38 PredictionPropagationPhase(Graph
& graph
)
39 : Phase(graph
, "prediction propagation")
45 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
48 // 1) propagate predictions
53 // Forward propagation is near-optimal for both topologically-sorted and
59 // Backward propagation reduces the likelihood that pathological code will
60 // cause slowness. Loops (especially nested ones) resemble backward flow.
61 // This pass captures two cases: (1) it detects if the forward fixpoint
62 // found a sound solution and (2) short-circuits backward flow.
67 // 2) repropagate predictions while doing double voting.
71 doRoundOfDoubleVoting();
77 doRoundOfDoubleVoting();
83 bool setPrediction(PredictedType prediction
)
85 ASSERT(m_graph
[m_compileIndex
].hasResult());
87 // setPrediction() is used when we know that there is no way that we can change
88 // our minds about what the prediction is going to be. There is no semantic
89 // difference between setPrediction() and mergePrediction() other than the
90 // increased checking to validate this property.
91 ASSERT(m_graph
[m_compileIndex
].prediction() == PredictNone
|| m_graph
[m_compileIndex
].prediction() == prediction
);
93 return m_graph
[m_compileIndex
].predict(prediction
);
96 bool mergePrediction(PredictedType prediction
)
98 ASSERT(m_graph
[m_compileIndex
].hasResult());
100 return m_graph
[m_compileIndex
].predict(prediction
);
103 bool isNotNegZero(NodeIndex nodeIndex
)
105 if (!m_graph
.isNumberConstant(nodeIndex
))
107 double value
= m_graph
.valueOfNumberConstant(nodeIndex
);
108 return !value
&& 1.0 / value
< 0.0;
111 bool isNotZero(NodeIndex nodeIndex
)
113 if (!m_graph
.isNumberConstant(nodeIndex
))
115 return !!m_graph
.valueOfNumberConstant(nodeIndex
);
118 void propagate(Node
& node
)
120 if (!node
.shouldGenerate())
123 NodeType op
= node
.op();
124 NodeFlags flags
= node
.flags() & NodeBackPropMask
;
126 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
127 dataLog(" %s @%u: %s ", Graph::opName(op
), m_compileIndex
, nodeFlagsAsString(flags
));
130 bool changed
= false;
134 case WeakJSConstant
: {
135 changed
|= setPrediction(predictionFromValue(m_graph
.valueOfJSConstant(m_compileIndex
)));
140 VariableAccessData
* variableAccessData
= node
.variableAccessData();
141 PredictedType prediction
= variableAccessData
->prediction();
143 changed
|= mergePrediction(prediction
);
145 changed
|= variableAccessData
->mergeFlags(flags
);
150 VariableAccessData
* variableAccessData
= node
.variableAccessData();
151 changed
|= variableAccessData
->predict(m_graph
[node
.child1()].prediction());
152 changed
|= m_graph
[node
.child1()].mergeFlags(variableAccessData
->flags());
157 // Make sure that the analysis knows that flushed locals escape.
158 VariableAccessData
* variableAccessData
= node
.variableAccessData();
159 changed
|= variableAccessData
->mergeFlags(NodeUsedAsValue
);
169 changed
|= setPrediction(PredictInt32
);
170 flags
|= NodeUsedAsInt
;
171 flags
&= ~(NodeUsedAsNumber
| NodeNeedsNegZero
);
172 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
173 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
178 changed
|= setPrediction(PredictInt32
);
179 flags
|= NodeUsedAsInt
;
180 flags
&= ~(NodeUsedAsNumber
| NodeNeedsNegZero
);
181 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
186 changed
|= mergePrediction(node
.getHeapPrediction());
187 changed
|= mergeDefaultFlags(node
);
192 changed
|= mergePrediction(node
.getHeapPrediction());
193 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
194 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsValue
);
200 changed
|= mergePrediction(node
.getHeapPrediction());
201 changed
|= mergeDefaultFlags(node
);
205 case StringCharCodeAt
: {
206 changed
|= mergePrediction(PredictInt32
);
207 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
208 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsNumber
| NodeUsedAsInt
);
213 PredictedType left
= m_graph
[node
.child1()].prediction();
214 PredictedType right
= m_graph
[node
.child2()].prediction();
217 if (isInt32Prediction(mergePredictions(left
, right
))
218 && nodeCanSpeculateInteger(node
.arithNodeFlags()))
219 changed
|= mergePrediction(PredictInt32
);
221 changed
|= mergePrediction(PredictDouble
);
224 flags
|= NodeUsedAsValue
;
225 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
226 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
230 case UInt32ToNumber
: {
231 if (nodeCanSpeculateInteger(node
.arithNodeFlags()))
232 changed
|= mergePrediction(PredictInt32
);
234 changed
|= mergePrediction(PredictNumber
);
236 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
241 PredictedType left
= m_graph
[node
.child1()].prediction();
242 PredictedType right
= m_graph
[node
.child2()].prediction();
245 if (isNumberPrediction(left
) && isNumberPrediction(right
)) {
246 if (m_graph
.addShouldSpeculateInteger(node
))
247 changed
|= mergePrediction(PredictInt32
);
249 changed
|= mergePrediction(PredictDouble
);
250 } else if (!(left
& PredictNumber
) || !(right
& PredictNumber
)) {
251 // left or right is definitely something other than a number.
252 changed
|= mergePrediction(PredictString
);
254 changed
|= mergePrediction(PredictString
| PredictInt32
| PredictDouble
);
257 if (isNotNegZero(node
.child1().index()) || isNotNegZero(node
.child2().index()))
258 flags
&= ~NodeNeedsNegZero
;
260 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
261 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
266 PredictedType left
= m_graph
[node
.child1()].prediction();
267 PredictedType right
= m_graph
[node
.child2()].prediction();
270 if (m_graph
.addShouldSpeculateInteger(node
))
271 changed
|= mergePrediction(PredictInt32
);
273 changed
|= mergePrediction(PredictDouble
);
276 if (isNotNegZero(node
.child1().index()) || isNotNegZero(node
.child2().index()))
277 flags
&= ~NodeNeedsNegZero
;
279 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
280 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
285 PredictedType left
= m_graph
[node
.child1()].prediction();
286 PredictedType right
= m_graph
[node
.child2()].prediction();
289 if (m_graph
.addShouldSpeculateInteger(node
))
290 changed
|= mergePrediction(PredictInt32
);
292 changed
|= mergePrediction(PredictDouble
);
295 if (isNotZero(node
.child1().index()) || isNotZero(node
.child2().index()))
296 flags
&= ~NodeNeedsNegZero
;
298 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
299 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
304 if (m_graph
[node
.child1()].prediction()) {
305 if (m_graph
.negateShouldSpeculateInteger(node
))
306 changed
|= mergePrediction(PredictInt32
);
308 changed
|= mergePrediction(PredictDouble
);
311 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
316 PredictedType left
= m_graph
[node
.child1()].prediction();
317 PredictedType right
= m_graph
[node
.child2()].prediction();
320 if (isInt32Prediction(mergePredictions(left
, right
))
321 && nodeCanSpeculateInteger(node
.arithNodeFlags()))
322 changed
|= mergePrediction(PredictInt32
);
324 changed
|= mergePrediction(PredictDouble
);
327 flags
|= NodeUsedAsNumber
;
328 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
329 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
335 PredictedType left
= m_graph
[node
.child1()].prediction();
336 PredictedType right
= m_graph
[node
.child2()].prediction();
339 if (isInt32Prediction(mergePredictions(left
, right
))
340 && nodeCanSpeculateInteger(node
.arithNodeFlags()))
341 changed
|= mergePrediction(PredictInt32
);
343 changed
|= mergePrediction(PredictDouble
);
346 // As soon as a multiply happens, we can easily end up in the part
347 // of the double domain where the point at which you do truncation
348 // can change the outcome. So, ArithMul always checks for overflow
349 // no matter what, and always forces its inputs to check as well.
351 flags
|= NodeUsedAsNumber
| NodeNeedsNegZero
;
352 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
353 changed
|= m_graph
[node
.child2()].mergeFlags(flags
);
358 changed
|= setPrediction(PredictDouble
);
359 changed
|= m_graph
[node
.child1()].mergeFlags(flags
| NodeUsedAsValue
);
364 PredictedType child
= m_graph
[node
.child1()].prediction();
365 if (nodeCanSpeculateInteger(node
.arithNodeFlags()))
366 changed
|= mergePrediction(child
);
368 changed
|= setPrediction(PredictDouble
);
370 flags
&= ~NodeNeedsNegZero
;
371 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
379 case CompareGreaterEq
:
381 case CompareStrictEq
:
389 changed
|= setPrediction(PredictBoolean
);
390 changed
|= mergeDefaultFlags(node
);
395 changed
|= mergePrediction(node
.getHeapPrediction());
396 changed
|= mergeDefaultFlags(node
);
401 changed
|= mergePrediction(node
.getHeapPrediction());
402 changed
|= mergeDefaultFlags(node
);
406 if (m_graph
[node
.child1()].shouldSpeculateFloat32Array()
407 || m_graph
[node
.child1()].shouldSpeculateFloat64Array())
408 changed
|= mergePrediction(PredictDouble
);
410 changed
|= mergePrediction(node
.getHeapPrediction());
412 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
413 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsNumber
| NodeUsedAsInt
);
417 case GetPropertyStorage
:
418 case GetIndexedPropertyStorage
: {
419 changed
|= setPrediction(PredictOther
);
420 changed
|= mergeDefaultFlags(node
);
425 changed
|= mergePrediction(node
.getHeapPrediction());
426 changed
|= mergeDefaultFlags(node
);
432 changed
|= mergePrediction(node
.getHeapPrediction());
433 for (unsigned childIdx
= node
.firstChild();
434 childIdx
< node
.firstChild() + node
.numChildren();
436 Edge edge
= m_graph
.m_varArgChildren
[childIdx
];
437 changed
|= m_graph
[edge
].mergeFlags(NodeUsedAsValue
);
443 PredictedType prediction
= m_graph
[node
.child1()].prediction();
445 if (prediction
& ~PredictObjectMask
) {
446 prediction
&= PredictObjectMask
;
447 prediction
= mergePredictions(prediction
, PredictObjectOther
);
449 changed
|= mergePrediction(prediction
);
451 changed
|= mergeDefaultFlags(node
);
456 changed
|= mergePrediction(node
.getHeapPrediction());
461 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
468 case ResolveBaseStrictPut
:
469 case ResolveGlobal
: {
470 PredictedType prediction
= node
.getHeapPrediction();
471 changed
|= mergePrediction(prediction
);
475 case GetScopeChain
: {
476 changed
|= setPrediction(PredictCellOther
);
481 changed
|= setPrediction(PredictFunction
);
487 changed
|= setPrediction(PredictFinalObject
);
488 changed
|= mergeDefaultFlags(node
);
493 changed
|= setPrediction(PredictArray
);
494 for (unsigned childIdx
= node
.firstChild();
495 childIdx
< node
.firstChild() + node
.numChildren();
497 Edge edge
= m_graph
.m_varArgChildren
[childIdx
];
498 changed
|= m_graph
[edge
].mergeFlags(NodeUsedAsValue
);
503 case NewArrayBuffer
: {
504 changed
|= setPrediction(PredictArray
);
509 changed
|= setPrediction(PredictObjectOther
);
514 changed
|= setPrediction(PredictString
);
515 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
516 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsNumber
| NodeUsedAsInt
);
521 changed
|= setPrediction(PredictString
);
522 for (unsigned childIdx
= node
.firstChild();
523 childIdx
< node
.firstChild() + node
.numChildren();
525 changed
|= m_graph
[m_graph
.m_varArgChildren
[childIdx
]].mergeFlags(NodeUsedAsNumber
);
530 PredictedType child
= m_graph
[node
.child1()].prediction();
532 if (isObjectPrediction(child
)) {
533 // I'd love to fold this case into the case below, but I can't, because
534 // removing PredictObjectMask from something that only has an object
535 // prediction and nothing else means we have an ill-formed PredictedType
536 // (strong predict-none). This should be killed once we remove all traces
537 // of static (aka weak) predictions.
538 changed
|= mergePrediction(PredictString
);
539 } else if (child
& PredictObjectMask
) {
540 // Objects get turned into strings. So if the input has hints of objectness,
541 // the output will have hinsts of stringiness.
542 changed
|= mergePrediction(
543 mergePredictions(child
& ~PredictObjectMask
, PredictString
));
545 changed
|= mergePrediction(child
);
547 changed
|= m_graph
[node
.child1()].mergeFlags(flags
);
551 case CreateActivation
: {
552 changed
|= setPrediction(PredictObjectOther
);
557 case NewFunctionNoCheck
:
558 case NewFunctionExpression
: {
559 changed
|= setPrediction(PredictFunction
);
565 case GetInt8ArrayLength
:
566 case GetInt16ArrayLength
:
567 case GetInt32ArrayLength
:
568 case GetUint8ArrayLength
:
569 case GetUint8ClampedArrayLength
:
570 case GetUint16ArrayLength
:
571 case GetUint32ArrayLength
:
572 case GetFloat32ArrayLength
:
573 case GetFloat64ArrayLength
:
574 case GetStringLength
:
576 case DoubleAsInt32
: {
577 // This node should never be visible at this stage of compilation. It is
578 // inserted by fixup(), which follows this phase.
579 ASSERT_NOT_REACHED();
584 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
585 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsNumber
| NodeUsedAsInt
);
586 changed
|= m_graph
[node
.child3()].mergeFlags(NodeUsedAsValue
);
592 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
597 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
598 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsValue
);
602 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
603 changed
|= m_graph
[node
.child3()].mergeFlags(NodeUsedAsValue
);
610 // These get ignored because they don't return anything.
614 case CheckHasInstance
:
615 case ThrowReferenceError
:
621 case TearOffActivation
:
623 changed
|= mergeDefaultFlags(node
);
626 // These gets ignored because it doesn't do anything.
633 ASSERT_NOT_REACHED();
637 changed
|= mergeDefaultFlags(node
);
642 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
643 dataLog("%s\n", predictionToString(m_graph
[m_compileIndex
].prediction()));
646 m_changed
|= changed
;
649 bool mergeDefaultFlags(Node
& node
)
651 bool changed
= false;
652 if (node
.flags() & NodeHasVarArgs
) {
653 for (unsigned childIdx
= node
.firstChild();
654 childIdx
< node
.firstChild() + node
.numChildren();
656 changed
|= m_graph
[m_graph
.m_varArgChildren
[childIdx
]].mergeFlags(NodeUsedAsValue
);
660 changed
|= m_graph
[node
.child1()].mergeFlags(NodeUsedAsValue
);
663 changed
|= m_graph
[node
.child2()].mergeFlags(NodeUsedAsValue
);
666 changed
|= m_graph
[node
.child3()].mergeFlags(NodeUsedAsValue
);
671 void propagateForward()
673 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
674 dataLog("Propagating predictions forward [%u]\n", ++m_count
);
676 for (m_compileIndex
= 0; m_compileIndex
< m_graph
.size(); ++m_compileIndex
)
677 propagate(m_graph
[m_compileIndex
]);
680 void propagateBackward()
682 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
683 dataLog("Propagating predictions backward [%u]\n", ++m_count
);
685 for (m_compileIndex
= m_graph
.size(); m_compileIndex
-- > 0;)
686 propagate(m_graph
[m_compileIndex
]);
689 void vote(Edge nodeUse
, VariableAccessData::Ballot ballot
)
691 switch (m_graph
[nodeUse
].op()) {
694 nodeUse
= m_graph
[nodeUse
].child1();
700 if (m_graph
[nodeUse
].op() == GetLocal
)
701 m_graph
[nodeUse
].variableAccessData()->vote(ballot
);
704 void vote(Node
& node
, VariableAccessData::Ballot ballot
)
706 if (node
.flags() & NodeHasVarArgs
) {
707 for (unsigned childIdx
= node
.firstChild();
708 childIdx
< node
.firstChild() + node
.numChildren();
710 vote(m_graph
.m_varArgChildren
[childIdx
], ballot
);
716 vote(node
.child1(), ballot
);
719 vote(node
.child2(), ballot
);
722 vote(node
.child3(), ballot
);
725 void doRoundOfDoubleVoting()
727 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
728 dataLog("Voting on double uses of locals [%u]\n", m_count
);
730 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
)
731 m_graph
.m_variableAccessData
[i
].find()->clearVotes();
732 for (m_compileIndex
= 0; m_compileIndex
< m_graph
.size(); ++m_compileIndex
) {
733 Node
& node
= m_graph
[m_compileIndex
];
738 PredictedType left
= m_graph
[node
.child1()].prediction();
739 PredictedType right
= m_graph
[node
.child2()].prediction();
741 VariableAccessData::Ballot ballot
;
743 if (isNumberPrediction(left
) && isNumberPrediction(right
)
744 && !m_graph
.addShouldSpeculateInteger(node
))
745 ballot
= VariableAccessData::VoteDouble
;
747 ballot
= VariableAccessData::VoteValue
;
749 vote(node
.child1(), ballot
);
750 vote(node
.child2(), ballot
);
759 PredictedType left
= m_graph
[node
.child1()].prediction();
760 PredictedType right
= m_graph
[node
.child2()].prediction();
762 VariableAccessData::Ballot ballot
;
764 if (isNumberPrediction(left
) && isNumberPrediction(right
)
765 && !(Node::shouldSpeculateInteger(m_graph
[node
.child1()], m_graph
[node
.child1()])
766 && node
.canSpeculateInteger()))
767 ballot
= VariableAccessData::VoteDouble
;
769 ballot
= VariableAccessData::VoteValue
;
771 vote(node
.child1(), ballot
);
772 vote(node
.child2(), ballot
);
777 VariableAccessData::Ballot ballot
;
778 if (!(m_graph
[node
.child1()].shouldSpeculateInteger()
779 && node
.canSpeculateInteger()))
780 ballot
= VariableAccessData::VoteDouble
;
782 ballot
= VariableAccessData::VoteValue
;
784 vote(node
.child1(), ballot
);
788 vote(node
.child1(), VariableAccessData::VoteDouble
);
792 PredictedType prediction
= m_graph
[node
.child1()].prediction();
793 if (isDoublePrediction(prediction
))
794 node
.variableAccessData()->vote(VariableAccessData::VoteDouble
);
795 else if (!isNumberPrediction(prediction
) || isInt32Prediction(prediction
))
796 node
.variableAccessData()->vote(VariableAccessData::VoteValue
);
801 vote(node
, VariableAccessData::VoteValue
);
805 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
806 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
807 if (!variableAccessData
->isRoot())
809 if (operandIsArgument(variableAccessData
->local())
810 || m_graph
.isCaptured(variableAccessData
->local()))
812 m_changed
|= variableAccessData
->tallyVotesForShouldUseDoubleFormat();
814 for (unsigned i
= 0; i
< m_graph
.m_argumentPositions
.size(); ++i
)
815 m_changed
|= m_graph
.m_argumentPositions
[i
].mergeArgumentAwareness();
816 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
817 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
818 if (!variableAccessData
->isRoot())
820 if (operandIsArgument(variableAccessData
->local())
821 || m_graph
.isCaptured(variableAccessData
->local()))
823 m_changed
|= variableAccessData
->makePredictionForDoubleFormat();
827 NodeIndex m_compileIndex
;
830 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
835 void performPredictionPropagation(Graph
& graph
)
837 runPhase
<PredictionPropagationPhase
>(graph
);
840 } } // namespace JSC::DFG
842 #endif // ENABLE(DFG_JIT)