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 "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 // Two stage process: first propagate predictions, then propagate while doing double voting.
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.
69 doRoundOfDoubleVoting();
75 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 void propagate(Node& node)
105 if (!node.shouldGenerate())
108 NodeType op = node.op;
110 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
111 dataLog(" %s @%u: ", Graph::opName(op), m_compileIndex);
114 bool changed = false;
118 case WeakJSConstant: {
119 changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex)));
124 PredictedType prediction = node.variableAccessData()->prediction();
126 changed |= mergePrediction(prediction);
131 changed |= node.variableAccessData()->predict(m_graph[node.child1()].prediction());
142 changed |= setPrediction(PredictInt32);
148 if (node.getHeapPrediction())
149 changed |= mergePrediction(node.getHeapPrediction());
153 case StringCharCodeAt: {
154 changed |= mergePrediction(PredictInt32);
159 PredictedType left = m_graph[node.child1()].prediction();
160 PredictedType right = m_graph[node.child2()].prediction();
163 if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
164 changed |= mergePrediction(PredictInt32);
166 changed |= mergePrediction(PredictDouble);
171 case UInt32ToNumber: {
172 if (nodeCanSpeculateInteger(node.arithNodeFlags()))
173 changed |= setPrediction(PredictInt32);
175 changed |= setPrediction(PredictNumber);
180 PredictedType left = m_graph[node.child1()].prediction();
181 PredictedType right = m_graph[node.child2()].prediction();
184 if (isNumberPrediction(left) && isNumberPrediction(right)) {
185 if (m_graph.addShouldSpeculateInteger(node))
186 changed |= mergePrediction(PredictInt32);
188 changed |= mergePrediction(PredictDouble);
189 } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
190 // left or right is definitely something other than a number.
191 changed |= mergePrediction(PredictString);
193 changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble);
200 PredictedType left = m_graph[node.child1()].prediction();
201 PredictedType right = m_graph[node.child2()].prediction();
204 if (m_graph.addShouldSpeculateInteger(node))
205 changed |= mergePrediction(PredictInt32);
207 changed |= mergePrediction(PredictDouble);
216 PredictedType left = m_graph[node.child1()].prediction();
217 PredictedType right = m_graph[node.child2()].prediction();
220 if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
221 changed |= mergePrediction(PredictInt32);
223 changed |= mergePrediction(PredictDouble);
229 changed |= setPrediction(PredictDouble);
234 PredictedType child = m_graph[node.child1()].prediction();
236 if (nodeCanSpeculateInteger(node.arithNodeFlags()))
237 changed |= mergePrediction(child);
239 changed |= setPrediction(PredictDouble);
248 case CompareGreaterEq:
250 case CompareStrictEq:
252 changed |= setPrediction(PredictBoolean);
257 if (node.getHeapPrediction())
258 changed |= mergePrediction(node.getHeapPrediction());
259 else if (codeBlock()->identifier(node.identifierNumber()) == globalData().propertyNames->length) {
260 // If there is no prediction from value profiles, check if we might be
261 // able to infer the type ourselves.
262 bool isArray = isArrayPrediction(m_graph[node.child1()].prediction());
263 bool isString = isStringPrediction(m_graph[node.child1()].prediction());
264 bool isByteArray = m_graph[node.child1()].shouldSpeculateByteArray();
265 bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array();
266 bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array();
267 bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array();
268 bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array();
269 bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray();
270 bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array();
271 bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array();
272 bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array();
273 bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array();
274 if (isArray || isString || isByteArray || isInt8Array || isInt16Array || isInt32Array || isUint8Array || isUint8ClampedArray || isUint16Array || isUint32Array || isFloat32Array || isFloat64Array)
275 changed |= mergePrediction(PredictInt32);
281 if (node.getHeapPrediction())
282 changed |= mergePrediction(node.getHeapPrediction());
286 if (m_graph[node.child1()].shouldSpeculateUint32Array() || m_graph[node.child1()].shouldSpeculateFloat32Array() || m_graph[node.child1()].shouldSpeculateFloat64Array())
287 changed |= mergePrediction(PredictDouble);
288 else if (node.getHeapPrediction())
289 changed |= mergePrediction(node.getHeapPrediction());
293 case GetPropertyStorage:
294 case GetIndexedPropertyStorage: {
295 changed |= setPrediction(PredictOther);
300 if (node.getHeapPrediction())
301 changed |= mergePrediction(node.getHeapPrediction());
307 if (node.getHeapPrediction())
308 changed |= mergePrediction(node.getHeapPrediction());
313 PredictedType prediction = m_graph[node.child1()].prediction();
315 if (prediction & ~PredictObjectMask) {
316 prediction &= PredictObjectMask;
317 prediction = mergePredictions(prediction, PredictObjectOther);
319 changed |= mergePrediction(prediction);
325 PredictedType prediction = m_graph.getGlobalVarPrediction(node.varNumber());
327 changed |= mergePrediction(prediction);
332 changed |= m_graph.predictGlobalVar(node.varNumber(), m_graph[node.child1()].prediction());
339 case ResolveBaseStrictPut:
340 case ResolveGlobal: {
341 PredictedType prediction = node.getHeapPrediction();
343 changed |= mergePrediction(prediction);
347 case GetScopeChain: {
348 changed |= setPrediction(PredictCellOther);
353 changed |= setPrediction(PredictFunction);
359 changed |= setPrediction(PredictFinalObject);
364 case NewArrayBuffer: {
365 changed |= setPrediction(PredictArray);
370 changed |= setPrediction(PredictObjectOther);
376 changed |= setPrediction(PredictString);
381 PredictedType child = m_graph[node.child1()].prediction();
383 if (isObjectPrediction(child)) {
384 // I'd love to fold this case into the case below, but I can't, because
385 // removing PredictObjectMask from something that only has an object
386 // prediction and nothing else means we have an ill-formed PredictedType
387 // (strong predict-none). This should be killed once we remove all traces
388 // of static (aka weak) predictions.
389 changed |= mergePrediction(PredictString);
390 } else if (child & PredictObjectMask) {
391 // Objects get turned into strings. So if the input has hints of objectness,
392 // the output will have hinsts of stringiness.
393 changed |= mergePrediction(mergePredictions(child & ~PredictObjectMask, PredictString));
395 changed |= mergePrediction(child);
401 case GetByteArrayLength:
402 case GetInt8ArrayLength:
403 case GetInt16ArrayLength:
404 case GetInt32ArrayLength:
405 case GetUint8ArrayLength:
406 case GetUint8ClampedArrayLength:
407 case GetUint16ArrayLength:
408 case GetUint32ArrayLength:
409 case GetFloat32ArrayLength:
410 case GetFloat64ArrayLength:
411 case GetStringLength: {
412 // This node should never be visible at this stage of compilation. It is
413 // inserted by fixup(), which follows this phase.
414 ASSERT_NOT_REACHED();
419 // These get ignored because they don't return anything.
425 case CheckHasInstance:
429 case ThrowReferenceError:
442 // These gets ignored because it doesn't do anything.
453 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
454 dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction()));
457 m_changed |= changed;
460 void propagateForward()
462 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
463 dataLog("Propagating predictions forward [%u]\n", ++m_count);
465 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
466 propagate(m_graph[m_compileIndex]);
469 void propagateBackward()
471 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
472 dataLog("Propagating predictions backward [%u]\n", ++m_count);
474 for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
475 propagate(m_graph[m_compileIndex]);
478 void vote(NodeUse nodeUse, VariableAccessData::Ballot ballot)
480 switch (m_graph[nodeUse].op) {
483 nodeUse = m_graph[nodeUse].child1();
489 if (m_graph[nodeUse].op == GetLocal)
490 m_graph[nodeUse].variableAccessData()->vote(ballot);
493 void vote(Node& node, VariableAccessData::Ballot ballot)
495 if (node.op & NodeHasVarArgs) {
496 for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
497 vote(m_graph.m_varArgChildren[childIdx], ballot);
503 vote(node.child1(), ballot);
506 vote(node.child2(), ballot);
509 vote(node.child3(), ballot);
512 void doRoundOfDoubleVoting()
514 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
515 dataLog("Voting on double uses of locals [%u]\n", m_count);
517 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
518 m_graph.m_variableAccessData[i].find()->clearVotes();
519 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex) {
520 Node& node = m_graph[m_compileIndex];
525 PredictedType left = m_graph[node.child1()].prediction();
526 PredictedType right = m_graph[node.child2()].prediction();
528 VariableAccessData::Ballot ballot;
530 if (isNumberPrediction(left) && isNumberPrediction(right)
531 && !m_graph.addShouldSpeculateInteger(node))
532 ballot = VariableAccessData::VoteDouble;
534 ballot = VariableAccessData::VoteValue;
536 vote(node.child1(), ballot);
537 vote(node.child2(), ballot);
546 PredictedType left = m_graph[node.child1()].prediction();
547 PredictedType right = m_graph[node.child2()].prediction();
549 VariableAccessData::Ballot ballot;
551 if (isNumberPrediction(left) && isNumberPrediction(right) && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()]) && node.canSpeculateInteger()))
552 ballot = VariableAccessData::VoteDouble;
554 ballot = VariableAccessData::VoteValue;
556 vote(node.child1(), ballot);
557 vote(node.child2(), ballot);
562 VariableAccessData::Ballot ballot;
563 if (!(m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()))
564 ballot = VariableAccessData::VoteDouble;
566 ballot = VariableAccessData::VoteValue;
568 vote(node.child1(), ballot);
572 vote(node.child1(), VariableAccessData::VoteDouble);
576 PredictedType prediction = m_graph[node.child1()].prediction();
577 if (isDoublePrediction(prediction))
578 node.variableAccessData()->vote(VariableAccessData::VoteDouble);
579 else if (!isNumberPrediction(prediction) || isInt32Prediction(prediction))
580 node.variableAccessData()->vote(VariableAccessData::VoteValue);
585 vote(node, VariableAccessData::VoteValue);
589 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
590 m_changed |= m_graph.m_variableAccessData[i].find()->tallyVotesForShouldUseDoubleFormat();
593 void fixupNode(Node& node)
595 if (!node.shouldGenerate())
598 NodeType op = node.op;
600 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
601 dataLog(" %s @%u: ", Graph::opName(op), m_compileIndex);
606 if (!isInt32Prediction(m_graph[m_compileIndex].prediction()))
608 if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length)
610 bool isArray = isArrayPrediction(m_graph[node.child1()].prediction());
611 bool isString = isStringPrediction(m_graph[node.child1()].prediction());
612 bool isByteArray = m_graph[node.child1()].shouldSpeculateByteArray();
613 bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array();
614 bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array();
615 bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array();
616 bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array();
617 bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray();
618 bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array();
619 bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array();
620 bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array();
621 bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array();
622 if (!isArray && !isString && !isByteArray && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint8ClampedArray && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array)
625 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
626 dataLog(" @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength");
629 node.op = GetArrayLength;
631 node.op = GetStringLength;
632 else if (isByteArray)
633 node.op = GetByteArrayLength;
634 else if (isInt8Array)
635 node.op = GetInt8ArrayLength;
636 else if (isInt16Array)
637 node.op = GetInt16ArrayLength;
638 else if (isInt32Array)
639 node.op = GetInt32ArrayLength;
640 else if (isUint8Array)
641 node.op = GetUint8ArrayLength;
642 else if (isUint8ClampedArray)
643 node.op = GetUint8ClampedArrayLength;
644 else if (isUint16Array)
645 node.op = GetUint16ArrayLength;
646 else if (isUint32Array)
647 node.op = GetUint32ArrayLength;
648 else if (isFloat32Array)
649 node.op = GetFloat32ArrayLength;
650 else if (isFloat64Array)
651 node.op = GetFloat64ArrayLength;
653 ASSERT_NOT_REACHED();
654 m_graph.deref(m_compileIndex); // No longer MustGenerate
657 case GetIndexedPropertyStorage: {
658 PredictedType basePrediction = m_graph[node.child2()].prediction();
659 if (!(basePrediction & PredictInt32) && basePrediction) {
661 m_graph.clearAndDerefChild1(node);
662 m_graph.clearAndDerefChild2(node);
663 m_graph.clearAndDerefChild3(node);
670 case StringCharCodeAt: {
671 if (!!node.child3() && m_graph[node.child3()].op == Nop)
672 node.children.child3() = NodeUse();
679 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
686 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
687 dataLog("Performing Fixup\n");
689 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
690 fixupNode(m_graph[m_compileIndex]);
693 NodeIndex m_compileIndex;
696 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
701 void performPredictionPropagation(Graph& graph)
703 runPhase<PredictionPropagationPhase>(graph);
706 } } // namespace JSC::DFG
708 #endif // ENABLE(DFG_JIT)