diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp | 789 |
1 files changed, 268 insertions, 521 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 4226fcc6a..980e6b447 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -1,5 +1,5 @@ /* - * 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 @@ -30,9 +30,21 @@ #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) @@ -42,6 +54,9 @@ public: bool run() { + ASSERT(m_graph.m_form == ThreadedCPS); + ASSERT(m_graph.m_unificationState == GloballyUnified); + #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) m_count = 0; #endif @@ -69,13 +84,10 @@ public: do { m_changed = false; doRoundOfDoubleVoting(); - propagateForward(); if (!m_changed) break; - m_changed = false; - doRoundOfDoubleVoting(); - propagateBackward(); + propagateForward(); } while (m_changed); return true; @@ -84,85 +96,24 @@ public: private: 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 mergeSpeculation() other than the // increased checking to validate this property. - ASSERT(m_graph[m_compileIndex].prediction() == SpecNone || 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(SpeculatedType prediction) { - ASSERT(m_graph[m_compileIndex].hasResult()); + ASSERT(m_currentNode->hasResult()); - return m_graph[m_compileIndex].predict(prediction); - } - - bool isNotNegZero(NodeIndex nodeIndex) - { - if (!m_graph.isNumberConstant(nodeIndex)) - return false; - double value = m_graph.valueOfNumberConstant(nodeIndex); - return !value && 1.0 / value < 0.0; - } - - bool isNotZero(NodeIndex nodeIndex) - { - if (!m_graph.isNumberConstant(nodeIndex)) - return false; - return !!m_graph.valueOfNumberConstant(nodeIndex); - } - - bool isWithinPowerOfTwoForConstant(Node& node, int power) - { - JSValue immediateValue = node.valueOfJSConstant(codeBlock()); - if (!immediateValue.isInt32()) - return false; - int32_t intImmediate = immediateValue.asInt32(); - return intImmediate > -(1 << power) && intImmediate < (1 << power); - } - - bool isWithinPowerOfTwoNonRecursive(NodeIndex nodeIndex, int power) - { - Node& node = m_graph[nodeIndex]; - if (node.op() != JSConstant) - return false; - return isWithinPowerOfTwoForConstant(node, power); + return m_currentNode->predict(prediction); } - bool isWithinPowerOfTwo(NodeIndex nodeIndex, int power) - { - Node& node = m_graph[nodeIndex]; - switch (node.op()) { - case JSConstant: { - return isWithinPowerOfTwoForConstant(node, power); - } - - case BitAnd: { - return isWithinPowerOfTwoNonRecursive(node.child1().index(), power) - || isWithinPowerOfTwoNonRecursive(node.child2().index(), power); - } - - case BitRShift: - case BitURShift: { - Node& shiftAmount = m_graph[node.child2()]; - if (shiftAmount.op() != JSConstant) - return false; - JSValue immediateValue = shiftAmount.valueOfJSConstant(codeBlock()); - if (!immediateValue.isInt32()) - return false; - return immediateValue > 32 - power; - } - - default: - return false; - } - } - SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value) { if (!isNumberSpeculation(value)) @@ -177,16 +128,12 @@ private: 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) - dataLogF(" %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags)); + dataLog(" ", Graph::opName(op), " ", m_currentNode, ": ", NodeFlagsDump(node->flags()), " "); #endif bool changed = false; @@ -194,37 +141,21 @@ private: switch (op) { case JSConstant: case WeakJSConstant: { - changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(m_compileIndex))); + changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(node))); break; } case GetLocal: { - VariableAccessData* variableAccessData = node.variableAccessData(); + 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()); - - // Assume conservatively that a SetLocal implies that the value may flow through a loop, - // and so we would have overflow leading to the program "observing" numbers even if all - // users of the value are doing toInt32. It might be worthwhile to revisit this at some - // point and actually check if the data flow involves loops, but right now I don't think - // we have evidence that this would be beneficial for benchmarks. - changed |= m_graph[node.child1()].mergeFlags(variableAccessData->flags() | NodeUsedAsNumber); - 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; } @@ -233,69 +164,57 @@ private: case BitXor: case BitRShift: case BitLShift: - case BitURShift: { + case BitURShift: + case ArithIMul: { changed |= setPrediction(SpecInt32); - flags |= NodeUsedAsInt; - flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther); - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ValueToInt32: { changed |= setPrediction(SpecInt32); - flags |= NodeUsedAsInt; - flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther); - 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 Call: + case Construct: + case GetGlobalVar: + case GetScopedVar: + case Resolve: + case ResolveBase: + case ResolveBaseStrictPut: + case ResolveGlobal: { + changed |= setPrediction(node->getHeapPrediction()); break; } case StringCharCodeAt: { - changed |= mergePrediction(SpecInt32); - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); - changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); + changed |= setPrediction(SpecInt32); break; } case UInt32ToNumber: { - if (nodeCanSpeculateInteger(node.arithNodeFlags())) + if (nodeCanSpeculateInteger(node->arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(SpecNumber); - - changed |= m_graph[node.child1()].mergeFlags(flags); break; } case ValueAdd: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); - - AddSpeculationMode mode = DontSpeculateInteger; + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) { - if ((mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger) + if (m_graph.addSpeculationMode(node) != DontSpeculateInteger) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); @@ -305,107 +224,62 @@ private: } else changed |= mergePrediction(SpecString | SpecInt32 | SpecDouble); } - - if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) - flags &= ~NodeNeedsNegZero; - if (m_graph[node.child1()].hasNumberResult() || m_graph[node.child2()].hasNumberResult()) - flags &= ~NodeUsedAsOther; - - if (mode != SpeculateInteger) - flags |= NodeUsedAsNumber; - - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithAdd: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); - - AddSpeculationMode mode = DontSpeculateInteger; + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { - if ((mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger) + if (m_graph.addSpeculationMode(node) != DontSpeculateInteger) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } - - if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index())) - flags &= ~NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; - - if (mode != SpeculateInteger) - flags |= NodeUsedAsNumber; - - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithSub: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); - - AddSpeculationMode mode = DontSpeculateInteger; + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { - if ((mode = m_graph.addSpeculationMode(node)) != DontSpeculateInteger) + if (m_graph.addSpeculationMode(node) != DontSpeculateInteger) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } - - if (isNotZero(node.child1().index()) || isNotZero(node.child2().index())) - flags &= ~NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; - - if (mode != SpeculateInteger) - flags |= NodeUsedAsNumber; - - 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(SpecInt32); else - changed |= mergePrediction(speculatedDoubleTypeForPrediction(m_graph[node.child1()].prediction())); + changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction())); } - - flags &= ~NodeUsedAsOther; - - changed |= m_graph[node.child1()].mergeFlags(flags); break; case ArithMin: case ArithMax: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) - && nodeCanSpeculateInteger(node.arithNodeFlags())) + if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node()) + && nodeCanSpeculateInteger(node->arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } - - flags |= NodeUsedAsNumber; - flags &= ~NodeUsedAsOther; - - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithMul: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { if (m_graph.mulShouldSpeculateInteger(node)) @@ -413,90 +287,49 @@ private: else changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); } - - // 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 forces its inputs to - // check for overflow. Additionally, it will have to check for overflow - // itself unless we can prove that there is no way for the values - // produced to cause double rounding. - - if (!isWithinPowerOfTwo(node.child1().index(), 22) - && !isWithinPowerOfTwo(node.child2().index(), 22)) - flags |= NodeUsedAsNumber; - - changed |= node.mergeFlags(flags); - - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; - - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithDiv: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) - && nodeCanSpeculateInteger(node.arithNodeFlags())) + if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node()) + && nodeCanSpeculateInteger(node->arithNodeFlags())) changed |= mergePrediction(SpecInt32); else 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, ArithDiv always checks for overflow - // no matter what, and always forces its inputs to check as well. - - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; - - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithMod: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); if (left && right) { - if (Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child2()]) - && nodeCanSpeculateInteger(node.arithNodeFlags())) + if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node()) + && nodeCanSpeculateInteger(node->arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(SpecDouble); } - - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; - - changed |= m_graph[node.child1()].mergeFlags(flags); - changed |= m_graph[node.child2()].mergeFlags(flags); break; } case ArithSqrt: { changed |= setPrediction(SpecDouble); - flags |= NodeUsedAsNumber | NodeNeedsNegZero; - flags &= ~NodeUsedAsOther; - changed |= m_graph[node.child1()].mergeFlags(flags); break; } case ArithAbs: { - SpeculatedType child = m_graph[node.child1()].prediction(); + SpeculatedType child = node->child1()->prediction(); if (isInt32SpeculationForArithmetic(child) - && nodeCanSpeculateInteger(node.arithNodeFlags())) + && nodeCanSpeculateInteger(node->arithNodeFlags())) changed |= mergePrediction(SpecInt32); else changed |= mergePrediction(speculatedDoubleTypeForPrediction(child)); - - changed |= m_graph[node.child1()].mergeFlags(flags); break; } @@ -506,7 +339,9 @@ private: case CompareGreater: case CompareGreaterEq: case CompareEq: + case CompareEqConstant: case CompareStrictEq: + case CompareStrictEqConstant: case InstanceOf: case IsUndefined: case IsBoolean: @@ -515,36 +350,20 @@ private: case IsObject: case IsFunction: { changed |= setPrediction(SpecBoolean); - changed |= mergeDefaultFlags(node); 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()) + 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 | NodeUsedAsOther | NodeUsedAsInt); - break; - } - - case GetMyArgumentByValSafe: { - changed |= mergePrediction(node.getHeapPrediction()); - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); + changed |= mergePrediction(node->getHeapPrediction()); break; } @@ -559,63 +378,24 @@ private: case AllocatePropertyStorage: case ReallocatePropertyStorage: { changed |= setPrediction(SpecOther); - changed |= mergeDefaultFlags(node); 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); - } - break; - } - case ConvertThis: { - SpeculatedType prediction = m_graph[node.child1()].prediction(); + SpeculatedType prediction = node->child1()->prediction(); if (prediction) { - if (prediction & ~SpecObjectMask) { - prediction &= SpecObjectMask; + 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: - case PutGlobalVarCheck: { - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); - break; - } - - case GetScopedVar: - case Resolve: - case ResolveBase: - case ResolveBaseStrictPut: - case ResolveGlobal: { - SpeculatedType prediction = node.getHeapPrediction(); - changed |= mergePrediction(prediction); - break; - } - - case GetScope: { + case GetMyScope: + case SkipTopScope: + case SkipScope: { changed |= setPrediction(SpecCellOther); break; } @@ -628,88 +408,60 @@ private: case CreateThis: case NewObject: { changed |= setPrediction(SpecFinalObject); - changed |= mergeDefaultFlags(node); - break; - } - - case NewArray: { - changed |= setPrediction(SpecArray); - 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 NewArrayWithSize: { - changed |= setPrediction(SpecArray); - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue | NodeUsedAsInt); break; } + case NewArray: + case NewArrayWithSize: case NewArrayBuffer: { changed |= setPrediction(SpecArray); break; } - case NewRegexp: { + case NewRegexp: + case CreateActivation: { changed |= setPrediction(SpecObjectOther); break; } - case StringCharAt: { + case StringFromCharCode: { changed |= setPrediction(SpecString); - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); - changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); + changed |= node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); break; } - - case StrCat: { + case StringCharAt: + case ToString: + case MakeRope: { changed |= setPrediction(SpecString); - for (unsigned childIdx = node.firstChild(); - childIdx < node.firstChild() + node.numChildren(); - ++childIdx) - changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther); break; } case ToPrimitive: { - SpeculatedType child = m_graph[node.child1()].prediction(); - if (child) { - if (isObjectSpeculation(child)) { - // I'd love to fold this case into the case below, but I can't, because - // removing SpecObjectMask from something that only has an object - // prediction and nothing else means we have an ill-formed SpeculatedType - // (strong predict-none). This should be killed once we remove all traces - // of static (aka weak) predictions. - changed |= mergePrediction(SpecString); - } else if (child & SpecObjectMask) { - // Objects get turned into strings. So if the input has hints of objectness, - // the output will have hinsts of stringiness. - changed |= mergePrediction( - mergeSpeculations(child & ~SpecObjectMask, SpecString)); - } 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(SpecObjectOther); + case NewStringObject: { + changed |= setPrediction(SpecStringObject); break; } case CreateArguments: { - // At this stage we don't try to predict whether the arguments are ours or - // someone else's. We could, but we don't, yet. changed |= setPrediction(SpecArguments); break; } - case NewFunction: + case NewFunction: { + SpeculatedType child = node->child1()->prediction(); + if (child & SpecEmpty) + changed |= mergePrediction((child & ~SpecEmpty) | SpecFunction); + else + changed |= mergePrediction(child); + break; + } + case NewFunctionNoCheck: case NewFunctionExpression: { changed |= setPrediction(SpecFunction); @@ -719,6 +471,7 @@ private: case PutByValAlias: case GetArrayLength: case Int32ToDouble: + case ForwardInt32ToDouble: case DoubleAsInt32: case GetLocalUnlinked: case GetMyArgumentsLength: @@ -728,45 +481,40 @@ private: case CheckArray: case Arrayify: case ArrayifyToStructure: - case Identity: { + 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. CRASH(); break; } - case PutByVal: - changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue); - changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt); - changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue); - break; - - case PutScopedVar: - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); - changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue); - break; - - 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. + CRASH(); break; - case PutById: - case PutByIdDirect: - changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue); - changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue); + case GetScope: + changed |= setPrediction(SpecCellOther); 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: @@ -775,6 +523,7 @@ private: case ForceOSRExit: case SetArgument: case CheckStructure: + case CheckExecutable: case ForwardCheckStructure: case StructureTransitionWatchpoint: case ForwardStructureTransitionWatchpoint: @@ -782,18 +531,22 @@ private: case PutStructure: case TearOffActivation: case TearOffArguments: - case CheckNumber: case CheckArgumentsNotCreated: case GlobalVarWatchpoint: case GarbageValue: - case InheritorIDWatchpoint: - changed |= mergeDefaultFlags(node); + 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: @@ -801,49 +554,32 @@ private: break; #else default: - changed |= mergeDefaultFlags(node); break; #endif } #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLogF("%s\n", speculationToString(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++) { - if (!!m_graph.m_varArgChildren[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) 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() @@ -851,147 +587,158 @@ private: #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) dataLogF("Propagating predictions backward [%u]\n", ++m_count); #endif - for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;) - propagate(m_graph[m_compileIndex]); + 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); + } + } } - void doRoundOfDoubleVoting() + void doDoubleVoting(Node* node) { -#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 (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: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType 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(); - DoubleBallot ballot; + DoubleBallot ballot; - if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right) - && !m_graph.addShouldSpeculateInteger(node)) - ballot = VoteDouble; - else - ballot = VoteValue; + if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right) + && !m_graph.addShouldSpeculateInteger(node)) + ballot = VoteDouble; + else + ballot = VoteValue; - m_graph.vote(node.child1(), ballot); - m_graph.vote(node.child2(), ballot); - break; - } + m_graph.voteNode(node->child1(), ballot); + m_graph.voteNode(node->child2(), ballot); + break; + } - case ArithMul: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); + case ArithMul: { + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); - DoubleBallot ballot; + DoubleBallot ballot; - if (isNumberSpeculation(left) && isNumberSpeculation(right) - && !m_graph.mulShouldSpeculateInteger(node)) - ballot = VoteDouble; - else - ballot = VoteValue; + if (isNumberSpeculation(left) && isNumberSpeculation(right) + && !m_graph.mulShouldSpeculateInteger(node)) + ballot = VoteDouble; + else + ballot = VoteValue; - m_graph.vote(node.child1(), ballot); - m_graph.vote(node.child2(), ballot); - break; - } + m_graph.voteNode(node->child1(), ballot); + m_graph.voteNode(node->child2(), ballot); + break; + } - case ArithMin: - case ArithMax: - case ArithMod: - case ArithDiv: { - SpeculatedType left = m_graph[node.child1()].prediction(); - SpeculatedType right = m_graph[node.child2()].prediction(); + case ArithMin: + case ArithMax: + case ArithMod: + case ArithDiv: { + SpeculatedType left = node->child1()->prediction(); + SpeculatedType right = node->child2()->prediction(); - DoubleBallot ballot; + DoubleBallot ballot; - if (isNumberSpeculation(left) && isNumberSpeculation(right) - && !(Node::shouldSpeculateIntegerForArithmetic(m_graph[node.child1()], m_graph[node.child1()]) - && node.canSpeculateInteger())) - ballot = VoteDouble; - else - ballot = VoteValue; + if (isNumberSpeculation(left) && isNumberSpeculation(right) + && !(Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInteger())) + ballot = VoteDouble; + else + ballot = VoteValue; - m_graph.vote(node.child1(), ballot); - m_graph.vote(node.child2(), ballot); - break; - } + m_graph.voteNode(node->child1(), ballot); + m_graph.voteNode(node->child2(), ballot); + break; + } - case ArithAbs: - DoubleBallot ballot; - if (!(m_graph[node.child1()].shouldSpeculateIntegerForArithmetic() - && node.canSpeculateInteger())) - ballot = VoteDouble; - else - ballot = VoteValue; + case ArithAbs: + DoubleBallot ballot; + if (!(node->child1()->shouldSpeculateIntegerForArithmetic() && node->canSpeculateInteger())) + ballot = VoteDouble; + else + ballot = VoteValue; - m_graph.vote(node.child1(), ballot); - break; + m_graph.voteNode(node->child1(), ballot); + break; - case ArithSqrt: - m_graph.vote(node.child1(), VoteDouble); - break; + case ArithSqrt: + m_graph.voteNode(node->child1(), VoteDouble); + break; - case SetLocal: { - SpeculatedType prediction = m_graph[node.child1()].prediction(); - if (isDoubleSpeculation(prediction)) - node.variableAccessData()->vote(VoteDouble); - else if (!isNumberSpeculation(prediction) || isInt32Speculation(prediction)) - node.variableAccessData()->vote(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.vote(child1, VoteValue); - m_graph.vote(child2, VoteValue); - switch (node.arrayMode().type()) { - case Array::Double: - m_graph.vote(child3, VoteDouble); - break; - default: - m_graph.vote(child3, 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: - m_graph.vote(node, 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()) - || variableAccessData->isCaptured()) - 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()) - || variableAccessData->isCaptured()) - continue; m_changed |= variableAccessData->makePredictionForDoubleFormat(); } } - NodeIndex m_compileIndex; + Node* m_currentNode; bool m_changed; #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) |