2 * Copyright (C) 2011, 2012, 2013, 2014 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 "JSCInlines.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
);
61 propagateToFixpoint();
63 m_pass
= RareCasePass
;
64 propagateToFixpoint();
66 m_pass
= DoubleVotingPass
;
69 doRoundOfDoubleVoting();
80 void propagateToFixpoint()
85 // Forward propagation is near-optimal for both topologically-sorted and
91 // Backward propagation reduces the likelihood that pathological code will
92 // cause slowness. Loops (especially nested ones) resemble backward flow.
93 // This pass captures two cases: (1) it detects if the forward fixpoint
94 // found a sound solution and (2) short-circuits backward flow.
100 bool setPrediction(SpeculatedType prediction
)
102 ASSERT(m_currentNode
->hasResult());
104 // setPrediction() is used when we know that there is no way that we can change
105 // our minds about what the prediction is going to be. There is no semantic
106 // difference between setPrediction() and mergeSpeculation() other than the
107 // increased checking to validate this property.
108 ASSERT(m_currentNode
->prediction() == SpecNone
|| m_currentNode
->prediction() == prediction
);
110 return m_currentNode
->predict(prediction
);
113 bool mergePrediction(SpeculatedType prediction
)
115 ASSERT(m_currentNode
->hasResult());
117 return m_currentNode
->predict(prediction
);
120 SpeculatedType
speculatedDoubleTypeForPrediction(SpeculatedType value
)
122 SpeculatedType result
= SpecDoubleReal
;
123 if (value
& SpecDoubleImpureNaN
)
124 result
|= SpecDoubleImpureNaN
;
125 if (value
& SpecDoublePureNaN
)
126 result
|= SpecDoublePureNaN
;
127 if (!isFullNumberOrBooleanSpeculation(value
))
128 result
|= SpecDoublePureNaN
;
132 SpeculatedType
speculatedDoubleTypeForPredictions(SpeculatedType left
, SpeculatedType right
)
134 return speculatedDoubleTypeForPrediction(mergeSpeculations(left
, right
));
137 void propagate(Node
* node
)
139 NodeType op
= node
->op();
141 bool changed
= false;
145 case WeakJSConstant
: {
146 SpeculatedType type
= speculationFromValue(m_graph
.valueOfJSConstant(node
));
147 if (type
== SpecInt52AsDouble
&& enableInt52())
149 changed
|= setPrediction(type
);
154 VariableAccessData
* variable
= node
->variableAccessData();
155 SpeculatedType prediction
= variable
->prediction();
156 if (!variable
->couldRepresentInt52() && (prediction
& SpecInt52
))
157 prediction
= (prediction
| SpecInt52AsDouble
) & ~SpecInt52
;
159 changed
|= mergePrediction(prediction
);
164 VariableAccessData
* variableAccessData
= node
->variableAccessData();
165 changed
|= variableAccessData
->predict(node
->child1()->prediction());
176 changed
|= setPrediction(SpecInt32
);
186 case GetMyArgumentByValSafe
:
188 case MultiGetByOffset
:
192 case GetClosureVar
: {
193 changed
|= setPrediction(node
->getHeapPrediction());
197 case StringCharCodeAt
: {
198 changed
|= setPrediction(SpecInt32
);
202 case UInt32ToNumber
: {
203 // FIXME: Support Int52.
204 // https://bugs.webkit.org/show_bug.cgi?id=125704
205 if (node
->canSpeculateInt32(m_pass
))
206 changed
|= mergePrediction(SpecInt32
);
208 changed
|= mergePrediction(SpecBytecodeNumber
);
213 SpeculatedType left
= node
->child1()->prediction();
214 SpeculatedType right
= node
->child2()->prediction();
217 if (isFullNumberOrBooleanSpeculationExpectingDefined(left
)
218 && isFullNumberOrBooleanSpeculationExpectingDefined(right
)) {
219 if (m_graph
.addSpeculationMode(node
, m_pass
) != DontSpeculateInt32
)
220 changed
|= mergePrediction(SpecInt32
);
221 else if (m_graph
.addShouldSpeculateMachineInt(node
))
222 changed
|= mergePrediction(SpecInt52
);
224 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
226 !(left
& (SpecFullNumber
| SpecBoolean
))
227 || !(right
& (SpecFullNumber
| SpecBoolean
))) {
228 // left or right is definitely something other than a number.
229 changed
|= mergePrediction(SpecString
);
231 changed
|= mergePrediction(SpecString
| SpecInt32
| SpecBytecodeDouble
);
237 SpeculatedType left
= node
->child1()->prediction();
238 SpeculatedType right
= node
->child2()->prediction();
241 if (m_graph
.addSpeculationMode(node
, m_pass
) != DontSpeculateInt32
)
242 changed
|= mergePrediction(SpecInt32
);
243 else if (m_graph
.addShouldSpeculateMachineInt(node
))
244 changed
|= mergePrediction(SpecInt52
);
246 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
252 SpeculatedType left
= node
->child1()->prediction();
253 SpeculatedType right
= node
->child2()->prediction();
256 if (m_graph
.addSpeculationMode(node
, m_pass
) != DontSpeculateInt32
)
257 changed
|= mergePrediction(SpecInt32
);
258 else if (m_graph
.addShouldSpeculateMachineInt(node
))
259 changed
|= mergePrediction(SpecInt52
);
261 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
267 if (node
->child1()->prediction()) {
268 if (m_graph
.negateShouldSpeculateInt32(node
, m_pass
))
269 changed
|= mergePrediction(SpecInt32
);
270 else if (m_graph
.negateShouldSpeculateMachineInt(node
, m_pass
))
271 changed
|= mergePrediction(SpecInt52
);
273 changed
|= mergePrediction(speculatedDoubleTypeForPrediction(node
->child1()->prediction()));
279 SpeculatedType left
= node
->child1()->prediction();
280 SpeculatedType right
= node
->child2()->prediction();
283 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node())
284 && node
->canSpeculateInt32(m_pass
))
285 changed
|= mergePrediction(SpecInt32
);
287 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
293 SpeculatedType left
= node
->child1()->prediction();
294 SpeculatedType right
= node
->child2()->prediction();
297 if (m_graph
.mulShouldSpeculateInt32(node
, m_pass
))
298 changed
|= mergePrediction(SpecInt32
);
299 else if (m_graph
.mulShouldSpeculateMachineInt(node
, m_pass
))
300 changed
|= mergePrediction(SpecInt52
);
302 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
308 SpeculatedType left
= node
->child1()->prediction();
309 SpeculatedType right
= node
->child2()->prediction();
312 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node())
313 && node
->canSpeculateInt32(m_pass
))
314 changed
|= mergePrediction(SpecInt32
);
316 changed
|= mergePrediction(SpecBytecodeDouble
);
322 SpeculatedType left
= node
->child1()->prediction();
323 SpeculatedType right
= node
->child2()->prediction();
326 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node())
327 && node
->canSpeculateInt32(m_pass
))
328 changed
|= mergePrediction(SpecInt32
);
330 changed
|= mergePrediction(SpecBytecodeDouble
);
339 changed
|= setPrediction(SpecBytecodeDouble
);
344 SpeculatedType child
= node
->child1()->prediction();
345 if (isInt32OrBooleanSpeculationForArithmetic(child
)
346 && node
->canSpeculateInt32(m_pass
))
347 changed
|= mergePrediction(SpecInt32
);
349 changed
|= mergePrediction(speculatedDoubleTypeForPrediction(child
));
357 case CompareGreaterEq
:
359 case CompareEqConstant
:
360 case CompareStrictEq
:
368 changed
|= setPrediction(SpecBoolean
);
373 changed
|= setPrediction(SpecString
);
378 if (!node
->child1()->prediction())
381 ArrayMode arrayMode
= node
->arrayMode().refine(
383 node
->child1()->prediction(),
384 node
->child2()->prediction(),
385 SpecNone
, node
->flags());
387 switch (arrayMode
.type()) {
389 if (arrayMode
.isOutOfBounds())
390 changed
|= mergePrediction(node
->getHeapPrediction() | SpecDoubleReal
);
392 changed
|= mergePrediction(SpecDoubleReal
);
394 case Array::Float32Array
:
395 case Array::Float64Array
:
396 changed
|= mergePrediction(SpecFullDouble
);
398 case Array::Uint32Array
:
399 if (isInt32Speculation(node
->getHeapPrediction()))
400 changed
|= mergePrediction(SpecInt32
);
401 else if (enableInt52())
402 changed
|= mergePrediction(SpecMachineInt
);
404 changed
|= mergePrediction(SpecInt32
| SpecInt52AsDouble
);
407 changed
|= mergePrediction(node
->getHeapPrediction());
413 case GetMyArgumentsLengthSafe
: {
414 changed
|= setPrediction(SpecInt32
);
418 case GetClosureRegisters
:
420 case GetIndexedPropertyStorage
:
421 case AllocatePropertyStorage
:
422 case ReallocatePropertyStorage
: {
423 changed
|= setPrediction(SpecOther
);
428 SpeculatedType prediction
= node
->child1()->prediction();
430 if (prediction
& ~SpecObject
) {
431 prediction
&= SpecObject
;
432 prediction
= mergeSpeculations(prediction
, SpecObjectOther
);
434 changed
|= mergePrediction(prediction
);
442 changed
|= setPrediction(SpecObjectOther
);
447 changed
|= setPrediction(SpecFunction
);
453 changed
|= setPrediction(SpecFinalObject
);
458 case NewArrayWithSize
:
459 case NewArrayBuffer
: {
460 changed
|= setPrediction(SpecArray
);
464 case NewTypedArray
: {
465 changed
|= setPrediction(speculationFromTypedArrayType(node
->typedArrayType()));
470 case CreateActivation
: {
471 changed
|= setPrediction(SpecObjectOther
);
475 case StringFromCharCode
: {
476 changed
|= setPrediction(SpecString
);
477 changed
|= node
->child1()->mergeFlags(NodeBytecodeUsesAsNumber
| NodeBytecodeUsesAsInt
);
483 changed
|= setPrediction(SpecString
);
488 SpeculatedType child
= node
->child1()->prediction();
490 changed
|= mergePrediction(resultOfToPrimitive(child
));
494 case NewStringObject
: {
495 changed
|= setPrediction(SpecStringObject
);
499 case CreateArguments
: {
500 changed
|= setPrediction(SpecArguments
);
505 SpeculatedType child
= node
->child1()->prediction();
506 if (child
& SpecEmpty
)
507 changed
|= mergePrediction((child
& ~SpecEmpty
) | SpecFunction
);
509 changed
|= mergePrediction(child
);
513 case NewFunctionNoCheck
:
514 case NewFunctionExpression
: {
515 changed
|= setPrediction(SpecFunction
);
520 RELEASE_ASSERT(enableInt52());
521 changed
|= setPrediction(SpecMachineInt
);
527 case GetTypedArrayByteOffset
:
529 case GetLocalUnlinked
:
530 case GetMyArgumentsLength
:
531 case GetMyArgumentByVal
:
532 case PhantomPutStructure
:
533 case PhantomArguments
:
536 case ArrayifyToStructure
:
537 case CheckTierUpInLoop
:
538 case CheckTierUpAtReturn
:
539 case CheckTierUpAndOSREnter
:
540 case InvalidationPoint
:
550 case BooleanToNumber
: {
551 // This node should never be visible at this stage of compilation. It is
552 // inserted by fixup(), which follows this phase.
553 RELEASE_ASSERT_NOT_REACHED();
558 // Phis should not be visible here since we're iterating the all-but-Phi's
559 // part of basic blocks.
560 RELEASE_ASSERT_NOT_REACHED();
565 // These don't get inserted until we go into SSA.
566 RELEASE_ASSERT_NOT_REACHED();
570 changed
|= setPrediction(SpecObjectOther
);
574 changed
|= setPrediction(SpecBoolean
);
578 // These get ignored because they don't return anything.
580 case StoreBarrierWithNullCheck
:
590 case MultiPutByOffset
:
595 case ProfileWillCall
:
597 case CheckHasInstance
:
598 case ThrowReferenceError
:
602 case CheckExecutable
:
603 case StructureTransitionWatchpoint
:
606 case TearOffActivation
:
607 case TearOffArguments
:
608 case CheckArgumentsNotCreated
:
609 case VariableWatchpoint
:
610 case VarInjectionWatchpoint
:
611 case AllocationProfileWatchpoint
:
615 case CheckWatchdogTimer
:
619 case FunctionReentryWatchpoint
:
620 case TypedArrayWatchpoint
:
621 case ConstantStoragePointer
:
626 // This gets ignored because it already has a prediction.
627 case ExtractOSREntryLocal
:
630 // These gets ignored because it doesn't do anything.
637 RELEASE_ASSERT_NOT_REACHED();
645 m_changed
|= changed
;
648 void propagateForward()
650 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
651 BasicBlock
* block
= m_graph
.block(blockIndex
);
654 ASSERT(block
->isReachable
);
655 for (unsigned i
= 0; i
< block
->size(); ++i
) {
656 m_currentNode
= block
->at(i
);
657 propagate(m_currentNode
);
662 void propagateBackward()
664 for (BlockIndex blockIndex
= m_graph
.numBlocks(); blockIndex
--;) {
665 BasicBlock
* block
= m_graph
.block(blockIndex
);
668 ASSERT(block
->isReachable
);
669 for (unsigned i
= block
->size(); i
--;) {
670 m_currentNode
= block
->at(i
);
671 propagate(m_currentNode
);
676 void doDoubleVoting(Node
* node
, float weight
)
678 // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate
679 // that we actually don't know they weight. Assume that they execute once. This turns
680 // out to be an OK assumption since the pre-header doesn't have any meaningful code.
681 if (weight
!= weight
)
684 switch (node
->op()) {
688 SpeculatedType left
= node
->child1()->prediction();
689 SpeculatedType right
= node
->child2()->prediction();
693 if (isFullNumberSpeculation(left
)
694 && isFullNumberSpeculation(right
)
695 && !m_graph
.addShouldSpeculateInt32(node
, m_pass
)
696 && !m_graph
.addShouldSpeculateMachineInt(node
))
701 m_graph
.voteNode(node
->child1(), ballot
, weight
);
702 m_graph
.voteNode(node
->child2(), ballot
, weight
);
707 SpeculatedType left
= node
->child1()->prediction();
708 SpeculatedType right
= node
->child2()->prediction();
712 if (isFullNumberSpeculation(left
)
713 && isFullNumberSpeculation(right
)
714 && !m_graph
.mulShouldSpeculateInt32(node
, m_pass
)
715 && !m_graph
.mulShouldSpeculateMachineInt(node
, m_pass
))
720 m_graph
.voteNode(node
->child1(), ballot
, weight
);
721 m_graph
.voteNode(node
->child2(), ballot
, weight
);
729 SpeculatedType left
= node
->child1()->prediction();
730 SpeculatedType right
= node
->child2()->prediction();
734 if (isFullNumberSpeculation(left
)
735 && isFullNumberSpeculation(right
)
736 && !(Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node()) && node
->canSpeculateInt32(m_pass
)))
741 m_graph
.voteNode(node
->child1(), ballot
, weight
);
742 m_graph
.voteNode(node
->child2(), ballot
, weight
);
748 if (node
->child1()->shouldSpeculateNumber()
749 && !(node
->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node
->canSpeculateInt32(m_pass
)))
754 m_graph
.voteNode(node
->child1(), ballot
, weight
);
760 if (node
->child1()->shouldSpeculateNumber())
761 m_graph
.voteNode(node
->child1(), VoteDouble
, weight
);
763 m_graph
.voteNode(node
->child1(), VoteValue
, weight
);
767 SpeculatedType prediction
= node
->child1()->prediction();
768 if (isDoubleSpeculation(prediction
))
769 node
->variableAccessData()->vote(VoteDouble
, weight
);
771 !isFullNumberSpeculation(prediction
)
772 || isInt32Speculation(prediction
) || isMachineIntSpeculation(prediction
))
773 node
->variableAccessData()->vote(VoteValue
, weight
);
779 case PutByValAlias
: {
780 Edge child1
= m_graph
.varArgChild(node
, 0);
781 Edge child2
= m_graph
.varArgChild(node
, 1);
782 Edge child3
= m_graph
.varArgChild(node
, 2);
783 m_graph
.voteNode(child1
, VoteValue
, weight
);
784 m_graph
.voteNode(child2
, VoteValue
, weight
);
785 switch (node
->arrayMode().type()) {
787 m_graph
.voteNode(child3
, VoteDouble
, weight
);
790 m_graph
.voteNode(child3
, VoteValue
, weight
);
797 // Ignore these since they have no effect on in-DFG execution.
801 m_graph
.voteChildren(node
, VoteValue
, weight
);
806 void doRoundOfDoubleVoting()
808 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
)
809 m_graph
.m_variableAccessData
[i
].find()->clearVotes();
810 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
811 BasicBlock
* block
= m_graph
.block(blockIndex
);
814 ASSERT(block
->isReachable
);
815 for (unsigned i
= 0; i
< block
->size(); ++i
) {
816 m_currentNode
= block
->at(i
);
817 doDoubleVoting(m_currentNode
, block
->executionCount
);
820 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
821 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
822 if (!variableAccessData
->isRoot())
824 m_changed
|= variableAccessData
->tallyVotesForShouldUseDoubleFormat();
826 for (unsigned i
= 0; i
< m_graph
.m_argumentPositions
.size(); ++i
)
827 m_changed
|= m_graph
.m_argumentPositions
[i
].mergeArgumentPredictionAwareness();
828 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
829 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
830 if (!variableAccessData
->isRoot())
832 m_changed
|= variableAccessData
->makePredictionForDoubleFormat();
838 PredictionPass m_pass
; // We use different logic for considering predictions depending on how far along we are in propagation.
841 bool performPredictionPropagation(Graph
& graph
)
843 SamplingRegion
samplingRegion("DFG Prediction Propagation Phase");
844 return runPhase
<PredictionPropagationPhase
>(graph
);
847 } } // namespace JSC::DFG
849 #endif // ENABLE(DFG_JIT)