/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 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 "Operations.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()
{
+ ASSERT(m_graph.m_form == ThreadedCPS);
+ ASSERT(m_graph.m_unificationState == GloballyUnified);
+
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
m_count = 0;
#endif
do {
m_changed = false;
doRoundOfDoubleVoting();
- propagateForward();
if (!m_changed)
break;
-
m_changed = false;
- doRoundOfDoubleVoting();
- propagateBackward();
+ propagateForward();
} while (m_changed);
+
+ return true;
}
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;
+ if (!isNumberSpeculation(value))
+ return SpecDouble;
+ if (value & SpecDoubleNaN)
+ return SpecDouble;
+ return SpecDoubleReal;
}
-
- 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));
+ dataLog(" ", Graph::opName(op), " ", m_currentNode, ": ", NodeFlagsDump(node->flags()), " ");
#endif
bool changed = false;
switch (op) {
case JSConstant:
case WeakJSConstant: {
- changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex)));
+ changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(node)));
break;
}
case GetLocal: {
- VariableAccessData* variableAccessData = node.variableAccessData();
- PredictedType prediction = variableAccessData->prediction();
+ VariableAccessData* variableAccessData = node->variableAccessData();
+ SpeculatedType prediction = variableAccessData->prediction();
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);
+ changed |= setPrediction(SpecInt32);
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 Call:
+ case Construct:
+ case GetGlobalVar:
+ case GetScopedVar:
+ case Resolve:
+ case ResolveBase:
+ case ResolveBaseStrictPut:
+ case ResolveGlobal: {
+ 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);
+ if (nodeCanSpeculateInteger(node->arithNodeFlags()))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= mergePrediction(PredictNumber);
-
- changed |= m_graph[node.child1()].mergeFlags(flags);
+ changed |= mergePrediction(SpecNumber);
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 (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) {
+ if (m_graph.addSpeculationMode(node) != DontSpeculateInteger)
+ changed |= mergePrediction(SpecInt32);
else
- changed |= mergePrediction(PredictDouble);
- } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ } else if (!(left & SpecNumber) || !(right & SpecNumber)) {
// 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 | SpecDouble);
}
-
- 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) != DontSpeculateInteger)
+ changed |= mergePrediction(SpecInt32);
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) != DontSpeculateInteger)
+ changed |= mergePrediction(SpecInt32);
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 (node->child1()->prediction()) {
if (m_graph.negateShouldSpeculateInteger(node))
- changed |= mergePrediction(PredictInt32);
+ changed |= mergePrediction(SpecInt32);
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::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+ && nodeCanSpeculateInteger(node->arithNodeFlags()))
+ 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.mulShouldSpeculateInteger(node))
+ changed |= mergePrediction(SpecInt32);
+ 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::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+ && nodeCanSpeculateInteger(node->arithNodeFlags()))
+ changed |= mergePrediction(SpecInt32);
else
- changed |= mergePrediction(PredictDouble);
+ changed |= mergePrediction(SpecDouble);
}
-
- // 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::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+ && nodeCanSpeculateInteger(node->arithNodeFlags()))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(SpecDouble);
+ }
break;
}
case ArithSqrt: {
- changed |= setPrediction(PredictDouble);
- changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
+ changed |= setPrediction(SpecDouble);
break;
}
case ArithAbs: {
- PredictedType child = m_graph[node.child1()].prediction();
- if (nodeCanSpeculateInteger(node.arithNodeFlags()))
- changed |= mergePrediction(child);
+ SpeculatedType child = node->child1()->prediction();
+ if (isInt32SpeculationForArithmetic(child)
+ && nodeCanSpeculateInteger(node->arithNodeFlags()))
+ 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 CompareStrictEqConstant:
case InstanceOf:
case IsUndefined:
case IsBoolean:
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 GetByIdFlush:
- changed |= mergePrediction(node.getHeapPrediction());
- changed |= mergeDefaultFlags(node);
- break;
-
+
case GetByVal: {
- if (m_graph[node.child1()].shouldSpeculateFloat32Array()
- || m_graph[node.child1()].shouldSpeculateFloat64Array())
- changed |= mergePrediction(PredictDouble);
+ if (node->child1()->shouldSpeculateFloat32Array()
+ || node->child1()->shouldSpeculateFloat64Array())
+ changed |= mergePrediction(SpecDouble);
else
- changed |= mergePrediction(node.getHeapPrediction());
-
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ changed |= mergePrediction(node->getHeapPrediction());
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);
- 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);
- }
+ case GetScopeRegisters:
+ case GetButterfly:
+ case GetIndexedPropertyStorage:
+ case AllocatePropertyStorage:
+ case ReallocatePropertyStorage: {
+ changed |= setPrediction(SpecOther);
break;
}
-
+
case ConvertThis: {
- PredictedType prediction = m_graph[node.child1()].prediction();
+ 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());
- break;
- }
-
- case PutGlobalVar: {
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- break;
- }
-
- case GetScopedVar:
- case Resolve:
- case ResolveBase:
- case ResolveBaseStrictPut:
- case ResolveGlobal: {
- PredictedType prediction = node.getHeapPrediction();
- changed |= mergePrediction(prediction);
break;
}
- case GetScopeChain: {
- changed |= setPrediction(PredictCellOther);
+ case GetMyScope:
+ case SkipTopScope:
+ case SkipScope: {
+ changed |= setPrediction(SpecObjectOther);
break;
}
case GetCallee: {
- changed |= setPrediction(PredictFunction);
+ changed |= setPrediction(SpecFunction);
break;
}
case CreateThis:
case NewObject: {
- changed |= setPrediction(PredictFinalObject);
- changed |= mergeDefaultFlags(node);
- 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);
- }
+ changed |= setPrediction(SpecFinalObject);
break;
}
+ case NewArray:
+ case NewArrayWithSize:
case NewArrayBuffer: {
- changed |= setPrediction(PredictArray);
+ changed |= setPrediction(SpecArray);
break;
}
- case NewRegexp: {
- changed |= setPrediction(PredictObjectOther);
+ case NewRegexp:
+ case CreateActivation: {
+ changed |= setPrediction(SpecObjectOther);
break;
}
- case StringCharAt: {
- changed |= setPrediction(PredictString);
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ case StringFromCharCode: {
+ changed |= setPrediction(SpecString);
+ changed |= node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
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 StringCharAt:
+ case ToString:
+ case MakeRope: {
+ changed |= setPrediction(SpecString);
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);
+ SpeculatedType child = node->child1()->prediction();
+ if (child)
+ changed |= mergePrediction(resultOfToPrimitive(child));
break;
}
- case CreateActivation: {
- changed |= setPrediction(PredictObjectOther);
+ case NewStringObject: {
+ changed |= setPrediction(SpecStringObject);
+ break;
+ }
+
+ case CreateArguments: {
+ changed |= setPrediction(SpecArguments);
+ break;
+ }
+
+ 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 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 ForwardInt32ToDouble:
+ case DoubleAsInt32:
+ case GetLocalUnlinked:
+ case GetMyArgumentsLength:
+ case GetMyArgumentByVal:
+ case PhantomPutStructure:
+ case PhantomArguments:
+ case CheckArray:
+ case Arrayify:
+ case ArrayifyToStructure:
+ case MovHint:
+ case MovHintAndCheck:
+ case ZombieHint: {
// This node should never be visible at this stage of compilation. It is
// inserted by fixup(), which follows this phase.
- ASSERT_NOT_REACHED();
+ CRASH();
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);
+ case Phi:
+ // Phis should not be visible here since we're iterating the all-but-Phi's
+ // part of basic blocks.
+ CRASH();
break;
- case PutScopedVar:
- case Return:
- case Throw:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+ case GetScope:
+ changed |= setPrediction(SpecObjectOther);
break;
- case PutById:
- case PutByIdDirect:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
- break;
-
- case PutByOffset:
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
- break;
-
- case Phi:
+ case Identity:
+ changed |= mergePrediction(node->child1()->prediction());
break;
#ifndef NDEBUG
// These get ignored because they don't return anything.
+ case PutByVal:
+ case PutScopedVar:
+ case Return:
+ case Throw:
+ case PutById:
+ case PutByIdDirect:
+ case PutByOffset:
+ case SetCallee:
+ case SetMyScope:
case DFG::Jump:
case Branch:
case Breakpoint:
case ForceOSRExit:
case SetArgument:
case CheckStructure:
+ case CheckExecutable:
+ case ForwardCheckStructure:
+ case StructureTransitionWatchpoint:
+ case ForwardStructureTransitionWatchpoint:
case CheckFunction:
case PutStructure:
case TearOffActivation:
- case CheckNumber:
- changed |= mergeDefaultFlags(node);
+ case TearOffArguments:
+ case CheckArgumentsNotCreated:
+ case GlobalVarWatchpoint:
+ case GarbageValue:
+ case AllocationProfileWatchpoint:
+ case Phantom:
+ case PutGlobalVar:
+ case PutGlobalVarCheck:
+ case CheckWatchdogTimer:
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();
+ CRASH();
break;
#else
default:
- changed |= mergeDefaultFlags(node);
break;
#endif
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction()));
+ dataLog(SpeculationDump(node->prediction()), "\n");
#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);
+ dataLogF("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.m_blocks.size(); ++blockIndex) {
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ 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);
+ dataLogF("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.m_blocks.size(); blockIndex--;) {
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ 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)
{
- if (node.flags() & NodeHasVarArgs) {
- for (unsigned childIdx = node.firstChild();
- childIdx < node.firstChild() + node.numChildren();
- childIdx++)
- vote(m_graph.m_varArgChildren[childIdx], ballot);
- return;
+ switch (node->op()) {
+ case ValueAdd:
+ case ArithAdd:
+ case ArithSub: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ DoubleBallot ballot;
+
+ if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)
+ && !m_graph.addShouldSpeculateInteger(node))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
+
+ m_graph.voteNode(node->child1(), ballot);
+ m_graph.voteNode(node->child2(), ballot);
+ break;
}
-
- 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();
- VariableAccessData::Ballot ballot;
+ case ArithMul: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
- if (isNumberPrediction(left) && isNumberPrediction(right)
- && !m_graph.addShouldSpeculateInteger(node))
- ballot = VariableAccessData::VoteDouble;
- else
- ballot = VariableAccessData::VoteValue;
+ DoubleBallot ballot;
- vote(node.child1(), ballot);
- vote(node.child2(), ballot);
- break;
- }
+ if (isNumberSpeculation(left) && isNumberSpeculation(right)
+ && !m_graph.mulShouldSpeculateInteger(node))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
- case ArithMul:
- case ArithMin:
- case ArithMax:
- case ArithMod:
- case ArithDiv: {
- PredictedType left = m_graph[node.child1()].prediction();
- PredictedType right = m_graph[node.child2()].prediction();
+ m_graph.voteNode(node->child1(), ballot);
+ m_graph.voteNode(node->child2(), ballot);
+ break;
+ }
+
+ case ArithMin:
+ case ArithMax:
+ case ArithMod:
+ case ArithDiv: {
+ 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 (isNumberSpeculation(left) && isNumberSpeculation(right)
+ && !(Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInteger()))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
- vote(node.child1(), ballot);
- vote(node.child2(), ballot);
- break;
- }
+ m_graph.voteNode(node->child1(), ballot);
+ m_graph.voteNode(node->child2(), ballot);
+ break;
+ }
- case ArithAbs:
- VariableAccessData::Ballot ballot;
- if (!(m_graph[node.child1()].shouldSpeculateInteger()
- && node.canSpeculateInteger()))
- ballot = VariableAccessData::VoteDouble;
- else
- ballot = VariableAccessData::VoteValue;
+ case ArithAbs:
+ DoubleBallot ballot;
+ if (!(node->child1()->shouldSpeculateIntegerForArithmetic() && node->canSpeculateInteger()))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
- vote(node.child1(), ballot);
- break;
+ m_graph.voteNode(node->child1(), ballot);
+ break;
- case ArithSqrt:
- vote(node.child1(), VariableAccessData::VoteDouble);
- break;
+ case ArithSqrt:
+ m_graph.voteNode(node->child1(), VoteDouble);
+ 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 SetLocal: {
+ SpeculatedType prediction = node->child1()->prediction();
+ if (isDoubleSpeculation(prediction))
+ node->variableAccessData()->vote(VoteDouble);
+ else if (!isNumberSpeculation(prediction) || isInt32Speculation(prediction))
+ node->variableAccessData()->vote(VoteValue);
+ break;
+ }
+ 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);
+ m_graph.voteNode(child2, VoteValue);
+ switch (node->arrayMode().type()) {
+ case Array::Double:
+ m_graph.voteNode(child3, VoteDouble);
+ break;
default:
- vote(node, VariableAccessData::VoteValue);
+ m_graph.voteNode(child3, VoteValue);
break;
}
+ break;
+ }
+
+ default:
+ m_graph.voteChildren(node, VoteValue);
+ break;
+ }
+ }
+
+ void doRoundOfDoubleVoting()
+ {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLogF("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 (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = 0; i < block->size(); ++i) {
+ m_currentNode = block->at(i);
+ doDoubleVoting(m_currentNode);
+ }
}
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)
#endif
};
-void performPredictionPropagation(Graph& graph)
+bool performPredictionPropagation(Graph& graph)
{
- runPhase<PredictionPropagationPhase>(graph);
+ SamplingRegion samplingRegion("DFG Prediction Propagation Phase");
+ return runPhase<PredictionPropagationPhase>(graph);
}
} } // namespace JSC::DFG