2 * Copyright (C) 2011, 2012, 2013 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"
33 #include "Operations.h"
35 namespace JSC
{ namespace DFG
{
37 SpeculatedType
resultOfToPrimitive(SpeculatedType type
)
39 if (type
& SpecObject
) {
40 // Objects get turned into strings. So if the input has hints of objectness,
41 // the output will have hinsts of stringiness.
42 return mergeSpeculations(type
& ~SpecObject
, SpecString
);
48 class PredictionPropagationPhase
: public Phase
{
50 PredictionPropagationPhase(Graph
& graph
)
51 : Phase(graph
, "prediction propagation")
57 ASSERT(m_graph
.m_form
== ThreadedCPS
);
58 ASSERT(m_graph
.m_unificationState
== GloballyUnified
);
60 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
63 // 1) propagate predictions
68 // Forward propagation is near-optimal for both topologically-sorted and
74 // Backward propagation reduces the likelihood that pathological code will
75 // cause slowness. Loops (especially nested ones) resemble backward flow.
76 // This pass captures two cases: (1) it detects if the forward fixpoint
77 // found a sound solution and (2) short-circuits backward flow.
82 // 2) repropagate predictions while doing double voting.
86 doRoundOfDoubleVoting();
97 bool setPrediction(SpeculatedType prediction
)
99 ASSERT(m_currentNode
->hasResult());
101 // setPrediction() is used when we know that there is no way that we can change
102 // our minds about what the prediction is going to be. There is no semantic
103 // difference between setPrediction() and mergeSpeculation() other than the
104 // increased checking to validate this property.
105 ASSERT(m_currentNode
->prediction() == SpecNone
|| m_currentNode
->prediction() == prediction
);
107 return m_currentNode
->predict(prediction
);
110 bool mergePrediction(SpeculatedType prediction
)
112 ASSERT(m_currentNode
->hasResult());
114 return m_currentNode
->predict(prediction
);
117 SpeculatedType
speculatedDoubleTypeForPrediction(SpeculatedType value
)
119 if (!isNumberSpeculation(value
))
121 if (value
& SpecDoubleNaN
)
123 return SpecDoubleReal
;
126 SpeculatedType
speculatedDoubleTypeForPredictions(SpeculatedType left
, SpeculatedType right
)
128 return speculatedDoubleTypeForPrediction(mergeSpeculations(left
, right
));
131 void propagate(Node
* node
)
133 NodeType op
= node
->op();
135 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
136 dataLog(" ", Graph::opName(op
), " ", m_currentNode
, ": ", NodeFlagsDump(node
->flags()), " ");
139 bool changed
= false;
143 case WeakJSConstant
: {
144 changed
|= setPrediction(speculationFromValue(m_graph
.valueOfJSConstant(node
)));
149 VariableAccessData
* variableAccessData
= node
->variableAccessData();
150 SpeculatedType prediction
= variableAccessData
->prediction();
152 changed
|= mergePrediction(prediction
);
157 VariableAccessData
* variableAccessData
= node
->variableAccessData();
158 changed
|= variableAccessData
->predict(node
->child1()->prediction());
169 changed
|= setPrediction(SpecInt32
);
174 changed
|= setPrediction(SpecInt32
);
184 case GetMyArgumentByValSafe
:
192 case ResolveBaseStrictPut
:
193 case ResolveGlobal
: {
194 changed
|= setPrediction(node
->getHeapPrediction());
198 case StringCharCodeAt
: {
199 changed
|= setPrediction(SpecInt32
);
203 case UInt32ToNumber
: {
204 if (nodeCanSpeculateInteger(node
->arithNodeFlags()))
205 changed
|= mergePrediction(SpecInt32
);
207 changed
|= mergePrediction(SpecNumber
);
212 SpeculatedType left
= node
->child1()->prediction();
213 SpeculatedType right
= node
->child2()->prediction();
216 if (isNumberSpeculationExpectingDefined(left
) && isNumberSpeculationExpectingDefined(right
)) {
217 if (m_graph
.addSpeculationMode(node
) != DontSpeculateInteger
)
218 changed
|= mergePrediction(SpecInt32
);
220 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
221 } else if (!(left
& SpecNumber
) || !(right
& SpecNumber
)) {
222 // left or right is definitely something other than a number.
223 changed
|= mergePrediction(SpecString
);
225 changed
|= mergePrediction(SpecString
| SpecInt32
| SpecDouble
);
231 SpeculatedType left
= node
->child1()->prediction();
232 SpeculatedType right
= node
->child2()->prediction();
235 if (m_graph
.addSpeculationMode(node
) != DontSpeculateInteger
)
236 changed
|= mergePrediction(SpecInt32
);
238 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
244 SpeculatedType left
= node
->child1()->prediction();
245 SpeculatedType right
= node
->child2()->prediction();
248 if (m_graph
.addSpeculationMode(node
) != DontSpeculateInteger
)
249 changed
|= mergePrediction(SpecInt32
);
251 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
257 if (node
->child1()->prediction()) {
258 if (m_graph
.negateShouldSpeculateInteger(node
))
259 changed
|= mergePrediction(SpecInt32
);
261 changed
|= mergePrediction(speculatedDoubleTypeForPrediction(node
->child1()->prediction()));
267 SpeculatedType left
= node
->child1()->prediction();
268 SpeculatedType right
= node
->child2()->prediction();
271 if (Node::shouldSpeculateIntegerForArithmetic(node
->child1().node(), node
->child2().node())
272 && nodeCanSpeculateInteger(node
->arithNodeFlags()))
273 changed
|= mergePrediction(SpecInt32
);
275 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
281 SpeculatedType left
= node
->child1()->prediction();
282 SpeculatedType right
= node
->child2()->prediction();
285 if (m_graph
.mulShouldSpeculateInteger(node
))
286 changed
|= mergePrediction(SpecInt32
);
288 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
294 SpeculatedType left
= node
->child1()->prediction();
295 SpeculatedType right
= node
->child2()->prediction();
298 if (Node::shouldSpeculateIntegerForArithmetic(node
->child1().node(), node
->child2().node())
299 && nodeCanSpeculateInteger(node
->arithNodeFlags()))
300 changed
|= mergePrediction(SpecInt32
);
302 changed
|= mergePrediction(SpecDouble
);
308 SpeculatedType left
= node
->child1()->prediction();
309 SpeculatedType right
= node
->child2()->prediction();
312 if (Node::shouldSpeculateIntegerForArithmetic(node
->child1().node(), node
->child2().node())
313 && nodeCanSpeculateInteger(node
->arithNodeFlags()))
314 changed
|= mergePrediction(SpecInt32
);
316 changed
|= mergePrediction(SpecDouble
);
322 changed
|= setPrediction(SpecDouble
);
327 SpeculatedType child
= node
->child1()->prediction();
328 if (isInt32SpeculationForArithmetic(child
)
329 && nodeCanSpeculateInteger(node
->arithNodeFlags()))
330 changed
|= mergePrediction(SpecInt32
);
332 changed
|= mergePrediction(speculatedDoubleTypeForPrediction(child
));
340 case CompareGreaterEq
:
342 case CompareEqConstant
:
343 case CompareStrictEq
:
344 case CompareStrictEqConstant
:
352 changed
|= setPrediction(SpecBoolean
);
357 changed
|= setPrediction(SpecString
);
362 if (node
->child1()->shouldSpeculateFloat32Array()
363 || node
->child1()->shouldSpeculateFloat64Array())
364 changed
|= mergePrediction(SpecDouble
);
366 changed
|= mergePrediction(node
->getHeapPrediction());
370 case GetMyArgumentsLengthSafe
: {
371 changed
|= setPrediction(SpecInt32
);
375 case GetScopeRegisters
:
377 case GetIndexedPropertyStorage
:
378 case AllocatePropertyStorage
:
379 case ReallocatePropertyStorage
: {
380 changed
|= setPrediction(SpecOther
);
385 SpeculatedType prediction
= node
->child1()->prediction();
387 if (prediction
& ~SpecObject
) {
388 prediction
&= SpecObject
;
389 prediction
= mergeSpeculations(prediction
, SpecObjectOther
);
391 changed
|= mergePrediction(prediction
);
399 changed
|= setPrediction(SpecObjectOther
);
404 changed
|= setPrediction(SpecFunction
);
410 changed
|= setPrediction(SpecFinalObject
);
415 case NewArrayWithSize
:
416 case NewArrayBuffer
: {
417 changed
|= setPrediction(SpecArray
);
422 case CreateActivation
: {
423 changed
|= setPrediction(SpecObjectOther
);
427 case StringFromCharCode
: {
428 changed
|= setPrediction(SpecString
);
429 changed
|= node
->child1()->mergeFlags(NodeUsedAsNumber
| NodeUsedAsInt
);
435 changed
|= setPrediction(SpecString
);
440 SpeculatedType child
= node
->child1()->prediction();
442 changed
|= mergePrediction(resultOfToPrimitive(child
));
446 case NewStringObject
: {
447 changed
|= setPrediction(SpecStringObject
);
451 case CreateArguments
: {
452 changed
|= setPrediction(SpecArguments
);
457 SpeculatedType child
= node
->child1()->prediction();
458 if (child
& SpecEmpty
)
459 changed
|= mergePrediction((child
& ~SpecEmpty
) | SpecFunction
);
461 changed
|= mergePrediction(child
);
465 case NewFunctionNoCheck
:
466 case NewFunctionExpression
: {
467 changed
|= setPrediction(SpecFunction
);
474 case ForwardInt32ToDouble
:
476 case GetLocalUnlinked
:
477 case GetMyArgumentsLength
:
478 case GetMyArgumentByVal
:
479 case PhantomPutStructure
:
480 case PhantomArguments
:
483 case ArrayifyToStructure
:
485 case MovHintAndCheck
:
487 // This node should never be visible at this stage of compilation. It is
488 // inserted by fixup(), which follows this phase.
494 // Phis should not be visible here since we're iterating the all-but-Phi's
495 // part of basic blocks.
500 changed
|= setPrediction(SpecObjectOther
);
504 changed
|= mergePrediction(node
->child1()->prediction());
508 // These get ignored because they don't return anything.
521 case CheckHasInstance
:
522 case ThrowReferenceError
:
526 case CheckExecutable
:
527 case ForwardCheckStructure
:
528 case StructureTransitionWatchpoint
:
529 case ForwardStructureTransitionWatchpoint
:
532 case TearOffActivation
:
533 case TearOffArguments
:
534 case CheckArgumentsNotCreated
:
535 case GlobalVarWatchpoint
:
537 case AllocationProfileWatchpoint
:
540 case PutGlobalVarCheck
:
541 case CheckWatchdogTimer
:
545 // These gets ignored because it doesn't do anything.
562 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
563 dataLog(SpeculationDump(node
->prediction()), "\n");
566 m_changed
|= changed
;
569 void propagateForward()
571 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
572 dataLogF("Propagating predictions forward [%u]\n", ++m_count
);
574 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
575 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
578 ASSERT(block
->isReachable
);
579 for (unsigned i
= 0; i
< block
->size(); ++i
) {
580 m_currentNode
= block
->at(i
);
581 propagate(m_currentNode
);
586 void propagateBackward()
588 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
589 dataLogF("Propagating predictions backward [%u]\n", ++m_count
);
591 for (BlockIndex blockIndex
= m_graph
.m_blocks
.size(); blockIndex
--;) {
592 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
595 ASSERT(block
->isReachable
);
596 for (unsigned i
= block
->size(); i
--;) {
597 m_currentNode
= block
->at(i
);
598 propagate(m_currentNode
);
603 void doDoubleVoting(Node
* node
)
605 switch (node
->op()) {
609 SpeculatedType left
= node
->child1()->prediction();
610 SpeculatedType right
= node
->child2()->prediction();
614 if (isNumberSpeculationExpectingDefined(left
) && isNumberSpeculationExpectingDefined(right
)
615 && !m_graph
.addShouldSpeculateInteger(node
))
620 m_graph
.voteNode(node
->child1(), ballot
);
621 m_graph
.voteNode(node
->child2(), ballot
);
626 SpeculatedType left
= node
->child1()->prediction();
627 SpeculatedType right
= node
->child2()->prediction();
631 if (isNumberSpeculation(left
) && isNumberSpeculation(right
)
632 && !m_graph
.mulShouldSpeculateInteger(node
))
637 m_graph
.voteNode(node
->child1(), ballot
);
638 m_graph
.voteNode(node
->child2(), ballot
);
646 SpeculatedType left
= node
->child1()->prediction();
647 SpeculatedType right
= node
->child2()->prediction();
651 if (isNumberSpeculation(left
) && isNumberSpeculation(right
)
652 && !(Node::shouldSpeculateIntegerForArithmetic(node
->child1().node(), node
->child2().node()) && node
->canSpeculateInteger()))
657 m_graph
.voteNode(node
->child1(), ballot
);
658 m_graph
.voteNode(node
->child2(), ballot
);
664 if (!(node
->child1()->shouldSpeculateIntegerForArithmetic() && node
->canSpeculateInteger()))
669 m_graph
.voteNode(node
->child1(), ballot
);
673 m_graph
.voteNode(node
->child1(), VoteDouble
);
677 SpeculatedType prediction
= node
->child1()->prediction();
678 if (isDoubleSpeculation(prediction
))
679 node
->variableAccessData()->vote(VoteDouble
);
680 else if (!isNumberSpeculation(prediction
) || isInt32Speculation(prediction
))
681 node
->variableAccessData()->vote(VoteValue
);
686 case PutByValAlias
: {
687 Edge child1
= m_graph
.varArgChild(node
, 0);
688 Edge child2
= m_graph
.varArgChild(node
, 1);
689 Edge child3
= m_graph
.varArgChild(node
, 2);
690 m_graph
.voteNode(child1
, VoteValue
);
691 m_graph
.voteNode(child2
, VoteValue
);
692 switch (node
->arrayMode().type()) {
694 m_graph
.voteNode(child3
, VoteDouble
);
697 m_graph
.voteNode(child3
, VoteValue
);
704 m_graph
.voteChildren(node
, VoteValue
);
709 void doRoundOfDoubleVoting()
711 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
712 dataLogF("Voting on double uses of locals [%u]\n", m_count
);
714 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
)
715 m_graph
.m_variableAccessData
[i
].find()->clearVotes();
716 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
) {
717 BasicBlock
* block
= m_graph
.m_blocks
[blockIndex
].get();
720 ASSERT(block
->isReachable
);
721 for (unsigned i
= 0; i
< block
->size(); ++i
) {
722 m_currentNode
= block
->at(i
);
723 doDoubleVoting(m_currentNode
);
726 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
727 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
728 if (!variableAccessData
->isRoot())
730 m_changed
|= variableAccessData
->tallyVotesForShouldUseDoubleFormat();
732 for (unsigned i
= 0; i
< m_graph
.m_argumentPositions
.size(); ++i
)
733 m_changed
|= m_graph
.m_argumentPositions
[i
].mergeArgumentPredictionAwareness();
734 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
735 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
736 if (!variableAccessData
->isRoot())
738 m_changed
|= variableAccessData
->makePredictionForDoubleFormat();
745 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
750 bool performPredictionPropagation(Graph
& graph
)
752 SamplingRegion
samplingRegion("DFG Prediction Propagation Phase");
753 return runPhase
<PredictionPropagationPhase
>(graph
);
756 } } // namespace JSC::DFG
758 #endif // ENABLE(DFG_JIT)