X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/a253471d7f8e4d91bf6ebabab00155c3b387d3d0..93a3786624b2768d89bfa27e46598dc64e2fb70a:/dfg/DFGPredictionPropagationPhase.cpp diff --git a/dfg/DFGPredictionPropagationPhase.cpp b/dfg/DFGPredictionPropagationPhase.cpp index 5317460..356adb5 100644 --- a/dfg/DFGPredictionPropagationPhase.cpp +++ b/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) @@ -40,8 +52,11 @@ public: { } - 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 @@ -69,62 +84,56 @@ public: 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; @@ -132,31 +141,21 @@ private: 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; } @@ -165,210 +164,172 @@ private: 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; } @@ -378,7 +339,9 @@ private: case CompareGreater: case CompareGreaterEq: case CompareEq: + case CompareEqConstant: case CompareStrictEq: + case CompareStrictEqConstant: case InstanceOf: case IsUndefined: case IsBoolean: @@ -386,228 +349,172 @@ private: 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: @@ -616,215 +523,222 @@ private: 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) @@ -832,9 +746,10 @@ private: #endif }; -void performPredictionPropagation(Graph& graph) +bool performPredictionPropagation(Graph& graph) { - runPhase(graph); + SamplingRegion samplingRegion("DFG Prediction Propagation Phase"); + return runPhase(graph); } } } // namespace JSC::DFG