2 * Copyright (C) 2011-2015 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
);
60 propagateThroughArgumentPositions();
63 propagateToFixpoint();
65 m_pass
= RareCasePass
;
66 propagateToFixpoint();
68 m_pass
= DoubleVotingPass
;
71 doRoundOfDoubleVoting();
82 void propagateToFixpoint()
87 // Forward propagation is near-optimal for both topologically-sorted and
93 // Backward propagation reduces the likelihood that pathological code will
94 // cause slowness. Loops (especially nested ones) resemble backward flow.
95 // This pass captures two cases: (1) it detects if the forward fixpoint
96 // found a sound solution and (2) short-circuits backward flow.
102 bool setPrediction(SpeculatedType prediction
)
104 ASSERT(m_currentNode
->hasResult());
106 // setPrediction() is used when we know that there is no way that we can change
107 // our minds about what the prediction is going to be. There is no semantic
108 // difference between setPrediction() and mergeSpeculation() other than the
109 // increased checking to validate this property.
110 ASSERT(m_currentNode
->prediction() == SpecNone
|| m_currentNode
->prediction() == prediction
);
112 return m_currentNode
->predict(prediction
);
115 bool mergePrediction(SpeculatedType prediction
)
117 ASSERT(m_currentNode
->hasResult());
119 return m_currentNode
->predict(prediction
);
122 SpeculatedType
speculatedDoubleTypeForPrediction(SpeculatedType value
)
124 SpeculatedType result
= SpecDoubleReal
;
125 if (value
& SpecDoubleImpureNaN
)
126 result
|= SpecDoubleImpureNaN
;
127 if (value
& SpecDoublePureNaN
)
128 result
|= SpecDoublePureNaN
;
129 if (!isFullNumberOrBooleanSpeculation(value
))
130 result
|= SpecDoublePureNaN
;
134 SpeculatedType
speculatedDoubleTypeForPredictions(SpeculatedType left
, SpeculatedType right
)
136 return speculatedDoubleTypeForPrediction(mergeSpeculations(left
, right
));
139 void propagate(Node
* node
)
141 NodeType op
= node
->op();
143 bool changed
= false;
147 SpeculatedType type
= speculationFromValue(node
->asJSValue());
148 if (type
== SpecInt52AsDouble
&& enableInt52())
150 changed
|= setPrediction(type
);
153 case DoubleConstant
: {
154 SpeculatedType type
= speculationFromValue(node
->asJSValue());
155 changed
|= setPrediction(type
);
160 VariableAccessData
* variable
= node
->variableAccessData();
161 SpeculatedType prediction
= variable
->prediction();
162 if (!variable
->couldRepresentInt52() && (prediction
& SpecInt52
))
163 prediction
= (prediction
| SpecInt52AsDouble
) & ~SpecInt52
;
165 changed
|= mergePrediction(prediction
);
170 VariableAccessData
* variableAccessData
= node
->variableAccessData();
171 changed
|= variableAccessData
->predict(node
->child1()->prediction());
183 changed
|= setPrediction(SpecInt32
);
194 case MultiGetByOffset
:
199 case ConstructVarargs
:
200 case CallForwardVarargs
:
201 case ConstructForwardVarargs
:
203 case NativeConstruct
:
206 case GetFromArguments
: {
207 changed
|= setPrediction(node
->getHeapPrediction());
211 case GetGetterSetterByOffset
:
212 case GetExecutable
: {
213 changed
|= setPrediction(SpecCellOther
);
221 changed
|= setPrediction(SpecFunction
);
225 case GetArgumentCount
: {
226 changed
|= setPrediction(SpecInt32
);
230 case StringCharCodeAt
: {
231 changed
|= setPrediction(SpecInt32
);
235 case UInt32ToNumber
: {
236 // FIXME: Support Int52.
237 // https://bugs.webkit.org/show_bug.cgi?id=125704
238 if (node
->canSpeculateInt32(m_pass
))
239 changed
|= mergePrediction(SpecInt32
);
241 changed
|= mergePrediction(SpecBytecodeNumber
);
246 SpeculatedType left
= node
->child1()->prediction();
247 SpeculatedType right
= node
->child2()->prediction();
250 if (isFullNumberOrBooleanSpeculationExpectingDefined(left
)
251 && isFullNumberOrBooleanSpeculationExpectingDefined(right
)) {
252 if (m_graph
.addSpeculationMode(node
, m_pass
) != DontSpeculateInt32
)
253 changed
|= mergePrediction(SpecInt32
);
254 else if (m_graph
.addShouldSpeculateMachineInt(node
))
255 changed
|= mergePrediction(SpecInt52
);
257 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
259 !(left
& (SpecFullNumber
| SpecBoolean
))
260 || !(right
& (SpecFullNumber
| SpecBoolean
))) {
261 // left or right is definitely something other than a number.
262 changed
|= mergePrediction(SpecString
);
264 changed
|= mergePrediction(SpecString
| SpecInt32
| SpecBytecodeDouble
);
271 SpeculatedType left
= node
->child1()->prediction();
272 SpeculatedType right
= node
->child2()->prediction();
275 if (m_graph
.addSpeculationMode(node
, m_pass
) != DontSpeculateInt32
)
276 changed
|= mergePrediction(SpecInt32
);
277 else if (m_graph
.addShouldSpeculateMachineInt(node
))
278 changed
|= mergePrediction(SpecInt52
);
280 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
286 if (node
->child1()->prediction()) {
287 if (m_graph
.negateShouldSpeculateInt32(node
, m_pass
))
288 changed
|= mergePrediction(SpecInt32
);
289 else if (m_graph
.negateShouldSpeculateMachineInt(node
, m_pass
))
290 changed
|= mergePrediction(SpecInt52
);
292 changed
|= mergePrediction(speculatedDoubleTypeForPrediction(node
->child1()->prediction()));
298 SpeculatedType left
= node
->child1()->prediction();
299 SpeculatedType right
= node
->child2()->prediction();
302 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node())
303 && node
->canSpeculateInt32(m_pass
))
304 changed
|= mergePrediction(SpecInt32
);
306 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
312 SpeculatedType left
= node
->child1()->prediction();
313 SpeculatedType right
= node
->child2()->prediction();
316 if (m_graph
.mulShouldSpeculateInt32(node
, m_pass
))
317 changed
|= mergePrediction(SpecInt32
);
318 else if (m_graph
.mulShouldSpeculateMachineInt(node
, m_pass
))
319 changed
|= mergePrediction(SpecInt52
);
321 changed
|= mergePrediction(speculatedDoubleTypeForPredictions(left
, right
));
328 SpeculatedType left
= node
->child1()->prediction();
329 SpeculatedType right
= node
->child2()->prediction();
332 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node())
333 && node
->canSpeculateInt32(m_pass
))
334 changed
|= mergePrediction(SpecInt32
);
336 changed
|= mergePrediction(SpecBytecodeDouble
);
347 changed
|= setPrediction(SpecBytecodeDouble
);
352 if (isInt32OrBooleanSpeculation(node
->getHeapPrediction()) && m_graph
.roundShouldSpeculateInt32(node
, m_pass
))
353 changed
|= setPrediction(SpecInt32
);
355 changed
|= setPrediction(SpecBytecodeDouble
);
360 SpeculatedType child
= node
->child1()->prediction();
361 if (isInt32OrBooleanSpeculationForArithmetic(child
)
362 && node
->canSpeculateInt32(m_pass
))
363 changed
|= mergePrediction(SpecInt32
);
365 changed
|= mergePrediction(speculatedDoubleTypeForPrediction(child
));
373 case CompareGreaterEq
:
375 case CompareEqConstant
:
376 case CompareStrictEq
:
385 changed
|= setPrediction(SpecBoolean
);
390 changed
|= setPrediction(SpecStringIdent
);
395 if (!node
->child1()->prediction())
398 ArrayMode arrayMode
= node
->arrayMode().refine(
400 node
->child1()->prediction(),
401 node
->child2()->prediction(),
404 switch (arrayMode
.type()) {
406 if (arrayMode
.isOutOfBounds())
407 changed
|= mergePrediction(node
->getHeapPrediction() | SpecInt32
);
409 changed
|= mergePrediction(SpecInt32
);
412 if (arrayMode
.isOutOfBounds())
413 changed
|= mergePrediction(node
->getHeapPrediction() | SpecDoubleReal
);
415 changed
|= mergePrediction(SpecDoubleReal
);
417 case Array::Float32Array
:
418 case Array::Float64Array
:
419 changed
|= mergePrediction(SpecFullDouble
);
421 case Array::Uint32Array
:
422 if (isInt32SpeculationForArithmetic(node
->getHeapPrediction()))
423 changed
|= mergePrediction(SpecInt32
);
424 else if (enableInt52())
425 changed
|= mergePrediction(SpecMachineInt
);
427 changed
|= mergePrediction(SpecInt32
| SpecInt52AsDouble
);
429 case Array::Int8Array
:
430 case Array::Uint8Array
:
431 case Array::Int16Array
:
432 case Array::Uint16Array
:
433 case Array::Int32Array
:
434 changed
|= mergePrediction(SpecInt32
);
437 changed
|= mergePrediction(node
->getHeapPrediction());
444 case GetIndexedPropertyStorage
:
445 case AllocatePropertyStorage
:
446 case ReallocatePropertyStorage
: {
447 changed
|= setPrediction(SpecOther
);
452 SpeculatedType prediction
= node
->child1()->prediction();
454 if (prediction
& ~SpecObject
) {
455 prediction
&= SpecObject
;
456 prediction
= mergeSpeculations(prediction
, SpecObjectOther
);
458 changed
|= mergePrediction(prediction
);
464 changed
|= setPrediction(SpecObjectOther
);
470 changed
|= setPrediction(SpecFinalObject
);
475 case NewArrayWithSize
:
476 case NewArrayBuffer
: {
477 changed
|= setPrediction(SpecArray
);
481 case NewTypedArray
: {
482 changed
|= setPrediction(speculationFromTypedArrayType(node
->typedArrayType()));
487 case CreateActivation
: {
488 changed
|= setPrediction(SpecObjectOther
);
492 case StringFromCharCode
: {
493 changed
|= setPrediction(SpecString
);
494 changed
|= node
->child1()->mergeFlags(NodeBytecodeUsesAsNumber
| NodeBytecodeUsesAsInt
);
498 case CallStringConstructor
:
501 changed
|= setPrediction(SpecString
);
506 SpeculatedType child
= node
->child1()->prediction();
508 changed
|= mergePrediction(resultOfToPrimitive(child
));
512 case NewStringObject
: {
513 changed
|= setPrediction(SpecStringObject
);
517 case CreateDirectArguments
: {
518 changed
|= setPrediction(SpecDirectArguments
);
522 case CreateScopedArguments
: {
523 changed
|= setPrediction(SpecScopedArguments
);
527 case CreateClonedArguments
: {
528 changed
|= setPrediction(SpecObjectOther
);
533 RELEASE_ASSERT(enableInt52());
534 changed
|= setPrediction(SpecMachineInt
);
540 case GetTypedArrayByteOffset
:
542 case GetLocalUnlinked
:
545 case ArrayifyToStructure
:
546 case CheckTierUpInLoop
:
547 case CheckTierUpAtReturn
:
548 case CheckTierUpAndOSREnter
:
549 case CheckTierUpWithNestedTriggerAndOSREnter
:
550 case InvalidationPoint
:
558 case BooleanToNumber
:
559 case PhantomNewObject
:
560 case PhantomNewFunction
:
561 case PhantomCreateActivation
:
562 case PhantomDirectArguments
:
563 case PhantomClonedArguments
:
564 case GetMyArgumentByVal
:
567 case CheckStructureImmediate
:
568 case MaterializeNewObject
:
569 case MaterializeCreateActivation
:
574 // This node should never be visible at this stage of compilation. It is
575 // inserted by fixup(), which follows this phase.
576 DFG_CRASH(m_graph
, node
, "Unexpected node during prediction propagation");
581 // Phis should not be visible here since we're iterating the all-but-Phi's
582 // part of basic blocks.
583 RELEASE_ASSERT_NOT_REACHED();
587 // These don't get inserted until we go into SSA.
588 RELEASE_ASSERT_NOT_REACHED();
592 changed
|= setPrediction(SpecObjectOther
);
596 changed
|= setPrediction(SpecBoolean
);
599 case GetEnumerableLength
: {
600 changed
|= setPrediction(SpecInt32
);
603 case HasGenericProperty
:
604 case HasStructureProperty
:
605 case HasIndexedProperty
: {
606 changed
|= setPrediction(SpecBoolean
);
609 case GetPropertyEnumerator
: {
610 changed
|= setPrediction(SpecCell
);
613 case GetEnumeratorStructurePname
: {
614 changed
|= setPrediction(SpecCell
| SpecOther
);
617 case GetEnumeratorGenericPname
: {
618 changed
|= setPrediction(SpecCell
| SpecOther
);
621 case ToIndexString
: {
622 changed
|= setPrediction(SpecString
);
627 // These get ignored because they don't return anything.
638 case MultiPutByOffset
:
643 case ProfileWillCall
:
646 case ProfileControlFlow
:
647 case CheckHasInstance
:
648 case ThrowReferenceError
:
656 case VarInjectionWatchpoint
:
660 case CheckWatchdogTimer
:
664 case ConstantStoragePointer
:
670 // This gets ignored because it only pretends to produce a value.
674 // This gets ignored because it already has a prediction.
675 case ExtractOSREntryLocal
:
678 // These gets ignored because it doesn't do anything.
685 RELEASE_ASSERT_NOT_REACHED();
693 m_changed
|= changed
;
696 void propagateForward()
698 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
699 BasicBlock
* block
= m_graph
.block(blockIndex
);
702 ASSERT(block
->isReachable
);
703 for (unsigned i
= 0; i
< block
->size(); ++i
) {
704 m_currentNode
= block
->at(i
);
705 propagate(m_currentNode
);
710 void propagateBackward()
712 for (BlockIndex blockIndex
= m_graph
.numBlocks(); blockIndex
--;) {
713 BasicBlock
* block
= m_graph
.block(blockIndex
);
716 ASSERT(block
->isReachable
);
717 for (unsigned i
= block
->size(); i
--;) {
718 m_currentNode
= block
->at(i
);
719 propagate(m_currentNode
);
724 void doDoubleVoting(Node
* node
, float weight
)
726 // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate
727 // that we actually don't know they weight. Assume that they execute once. This turns
728 // out to be an OK assumption since the pre-header doesn't have any meaningful code.
729 if (weight
!= weight
)
732 switch (node
->op()) {
736 SpeculatedType left
= node
->child1()->prediction();
737 SpeculatedType right
= node
->child2()->prediction();
741 if (isFullNumberSpeculation(left
)
742 && isFullNumberSpeculation(right
)
743 && !m_graph
.addShouldSpeculateInt32(node
, m_pass
)
744 && !m_graph
.addShouldSpeculateMachineInt(node
))
749 m_graph
.voteNode(node
->child1(), ballot
, weight
);
750 m_graph
.voteNode(node
->child2(), ballot
, weight
);
755 SpeculatedType left
= node
->child1()->prediction();
756 SpeculatedType right
= node
->child2()->prediction();
760 if (isFullNumberSpeculation(left
)
761 && isFullNumberSpeculation(right
)
762 && !m_graph
.mulShouldSpeculateInt32(node
, m_pass
)
763 && !m_graph
.mulShouldSpeculateMachineInt(node
, m_pass
))
768 m_graph
.voteNode(node
->child1(), ballot
, weight
);
769 m_graph
.voteNode(node
->child2(), ballot
, weight
);
777 SpeculatedType left
= node
->child1()->prediction();
778 SpeculatedType right
= node
->child2()->prediction();
782 if (isFullNumberSpeculation(left
)
783 && isFullNumberSpeculation(right
)
784 && !(Node::shouldSpeculateInt32OrBooleanForArithmetic(node
->child1().node(), node
->child2().node()) && node
->canSpeculateInt32(m_pass
)))
789 m_graph
.voteNode(node
->child1(), ballot
, weight
);
790 m_graph
.voteNode(node
->child2(), ballot
, weight
);
796 if (node
->child1()->shouldSpeculateNumber()
797 && !(node
->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node
->canSpeculateInt32(m_pass
)))
802 m_graph
.voteNode(node
->child1(), ballot
, weight
);
809 if (node
->child1()->shouldSpeculateNumber())
810 m_graph
.voteNode(node
->child1(), VoteDouble
, weight
);
812 m_graph
.voteNode(node
->child1(), VoteValue
, weight
);
816 SpeculatedType prediction
= node
->child1()->prediction();
817 if (isDoubleSpeculation(prediction
))
818 node
->variableAccessData()->vote(VoteDouble
, weight
);
820 !isFullNumberSpeculation(prediction
)
821 || isInt32Speculation(prediction
) || isMachineIntSpeculation(prediction
))
822 node
->variableAccessData()->vote(VoteValue
, weight
);
828 case PutByValAlias
: {
829 Edge child1
= m_graph
.varArgChild(node
, 0);
830 Edge child2
= m_graph
.varArgChild(node
, 1);
831 Edge child3
= m_graph
.varArgChild(node
, 2);
832 m_graph
.voteNode(child1
, VoteValue
, weight
);
833 m_graph
.voteNode(child2
, VoteValue
, weight
);
834 switch (node
->arrayMode().type()) {
836 m_graph
.voteNode(child3
, VoteDouble
, weight
);
839 m_graph
.voteNode(child3
, VoteValue
, weight
);
846 // Ignore these since they have no effect on in-DFG execution.
850 m_graph
.voteChildren(node
, VoteValue
, weight
);
855 void doRoundOfDoubleVoting()
857 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
)
858 m_graph
.m_variableAccessData
[i
].find()->clearVotes();
859 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
860 BasicBlock
* block
= m_graph
.block(blockIndex
);
863 ASSERT(block
->isReachable
);
864 for (unsigned i
= 0; i
< block
->size(); ++i
) {
865 m_currentNode
= block
->at(i
);
866 doDoubleVoting(m_currentNode
, block
->executionCount
);
869 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
870 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
871 if (!variableAccessData
->isRoot())
873 m_changed
|= variableAccessData
->tallyVotesForShouldUseDoubleFormat();
875 propagateThroughArgumentPositions();
876 for (unsigned i
= 0; i
< m_graph
.m_variableAccessData
.size(); ++i
) {
877 VariableAccessData
* variableAccessData
= &m_graph
.m_variableAccessData
[i
];
878 if (!variableAccessData
->isRoot())
880 m_changed
|= variableAccessData
->makePredictionForDoubleFormat();
884 void propagateThroughArgumentPositions()
886 for (unsigned i
= 0; i
< m_graph
.m_argumentPositions
.size(); ++i
)
887 m_changed
|= m_graph
.m_argumentPositions
[i
].mergeArgumentPredictionAwareness();
892 PredictionPass m_pass
; // We use different logic for considering predictions depending on how far along we are in propagation.
895 bool performPredictionPropagation(Graph
& graph
)
897 SamplingRegion
samplingRegion("DFG Prediction Propagation Phase");
898 return runPhase
<PredictionPropagationPhase
>(graph
);
901 } } // namespace JSC::DFG
903 #endif // ENABLE(DFG_JIT)