/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "DFGGraph.h"
#include "DFGPhase.h"
+#include "JSCInlines.h"
namespace JSC { namespace DFG {
+SpeculatedType resultOfToPrimitive(SpeculatedType type)
+{
+ if (type & SpecObject) {
+ // Objects get turned into strings. So if the input has hints of objectness,
+ // the output will have hinsts of stringiness.
+ return mergeSpeculations(type & ~SpecObject, SpecString);
+ }
+
+ return type;
+}
+
class PredictionPropagationPhase : public Phase {
public:
PredictionPropagationPhase(Graph& graph)
{
}
- void run()
+ bool run()
{
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- m_count = 0;
-#endif
- // 1) propagate predictions
+ ASSERT(m_graph.m_form == ThreadedCPS);
+ ASSERT(m_graph.m_unificationState == GloballyUnified);
+ m_pass = PrimaryPass;
+ propagateToFixpoint();
+
+ m_pass = RareCasePass;
+ propagateToFixpoint();
+
+ m_pass = DoubleVotingPass;
do {
m_changed = false;
-
- // Forward propagation is near-optimal for both topologically-sorted and
- // DFS-sorted code.
- propagateForward();
+ doRoundOfDoubleVoting();
if (!m_changed)
break;
-
- // Backward propagation reduces the likelihood that pathological code will
- // cause slowness. Loops (especially nested ones) resemble backward flow.
- // This pass captures two cases: (1) it detects if the forward fixpoint
- // found a sound solution and (2) short-circuits backward flow.
m_changed = false;
- propagateBackward();
+ propagateForward();
} while (m_changed);
- // 2) repropagate predictions while doing double voting.
-
+ return true;
+ }
+
+private:
+ void propagateToFixpoint()
+ {
do {
m_changed = false;
- doRoundOfDoubleVoting();
+
+ // Forward propagation is near-optimal for both topologically-sorted and
+ // DFS-sorted code.
propagateForward();
if (!m_changed)
break;
+ // Backward propagation reduces the likelihood that pathological code will
+ // cause slowness. Loops (especially nested ones) resemble backward flow.
+ // This pass captures two cases: (1) it detects if the forward fixpoint
+ // found a sound solution and (2) short-circuits backward flow.
m_changed = false;
- doRoundOfDoubleVoting();
propagateBackward();
} while (m_changed);
}
-private:
- bool setPrediction(PredictedType prediction)
+ bool setPrediction(SpeculatedType prediction)
{
- ASSERT(m_graph[m_compileIndex].hasResult());
+ ASSERT(m_currentNode->hasResult());
// setPrediction() is used when we know that there is no way that we can change
// our minds about what the prediction is going to be. There is no semantic
- // difference between setPrediction() and mergePrediction() other than the
+ // difference between setPrediction() and mergeSpeculation() other than the
// increased checking to validate this property.
- ASSERT(m_graph[m_compileIndex].prediction() == PredictNone || m_graph[m_compileIndex].prediction() == prediction);
+ ASSERT(m_currentNode->prediction() == SpecNone || m_currentNode->prediction() == prediction);
- return m_graph[m_compileIndex].predict(prediction);
+ return m_currentNode->predict(prediction);
}
- bool mergePrediction(PredictedType prediction)
+ bool mergePrediction(SpeculatedType prediction)
{
- ASSERT(m_graph[m_compileIndex].hasResult());
+ ASSERT(m_currentNode->hasResult());
- return m_graph[m_compileIndex].predict(prediction);
+ return m_currentNode->predict(prediction);
}
- bool isNotNegZero(NodeIndex nodeIndex)
+ SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value)
{
- if (!m_graph.isNumberConstant(nodeIndex))
- return false;
- double value = m_graph.valueOfNumberConstant(nodeIndex);
- return !value && 1.0 / value < 0.0;
+ SpeculatedType result = SpecDoubleReal;
+ if (value & SpecDoubleImpureNaN)
+ result |= SpecDoubleImpureNaN;
+ if (value & SpecDoublePureNaN)
+ result |= SpecDoublePureNaN;
+ if (!isFullNumberOrBooleanSpeculation(value))
+ result |= SpecDoublePureNaN;
+ return result;
}
-
- bool isNotZero(NodeIndex nodeIndex)
+
+ SpeculatedType speculatedDoubleTypeForPredictions(SpeculatedType left, SpeculatedType right)
{
- if (!m_graph.isNumberConstant(nodeIndex))
- return false;
- return !!m_graph.valueOfNumberConstant(nodeIndex);
+ return speculatedDoubleTypeForPrediction(mergeSpeculations(left, right));
}
-
- void propagate(Node& node)
+
+ void propagate(Node* node)
{
- if (!node.shouldGenerate())
- return;
-
- NodeType op = node.op();
- NodeFlags flags = node.flags() & NodeBackPropMask;
+ NodeType op = node->op();
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags));
-#endif
-
bool changed = false;
switch (op) {
case JSConstant:
case WeakJSConstant: {
- changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex)));
+ SpeculatedType type = speculationFromValue(m_graph.valueOfJSConstant(node));
+ if (type == SpecInt52AsDouble && enableInt52())
+ type = SpecInt52;
+ changed |= setPrediction(type);
break;
}
case GetLocal: {
- VariableAccessData* variableAccessData = node.variableAccessData();
- PredictedType prediction = variableAccessData->prediction();
+ VariableAccessData* variable = node->variableAccessData();
+ SpeculatedType prediction = variable->prediction();
+ if (!variable->couldRepresentInt52() && (prediction & SpecInt52))
+ prediction = (prediction | SpecInt52AsDouble) & ~SpecInt52;
if (prediction)
changed |= mergePrediction(prediction);
-
- changed |= variableAccessData->mergeFlags(flags);
break;
}
case SetLocal: {
- VariableAccessData* variableAccessData = node.variableAccessData();
- changed |= variableAccessData->predict(m_graph[node.child1()].prediction());
- changed |= m_graph[node.child1()].mergeFlags(variableAccessData->flags());
- break;
- }
-
- case Flush: {
- // Make sure that the analysis knows that flushed locals escape.
- VariableAccessData* variableAccessData = node.variableAccessData();
- changed |= variableAccessData->mergeFlags(NodeUsedAsValue);
+ VariableAccessData* variableAccessData = node->variableAccessData();
+ changed |= variableAccessData->predict(node->child1()->prediction());
break;
}
case BitXor:
case BitRShift:
case BitLShift:
- case BitURShift: {
- changed |= setPrediction(PredictInt32);
- flags |= NodeUsedAsInt;
- flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
+ case BitURShift:
+ case ArithIMul: {
+ changed |= setPrediction(SpecInt32);
break;
}
- case ValueToInt32: {
- changed |= setPrediction(PredictInt32);
- flags |= NodeUsedAsInt;
- flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
- changed |= m_graph[node.child1()].mergeFlags(flags);
- break;
- }
-
- case ArrayPop: {
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= mergeDefaultFlags(node);
- break;
- }
-
- case ArrayPush: {
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
- break;
- }
-
+ case ArrayPop:
+ case ArrayPush:
case RegExpExec:
- case RegExpTest: {
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= mergeDefaultFlags(node);
+ case RegExpTest:
+ case GetById:
+ case GetByIdFlush:
+ case GetMyArgumentByValSafe:
+ case GetByOffset:
+ case MultiGetByOffset:
+ case Call:
+ case Construct:
+ case GetGlobalVar:
+ case GetClosureVar: {
+ changed |= setPrediction(node->getHeapPrediction());
break;
}
case StringCharCodeAt: {
- changed |= mergePrediction(PredictInt32);
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= setPrediction(SpecInt32);
break;
}
- case ArithMod: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
-
- if (left && right) {
- if (isInt32Prediction(mergePredictions(left, right))
- && nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(PredictInt32);
- else
- changed |= mergePrediction(PredictDouble);
- }
-
- flags |= NodeUsedAsValue;
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
- break;
- }
-
case UInt32ToNumber: {
- if (nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(PredictInt32);
+ // FIXME: Support Int52.
+ // https://bugs.webkit.org/show_bug.cgi?id=125704
+ if (node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= mergePrediction(PredictNumber);
-
- changed |= m_graph[node.child1()].mergeFlags(flags);
+ changed |= mergePrediction(SpecBytecodeNumber);
break;
}
case ValueAdd: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
if (left && right) {
- if (isNumberPrediction(left) && isNumberPrediction(right)) {
- if (m_graph.addShouldSpeculateInteger(node))
- changed |= mergePrediction(PredictInt32);
+ if (isFullNumberOrBooleanSpeculationExpectingDefined(left)
+ && isFullNumberOrBooleanSpeculationExpectingDefined(right)) {
+ if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32)
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.addShouldSpeculateMachineInt(node))
+ changed |= mergePrediction(SpecInt52);
else
- changed |= mergePrediction(PredictDouble);
- } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ } else if (
+ !(left & (SpecFullNumber | SpecBoolean))
+ || !(right & (SpecFullNumber | SpecBoolean))) {
// left or right is definitely something other than a number.
- changed |= mergePrediction(PredictString);
+ changed |= mergePrediction(SpecString);
} else
- changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble);
+ changed |= mergePrediction(SpecString | SpecInt32 | SpecBytecodeDouble);
}
-
- if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
- flags &= ~NodeNeedsNegZero;
-
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
break;
}
case ArithAdd: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
if (left && right) {
- if (m_graph.addShouldSpeculateInteger(node))
- changed |= mergePrediction(PredictInt32);
+ if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32)
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.addShouldSpeculateMachineInt(node))
+ changed |= mergePrediction(SpecInt52);
else
- changed |= mergePrediction(PredictDouble);
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
}
-
- if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
- flags &= ~NodeNeedsNegZero;
-
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
break;
}
case ArithSub: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
if (left && right) {
- if (m_graph.addShouldSpeculateInteger(node))
- changed |= mergePrediction(PredictInt32);
+ if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32)
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.addShouldSpeculateMachineInt(node))
+ changed |= mergePrediction(SpecInt52);
else
- changed |= mergePrediction(PredictDouble);
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
}
-
- if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
- flags &= ~NodeNeedsNegZero;
-
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
break;
}
case ArithNegate:
- if (m_graph[node.child1()].prediction()) {
- if (m_graph.negateShouldSpeculateInteger(node))
- changed |= mergePrediction(PredictInt32);
+ if (node->child1()->prediction()) {
+ if (m_graph.negateShouldSpeculateInt32(node, m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.negateShouldSpeculateMachineInt(node, m_pass))
+ changed |= mergePrediction(SpecInt52);
else
- changed |= mergePrediction(PredictDouble);
+ changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction()));
}
-
- changed |= m_graph[node.child1()].mergeFlags(flags);
break;
case ArithMin:
case ArithMax: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
if (left && right) {
- if (isInt32Prediction(mergePredictions(left, right))
- && nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(PredictInt32);
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= mergePrediction(PredictDouble);
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
}
+ break;
+ }
- flags |= NodeUsedAsNumber;
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
+ case ArithMul: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (m_graph.mulShouldSpeculateInt32(node, m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+ changed |= mergePrediction(SpecInt52);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ }
break;
}
- case ArithMul:
case ArithDiv: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
if (left && right) {
- if (isInt32Prediction(mergePredictions(left, right))
- && nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(PredictInt32);
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= mergePrediction(PredictDouble);
+ changed |= mergePrediction(SpecBytecodeDouble);
}
-
- // As soon as a multiply happens, we can easily end up in the part
- // of the double domain where the point at which you do truncation
- // can change the outcome. So, ArithMul always checks for overflow
- // no matter what, and always forces its inputs to check as well.
+ break;
+ }
- flags |= NodeUsedAsNumber | NodeNeedsNegZero;
- changed |= m_graph[node.child1()].mergeFlags(flags);
- changed |= m_graph[node.child2()].mergeFlags(flags);
+ case ArithMod: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(SpecBytecodeDouble);
+ }
break;
}
- case ArithSqrt: {
- changed |= setPrediction(PredictDouble);
- changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
+ case ArithSqrt:
+ case ArithFRound:
+ case ArithSin:
+ case ArithCos: {
+ changed |= setPrediction(SpecBytecodeDouble);
break;
}
case ArithAbs: {
- PredictedType child = m_graph[node.child1()].prediction();
- if (nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(child);
+ SpeculatedType child = node->child1()->prediction();
+ if (isInt32OrBooleanSpeculationForArithmetic(child)
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= setPrediction(PredictDouble);
-
- flags &= ~NodeNeedsNegZero;
- changed |= m_graph[node.child1()].mergeFlags(flags);
+ changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
break;
}
case CompareGreater:
case CompareGreaterEq:
case CompareEq:
+ case CompareEqConstant:
case CompareStrictEq:
case InstanceOf:
case IsUndefined:
case IsString:
case IsObject:
case IsFunction: {
- changed |= setPrediction(PredictBoolean);
- changed |= mergeDefaultFlags(node);
+ changed |= setPrediction(SpecBoolean);
break;
}
-
- case GetById: {
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= mergeDefaultFlags(node);
+
+ case TypeOf: {
+ changed |= setPrediction(SpecString);
break;
}
+
+ case GetByVal: {
+ if (!node->child1()->prediction())
+ break;
- case GetByIdFlush:
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= mergeDefaultFlags(node);
- break;
+ ArrayMode arrayMode = node->arrayMode().refine(
+ m_graph, node,
+ node->child1()->prediction(),
+ node->child2()->prediction(),
+ SpecNone, node->flags());
- case GetByVal: {
- if (m_graph[node.child1()].shouldSpeculateFloat32Array()
- || m_graph[node.child1()].shouldSpeculateFloat64Array())
- changed |= mergePrediction(PredictDouble);
- else
- changed |= mergePrediction(node.getHeapPrediction());
-
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ switch (arrayMode.type()) {
+ case Array::Double:
+ if (arrayMode.isOutOfBounds())
+ changed |= mergePrediction(node->getHeapPrediction() | SpecDoubleReal);
+ else
+ changed |= mergePrediction(SpecDoubleReal);
+ break;
+ case Array::Float32Array:
+ case Array::Float64Array:
+ changed |= mergePrediction(SpecFullDouble);
+ break;
+ case Array::Uint32Array:
+ if (isInt32Speculation(node->getHeapPrediction()))
+ changed |= mergePrediction(SpecInt32);
+ else if (enableInt52())
+ changed |= mergePrediction(SpecMachineInt);
+ else
+ changed |= mergePrediction(SpecInt32 | SpecInt52AsDouble);
+ break;
+ default:
+ changed |= mergePrediction(node->getHeapPrediction());
+ break;
+ }
break;
}
- case GetPropertyStorage:
- case GetIndexedPropertyStorage: {
- changed |= setPrediction(PredictOther);
- changed |= mergeDefaultFlags(node);
+ case GetMyArgumentsLengthSafe: {
+ changed |= setPrediction(SpecInt32);
break;
}
- case GetByOffset: {
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= mergeDefaultFlags(node);
+ case GetClosureRegisters:
+ case GetButterfly:
+ case GetIndexedPropertyStorage:
+ case AllocatePropertyStorage:
+ case ReallocatePropertyStorage: {
+ changed |= setPrediction(SpecOther);
break;
}
-
- case Call:
- case Construct: {
- changed |= mergePrediction(node.getHeapPrediction());
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- ++childIdx) {
- Edge edge = m_graph.m_varArgChildren[childIdx];
- changed |= m_graph[edge].mergeFlags(NodeUsedAsValue);
- }
- break;
- }
-
- case ConvertThis: {
- PredictedType prediction = m_graph[node.child1()].prediction();
+
+ case ToThis: {
+ SpeculatedType prediction = node->child1()->prediction();
if (prediction) {
- if (prediction & ~PredictObjectMask) {
- prediction &= PredictObjectMask;
- prediction = mergePredictions(prediction, PredictObjectOther);
+ if (prediction & ~SpecObject) {
+ prediction &= SpecObject;
+ prediction = mergeSpeculations(prediction, SpecObjectOther);
}
changed |= mergePrediction(prediction);
}
- changed |= mergeDefaultFlags(node);
break;
}
- case GetGlobalVar: {
- changed |= mergePrediction(node.getHeapPrediction());
+ case GetMyScope:
+ case SkipTopScope:
+ case SkipScope: {
+ changed |= setPrediction(SpecObjectOther);
break;
}
- case PutGlobalVar: {
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+ case GetCallee: {
+ changed |= setPrediction(SpecFunction);
break;
}
- case GetScopedVar:
- case Resolve:
- case ResolveBase:
- case ResolveBaseStrictPut:
- case ResolveGlobal: {
- PredictedType prediction = node.getHeapPrediction();
- changed |= mergePrediction(prediction);
+ case CreateThis:
+ case NewObject: {
+ changed |= setPrediction(SpecFinalObject);
break;
}
- case GetScopeChain: {
- changed |= setPrediction(PredictCellOther);
+ case NewArray:
+ case NewArrayWithSize:
+ case NewArrayBuffer: {
+ changed |= setPrediction(SpecArray);
break;
}
- case GetCallee: {
- changed |= setPrediction(PredictFunction);
+ case NewTypedArray: {
+ changed |= setPrediction(speculationFromTypedArrayType(node->typedArrayType()));
break;
}
- case CreateThis:
- case NewObject: {
- changed |= setPrediction(PredictFinalObject);
- changed |= mergeDefaultFlags(node);
+ case NewRegexp:
+ case CreateActivation: {
+ changed |= setPrediction(SpecObjectOther);
break;
}
-
- case NewArray: {
- changed |= setPrediction(PredictArray);
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- ++childIdx) {
- Edge edge = m_graph.m_varArgChildren[childIdx];
- changed |= m_graph[edge].mergeFlags(NodeUsedAsValue);
- }
+
+ case StringFromCharCode: {
+ changed |= setPrediction(SpecString);
+ changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt);
break;
}
-
- case NewArrayBuffer: {
- changed |= setPrediction(PredictArray);
+ case StringCharAt:
+ case ToString:
+ case MakeRope: {
+ changed |= setPrediction(SpecString);
break;
}
- case NewRegexp: {
- changed |= setPrediction(PredictObjectOther);
- break;
- }
-
- case StringCharAt: {
- changed |= setPrediction(PredictString);
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ case ToPrimitive: {
+ SpeculatedType child = node->child1()->prediction();
+ if (child)
+ changed |= mergePrediction(resultOfToPrimitive(child));
break;
}
- case StrCat: {
- changed |= setPrediction(PredictString);
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- ++childIdx)
- changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber);
+ case NewStringObject: {
+ changed |= setPrediction(SpecStringObject);
break;
}
- case ToPrimitive: {
- PredictedType child = m_graph[node.child1()].prediction();
- if (child) {
- if (isObjectPrediction(child)) {
- // I'd love to fold this case into the case below, but I can't, because
- // removing PredictObjectMask from something that only has an object
- // prediction and nothing else means we have an ill-formed PredictedType
- // (strong predict-none). This should be killed once we remove all traces
- // of static (aka weak) predictions.
- changed |= mergePrediction(PredictString);
- } else if (child & PredictObjectMask) {
- // Objects get turned into strings. So if the input has hints of objectness,
- // the output will have hinsts of stringiness.
- changed |= mergePrediction(
- mergePredictions(child & ~PredictObjectMask, PredictString));
- } else
- changed |= mergePrediction(child);
- }
- changed |= m_graph[node.child1()].mergeFlags(flags);
+ case CreateArguments: {
+ changed |= setPrediction(SpecArguments);
break;
}
- case CreateActivation: {
- changed |= setPrediction(PredictObjectOther);
+ case NewFunction: {
+ SpeculatedType child = node->child1()->prediction();
+ if (child & SpecEmpty)
+ changed |= mergePrediction((child & ~SpecEmpty) | SpecFunction);
+ else
+ changed |= mergePrediction(child);
break;
}
- case NewFunction:
case NewFunctionNoCheck:
case NewFunctionExpression: {
- changed |= setPrediction(PredictFunction);
+ changed |= setPrediction(SpecFunction);
break;
}
+ case FiatInt52: {
+ RELEASE_ASSERT(enableInt52());
+ changed |= setPrediction(SpecMachineInt);
+ break;
+ }
+
case PutByValAlias:
case GetArrayLength:
- case GetInt8ArrayLength:
- case GetInt16ArrayLength:
- case GetInt32ArrayLength:
- case GetUint8ArrayLength:
- case GetUint8ClampedArrayLength:
- case GetUint16ArrayLength:
- case GetUint32ArrayLength:
- case GetFloat32ArrayLength:
- case GetFloat64ArrayLength:
- case GetStringLength:
- case Int32ToDouble:
- case DoubleAsInt32: {
+ case GetTypedArrayByteOffset:
+ case DoubleAsInt32:
+ case GetLocalUnlinked:
+ case GetMyArgumentsLength:
+ case GetMyArgumentByVal:
+ case PhantomPutStructure:
+ case PhantomArguments:
+ case CheckArray:
+ case Arrayify:
+ case ArrayifyToStructure:
+ case CheckTierUpInLoop:
+ case CheckTierUpAtReturn:
+ case CheckTierUpAndOSREnter:
+ case InvalidationPoint:
+ case CheckInBounds:
+ case ValueToInt32:
+ case HardPhantom:
+ case DoubleRep:
+ case ValueRep:
+ case Int52Rep:
+ case DoubleConstant:
+ case Int52Constant:
+ case Identity:
+ case BooleanToNumber: {
// This node should never be visible at this stage of compilation. It is
// inserted by fixup(), which follows this phase.
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- case PutByVal:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
- changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
- break;
-
- case PutScopedVar:
- case Return:
- case Throw:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+ case Phi:
+ // Phis should not be visible here since we're iterating the all-but-Phi's
+ // part of basic blocks.
+ RELEASE_ASSERT_NOT_REACHED();
break;
-
- case PutById:
- case PutByIdDirect:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
+
+ case Upsilon:
+ case GetArgument:
+ // These don't get inserted until we go into SSA.
+ RELEASE_ASSERT_NOT_REACHED();
break;
- case PutByOffset:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
+ case GetScope:
+ changed |= setPrediction(SpecObjectOther);
break;
- case Phi:
+ case In:
+ changed |= setPrediction(SpecBoolean);
break;
#ifndef NDEBUG
// These get ignored because they don't return anything.
+ case StoreBarrier:
+ case StoreBarrierWithNullCheck:
+ case PutByValDirect:
+ case PutByVal:
+ case PutClosureVar:
+ case Return:
+ case Throw:
+ case PutById:
+ case PutByIdFlush:
+ case PutByIdDirect:
+ case PutByOffset:
+ case MultiPutByOffset:
case DFG::Jump:
case Branch:
+ case Switch:
case Breakpoint:
+ case ProfileWillCall:
+ case ProfileDidCall:
case CheckHasInstance:
case ThrowReferenceError:
case ForceOSRExit:
case SetArgument:
case CheckStructure:
+ case CheckExecutable:
+ case StructureTransitionWatchpoint:
case CheckFunction:
case PutStructure:
case TearOffActivation:
- case CheckNumber:
- changed |= mergeDefaultFlags(node);
+ case TearOffArguments:
+ case CheckArgumentsNotCreated:
+ case VariableWatchpoint:
+ case VarInjectionWatchpoint:
+ case AllocationProfileWatchpoint:
+ case Phantom:
+ case Check:
+ case PutGlobalVar:
+ case CheckWatchdogTimer:
+ case Unreachable:
+ case LoopHint:
+ case NotifyWrite:
+ case FunctionReentryWatchpoint:
+ case TypedArrayWatchpoint:
+ case ConstantStoragePointer:
+ case MovHint:
+ case ZombieHint:
+ break;
+
+ // This gets ignored because it already has a prediction.
+ case ExtractOSREntryLocal:
break;
// These gets ignored because it doesn't do anything.
- case Phantom:
- case InlineStart:
- case Nop:
+ case CountExecution:
+ case PhantomLocal:
+ case Flush:
break;
case LastNodeType:
- ASSERT_NOT_REACHED();
+ RELEASE_ASSERT_NOT_REACHED();
break;
#else
default:
- changed |= mergeDefaultFlags(node);
break;
#endif
}
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction()));
-#endif
-
m_changed |= changed;
}
- bool mergeDefaultFlags(Node& node)
- {
- bool changed = false;
- if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- childIdx++)
- changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
- } else {
- if (!node.child1())
- return changed;
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- if (!node.child2())
- return changed;
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
- if (!node.child3())
- return changed;
- changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
- }
- return changed;
- }
-
void propagateForward()
{
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Propagating predictions forward [%u]\n", ++m_count);
-#endif
- for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
- propagate(m_graph[m_compileIndex]);
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = 0; i < block->size(); ++i) {
+ m_currentNode = block->at(i);
+ propagate(m_currentNode);
+ }
+ }
}
void propagateBackward()
{
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Propagating predictions backward [%u]\n", ++m_count);
-#endif
- for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
- propagate(m_graph[m_compileIndex]);
- }
-
- void vote(Edge nodeUse, VariableAccessData::Ballot ballot)
- {
- switch (m_graph[nodeUse].op()) {
- case ValueToInt32:
- case UInt32ToNumber:
- nodeUse = m_graph[nodeUse].child1();
- break;
- default:
- break;
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = block->size(); i--;) {
+ m_currentNode = block->at(i);
+ propagate(m_currentNode);
+ }
}
-
- if (m_graph[nodeUse].op() == GetLocal)
- m_graph[nodeUse].variableAccessData()->vote(ballot);
}
- void vote(Node& node, VariableAccessData::Ballot ballot)
+ void doDoubleVoting(Node* node, float weight)
{
- if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- childIdx++)
- vote(m_graph.m_varArgChildren[childIdx], ballot);
- return;
- }
+ // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate
+ // that we actually don't know they weight. Assume that they execute once. This turns
+ // out to be an OK assumption since the pre-header doesn't have any meaningful code.
+ if (weight != weight)
+ weight = 1;
- if (!node.child1())
- return;
- vote(node.child1(), ballot);
- if (!node.child2())
- return;
- vote(node.child2(), ballot);
- if (!node.child3())
- return;
- vote(node.child3(), ballot);
- }
-
- void doRoundOfDoubleVoting()
- {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Voting on double uses of locals [%u]\n", m_count);
-#endif
- for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
- m_graph.m_variableAccessData[i].find()->clearVotes();
- for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex) {
- Node& node = m_graph[m_compileIndex];
- switch (node.op()) {
- case ValueAdd:
- case ArithAdd:
- case ArithSub: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ switch (node->op()) {
+ case ValueAdd:
+ case ArithAdd:
+ case ArithSub: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
- VariableAccessData::Ballot ballot;
+ DoubleBallot ballot;
- if (isNumberPrediction(left) && isNumberPrediction(right)
- && !m_graph.addShouldSpeculateInteger(node))
- ballot = VariableAccessData::VoteDouble;
- else
- ballot = VariableAccessData::VoteValue;
+ if (isFullNumberSpeculation(left)
+ && isFullNumberSpeculation(right)
+ && !m_graph.addShouldSpeculateInt32(node, m_pass)
+ && !m_graph.addShouldSpeculateMachineInt(node))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
- vote(node.child1(), ballot);
- vote(node.child2(), ballot);
- break;
- }
+ m_graph.voteNode(node->child1(), ballot, weight);
+ m_graph.voteNode(node->child2(), ballot, weight);
+ break;
+ }
- case ArithMul:
- case ArithMin:
- case ArithMax:
- case ArithMod:
- case ArithDiv: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ case ArithMul: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
- VariableAccessData::Ballot ballot;
+ DoubleBallot ballot;
- if (isNumberPrediction(left) && isNumberPrediction(right)
- && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()])
- && node.canSpeculateInteger()))
- ballot = VariableAccessData::VoteDouble;
- else
- ballot = VariableAccessData::VoteValue;
+ if (isFullNumberSpeculation(left)
+ && isFullNumberSpeculation(right)
+ && !m_graph.mulShouldSpeculateInt32(node, m_pass)
+ && !m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
- vote(node.child1(), ballot);
- vote(node.child2(), ballot);
- break;
- }
+ m_graph.voteNode(node->child1(), ballot, weight);
+ m_graph.voteNode(node->child2(), ballot, weight);
+ break;
+ }
+
+ case ArithMin:
+ case ArithMax:
+ case ArithMod:
+ case ArithDiv: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
- case ArithAbs:
- VariableAccessData::Ballot ballot;
- if (!(m_graph[node.child1()].shouldSpeculateInteger()
- && node.canSpeculateInteger()))
- ballot = VariableAccessData::VoteDouble;
- else
- ballot = VariableAccessData::VoteValue;
+ DoubleBallot ballot;
- vote(node.child1(), ballot);
- break;
+ if (isFullNumberSpeculation(left)
+ && isFullNumberSpeculation(right)
+ && !(Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInt32(m_pass)))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
- case ArithSqrt:
- vote(node.child1(), VariableAccessData::VoteDouble);
- break;
+ m_graph.voteNode(node->child1(), ballot, weight);
+ m_graph.voteNode(node->child2(), ballot, weight);
+ break;
+ }
- case SetLocal: {
- PredictedType prediction = m_graph[node.child1()].prediction();
- if (isDoublePrediction(prediction))
- node.variableAccessData()->vote(VariableAccessData::VoteDouble);
- else if (!isNumberPrediction(prediction) || isInt32Prediction(prediction))
- node.variableAccessData()->vote(VariableAccessData::VoteValue);
- break;
- }
+ case ArithAbs:
+ DoubleBallot ballot;
+ if (node->child1()->shouldSpeculateNumber()
+ && !(node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(m_pass)))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
+ m_graph.voteNode(node->child1(), ballot, weight);
+ break;
+
+ case ArithSqrt:
+ case ArithCos:
+ case ArithSin:
+ if (node->child1()->shouldSpeculateNumber())
+ m_graph.voteNode(node->child1(), VoteDouble, weight);
+ else
+ m_graph.voteNode(node->child1(), VoteValue, weight);
+ break;
+
+ case SetLocal: {
+ SpeculatedType prediction = node->child1()->prediction();
+ if (isDoubleSpeculation(prediction))
+ node->variableAccessData()->vote(VoteDouble, weight);
+ else if (
+ !isFullNumberSpeculation(prediction)
+ || isInt32Speculation(prediction) || isMachineIntSpeculation(prediction))
+ node->variableAccessData()->vote(VoteValue, weight);
+ break;
+ }
+
+ case PutByValDirect:
+ case PutByVal:
+ case PutByValAlias: {
+ Edge child1 = m_graph.varArgChild(node, 0);
+ Edge child2 = m_graph.varArgChild(node, 1);
+ Edge child3 = m_graph.varArgChild(node, 2);
+ m_graph.voteNode(child1, VoteValue, weight);
+ m_graph.voteNode(child2, VoteValue, weight);
+ switch (node->arrayMode().type()) {
+ case Array::Double:
+ m_graph.voteNode(child3, VoteDouble, weight);
+ break;
default:
- vote(node, VariableAccessData::VoteValue);
+ m_graph.voteNode(child3, VoteValue, weight);
break;
}
+ break;
+ }
+
+ case MovHint:
+ // Ignore these since they have no effect on in-DFG execution.
+ break;
+
+ default:
+ m_graph.voteChildren(node, VoteValue, weight);
+ break;
+ }
+ }
+
+ void doRoundOfDoubleVoting()
+ {
+ for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
+ m_graph.m_variableAccessData[i].find()->clearVotes();
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = 0; i < block->size(); ++i) {
+ m_currentNode = block->at(i);
+ doDoubleVoting(m_currentNode, block->executionCount);
+ }
}
for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
if (!variableAccessData->isRoot())
continue;
- if (operandIsArgument(variableAccessData->local())
- || m_graph.isCaptured(variableAccessData->local()))
- continue;
m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
}
for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i)
- m_changed |= m_graph.m_argumentPositions[i].mergeArgumentAwareness();
+ m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness();
for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
if (!variableAccessData->isRoot())
continue;
- if (operandIsArgument(variableAccessData->local())
- || m_graph.isCaptured(variableAccessData->local()))
- continue;
m_changed |= variableAccessData->makePredictionForDoubleFormat();
}
}
- NodeIndex m_compileIndex;
+ Node* m_currentNode;
bool m_changed;
-
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- unsigned m_count;
-#endif
+ PredictionPass m_pass; // We use different logic for considering predictions depending on how far along we are in propagation.
};
-void performPredictionPropagation(Graph& graph)
+bool performPredictionPropagation(Graph& graph)
{
- runPhase<PredictionPropagationPhase>(graph);
+ SamplingRegion samplingRegion("DFG Prediction Propagation Phase");
+ return runPhase<PredictionPropagationPhase>(graph);
}
} } // namespace JSC::DFG