summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
commite15dd966d523731101f70ccf768bba12435a0208 (patch)
treeae9cb828a24ded2585a41af3f21411523b47897d /Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
downloadWebKitGtk-tarball-e15dd966d523731101f70ccf768bba12435a0208.tar.gz
webkitgtk-2.10.2webkitgtk-2.10.2
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp903
1 files changed, 903 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
new file mode 100644
index 000000000..36f2df7c7
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGPredictionPropagationPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+#include "DFGPhase.h"
+#include "JSCInlines.h"
+
+namespace JSC { namespace DFG {
+
+SpeculatedType resultOfToPrimitive(SpeculatedType type)
+{
+ if (type & SpecObject) {
+ // Objects get turned into strings. So if the input has hints of objectness,
+ // the output will have hinsts of stringiness.
+ return mergeSpeculations(type & ~SpecObject, SpecString);
+ }
+
+ return type;
+}
+
+class PredictionPropagationPhase : public Phase {
+public:
+ PredictionPropagationPhase(Graph& graph)
+ : Phase(graph, "prediction propagation")
+ {
+ }
+
+ bool run()
+ {
+ ASSERT(m_graph.m_form == ThreadedCPS);
+ ASSERT(m_graph.m_unificationState == GloballyUnified);
+
+ propagateThroughArgumentPositions();
+
+ m_pass = PrimaryPass;
+ propagateToFixpoint();
+
+ m_pass = RareCasePass;
+ propagateToFixpoint();
+
+ m_pass = DoubleVotingPass;
+ do {
+ m_changed = false;
+ doRoundOfDoubleVoting();
+ if (!m_changed)
+ break;
+ m_changed = false;
+ propagateForward();
+ } while (m_changed);
+
+ return true;
+ }
+
+private:
+ void propagateToFixpoint()
+ {
+ do {
+ m_changed = false;
+
+ // Forward propagation is near-optimal for both topologically-sorted and
+ // DFS-sorted code.
+ propagateForward();
+ if (!m_changed)
+ break;
+
+ // Backward propagation reduces the likelihood that pathological code will
+ // cause slowness. Loops (especially nested ones) resemble backward flow.
+ // This pass captures two cases: (1) it detects if the forward fixpoint
+ // found a sound solution and (2) short-circuits backward flow.
+ m_changed = false;
+ propagateBackward();
+ } while (m_changed);
+ }
+
+ bool setPrediction(SpeculatedType prediction)
+ {
+ 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_currentNode->prediction() == SpecNone || m_currentNode->prediction() == prediction);
+
+ return m_currentNode->predict(prediction);
+ }
+
+ bool mergePrediction(SpeculatedType prediction)
+ {
+ ASSERT(m_currentNode->hasResult());
+
+ return m_currentNode->predict(prediction);
+ }
+
+ SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value)
+ {
+ SpeculatedType result = SpecDoubleReal;
+ if (value & SpecDoubleImpureNaN)
+ result |= SpecDoubleImpureNaN;
+ if (value & SpecDoublePureNaN)
+ result |= SpecDoublePureNaN;
+ if (!isFullNumberOrBooleanSpeculation(value))
+ result |= SpecDoublePureNaN;
+ return result;
+ }
+
+ SpeculatedType speculatedDoubleTypeForPredictions(SpeculatedType left, SpeculatedType right)
+ {
+ return speculatedDoubleTypeForPrediction(mergeSpeculations(left, right));
+ }
+
+ void propagate(Node* node)
+ {
+ NodeType op = node->op();
+
+ bool changed = false;
+
+ switch (op) {
+ case JSConstant: {
+ SpeculatedType type = speculationFromValue(node->asJSValue());
+ if (type == SpecInt52AsDouble && enableInt52())
+ type = SpecInt52;
+ changed |= setPrediction(type);
+ break;
+ }
+ case DoubleConstant: {
+ SpeculatedType type = speculationFromValue(node->asJSValue());
+ changed |= setPrediction(type);
+ break;
+ }
+
+ case GetLocal: {
+ VariableAccessData* variable = node->variableAccessData();
+ SpeculatedType prediction = variable->prediction();
+ if (!variable->couldRepresentInt52() && (prediction & SpecInt52))
+ prediction = (prediction | SpecInt52AsDouble) & ~SpecInt52;
+ if (prediction)
+ changed |= mergePrediction(prediction);
+ break;
+ }
+
+ case SetLocal: {
+ VariableAccessData* variableAccessData = node->variableAccessData();
+ changed |= variableAccessData->predict(node->child1()->prediction());
+ break;
+ }
+
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ case BitRShift:
+ case BitLShift:
+ case BitURShift:
+ case ArithIMul:
+ case ArithClz32: {
+ changed |= setPrediction(SpecInt32);
+ break;
+ }
+
+ case ArrayPop:
+ case ArrayPush:
+ case RegExpExec:
+ case RegExpTest:
+ case GetById:
+ case GetByIdFlush:
+ case GetByOffset:
+ case MultiGetByOffset:
+ case GetDirectPname:
+ case Call:
+ case Construct:
+ case CallVarargs:
+ case ConstructVarargs:
+ case CallForwardVarargs:
+ case ConstructForwardVarargs:
+ case GetGlobalVar:
+ case GetClosureVar:
+ case GetFromArguments: {
+ changed |= setPrediction(node->getHeapPrediction());
+ break;
+ }
+
+ case GetGetterSetterByOffset:
+ case GetExecutable: {
+ changed |= setPrediction(SpecCellOther);
+ break;
+ }
+
+ case GetGetter:
+ case GetSetter:
+ case GetCallee:
+ case NewFunction: {
+ changed |= setPrediction(SpecFunction);
+ break;
+ }
+
+ case GetArgumentCount: {
+ changed |= setPrediction(SpecInt32);
+ break;
+ }
+
+ case StringCharCodeAt: {
+ changed |= setPrediction(SpecInt32);
+ break;
+ }
+
+ case UInt32ToNumber: {
+ // FIXME: Support Int52.
+ // https://bugs.webkit.org/show_bug.cgi?id=125704
+ if (node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(SpecBytecodeNumber);
+ break;
+ }
+
+ case ValueAdd: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (isFullNumberOrBooleanSpeculationExpectingDefined(left)
+ && isFullNumberOrBooleanSpeculationExpectingDefined(right)) {
+ if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32)
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.addShouldSpeculateMachineInt(node))
+ changed |= mergePrediction(SpecInt52);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ } else if (
+ !(left & (SpecFullNumber | SpecBoolean))
+ || !(right & (SpecFullNumber | SpecBoolean))) {
+ // left or right is definitely something other than a number.
+ changed |= mergePrediction(SpecString);
+ } else
+ changed |= mergePrediction(SpecString | SpecInt32 | SpecBytecodeDouble);
+ }
+ break;
+ }
+
+ case ArithAdd:
+ case ArithSub: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32)
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.addShouldSpeculateMachineInt(node))
+ changed |= mergePrediction(SpecInt52);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ }
+ break;
+ }
+
+ case ArithNegate:
+ if (node->child1()->prediction()) {
+ if (m_graph.negateShouldSpeculateInt32(node, m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.negateShouldSpeculateMachineInt(node, m_pass))
+ changed |= mergePrediction(SpecInt52);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction()));
+ }
+ break;
+
+ case ArithMin:
+ case ArithMax: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ }
+ break;
+ }
+
+ case ArithMul: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (m_graph.mulShouldSpeculateInt32(node, m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+ changed |= mergePrediction(SpecInt52);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+ }
+ break;
+ }
+
+ case ArithDiv:
+ case ArithMod: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ if (left && right) {
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(SpecBytecodeDouble);
+ }
+ break;
+ }
+
+ case ArithPow:
+ case ArithSqrt:
+ case ArithFRound:
+ case ArithSin:
+ case ArithCos:
+ case ArithLog: {
+ changed |= setPrediction(SpecBytecodeDouble);
+ break;
+ }
+
+ case ArithRound: {
+ if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, m_pass))
+ changed |= setPrediction(SpecInt32);
+ else
+ changed |= setPrediction(SpecBytecodeDouble);
+ break;
+ }
+
+ case ArithAbs: {
+ SpeculatedType child = node->child1()->prediction();
+ if (isInt32OrBooleanSpeculationForArithmetic(child)
+ && node->canSpeculateInt32(m_pass))
+ changed |= mergePrediction(SpecInt32);
+ else
+ changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
+ break;
+ }
+
+ case LogicalNot:
+ case CompareLess:
+ case CompareLessEq:
+ case CompareGreater:
+ case CompareGreaterEq:
+ case CompareEq:
+ case CompareEqConstant:
+ case CompareStrictEq:
+ case InstanceOf:
+ case IsUndefined:
+ case IsBoolean:
+ case IsNumber:
+ case IsString:
+ case IsObject:
+ case IsObjectOrNull:
+ case IsFunction: {
+ changed |= setPrediction(SpecBoolean);
+ break;
+ }
+
+ case TypeOf: {
+ changed |= setPrediction(SpecStringIdent);
+ break;
+ }
+
+ case GetByVal: {
+ if (!node->child1()->prediction())
+ break;
+
+ ArrayMode arrayMode = node->arrayMode().refine(
+ m_graph, node,
+ node->child1()->prediction(),
+ node->child2()->prediction(),
+ SpecNone);
+
+ switch (arrayMode.type()) {
+ case Array::Int32:
+ if (arrayMode.isOutOfBounds())
+ changed |= mergePrediction(node->getHeapPrediction() | SpecInt32);
+ else
+ changed |= mergePrediction(SpecInt32);
+ break;
+ case Array::Double:
+ if (arrayMode.isOutOfBounds())
+ changed |= mergePrediction(node->getHeapPrediction() | SpecDoubleReal);
+ else
+ changed |= mergePrediction(SpecDoubleReal);
+ break;
+ case Array::Float32Array:
+ case Array::Float64Array:
+ changed |= mergePrediction(SpecFullDouble);
+ break;
+ case Array::Uint32Array:
+ if (isInt32SpeculationForArithmetic(node->getHeapPrediction()))
+ changed |= mergePrediction(SpecInt32);
+ else if (enableInt52())
+ changed |= mergePrediction(SpecMachineInt);
+ else
+ changed |= mergePrediction(SpecInt32 | SpecInt52AsDouble);
+ break;
+ case Array::Int8Array:
+ case Array::Uint8Array:
+ case Array::Int16Array:
+ case Array::Uint16Array:
+ case Array::Int32Array:
+ changed |= mergePrediction(SpecInt32);
+ break;
+ default:
+ changed |= mergePrediction(node->getHeapPrediction());
+ break;
+ }
+ break;
+ }
+
+ case GetButterfly:
+ case GetIndexedPropertyStorage:
+ case AllocatePropertyStorage:
+ case ReallocatePropertyStorage: {
+ changed |= setPrediction(SpecOther);
+ break;
+ }
+
+ case ToThis: {
+ SpeculatedType prediction = node->child1()->prediction();
+ if (prediction) {
+ if (prediction & ~SpecObject) {
+ prediction &= SpecObject;
+ prediction = mergeSpeculations(prediction, SpecObjectOther);
+ }
+ changed |= mergePrediction(prediction);
+ }
+ break;
+ }
+
+ case SkipScope: {
+ changed |= setPrediction(SpecObjectOther);
+ break;
+ }
+
+ case CreateThis:
+ case NewObject: {
+ changed |= setPrediction(SpecFinalObject);
+ break;
+ }
+
+ case NewArray:
+ case NewArrayWithSize:
+ case NewArrayBuffer: {
+ changed |= setPrediction(SpecArray);
+ break;
+ }
+
+ case NewTypedArray: {
+ changed |= setPrediction(speculationFromTypedArrayType(node->typedArrayType()));
+ break;
+ }
+
+ case NewRegexp:
+ case CreateActivation: {
+ changed |= setPrediction(SpecObjectOther);
+ break;
+ }
+
+ case StringFromCharCode: {
+ changed |= setPrediction(SpecString);
+ changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt);
+ break;
+ }
+ case StringCharAt:
+ case CallStringConstructor:
+ case ToString:
+ case MakeRope: {
+ changed |= setPrediction(SpecString);
+ break;
+ }
+
+ case ToPrimitive: {
+ SpeculatedType child = node->child1()->prediction();
+ if (child)
+ changed |= mergePrediction(resultOfToPrimitive(child));
+ break;
+ }
+
+ case NewStringObject: {
+ changed |= setPrediction(SpecStringObject);
+ break;
+ }
+
+ case CreateDirectArguments: {
+ changed |= setPrediction(SpecDirectArguments);
+ break;
+ }
+
+ case CreateScopedArguments: {
+ changed |= setPrediction(SpecScopedArguments);
+ break;
+ }
+
+ case CreateClonedArguments: {
+ changed |= setPrediction(SpecObjectOther);
+ break;
+ }
+
+ case FiatInt52: {
+ RELEASE_ASSERT(enableInt52());
+ changed |= setPrediction(SpecMachineInt);
+ break;
+ }
+
+ case PutByValAlias:
+ case GetArrayLength:
+ case GetTypedArrayByteOffset:
+ case DoubleAsInt32:
+ case GetLocalUnlinked:
+ case CheckArray:
+ case Arrayify:
+ case ArrayifyToStructure:
+ case CheckTierUpInLoop:
+ case CheckTierUpAtReturn:
+ case CheckTierUpAndOSREnter:
+ case CheckTierUpWithNestedTriggerAndOSREnter:
+ case InvalidationPoint:
+ case CheckInBounds:
+ case ValueToInt32:
+ case DoubleRep:
+ case ValueRep:
+ case Int52Rep:
+ case Int52Constant:
+ case Identity:
+ case BooleanToNumber:
+ case PhantomNewObject:
+ case PhantomNewFunction:
+ case PhantomCreateActivation:
+ case PhantomDirectArguments:
+ case PhantomClonedArguments:
+ case GetMyArgumentByVal:
+ case ForwardVarargs:
+ case PutHint:
+ case CheckStructureImmediate:
+ case MaterializeNewObject:
+ case MaterializeCreateActivation:
+ case PutStack:
+ case KillStack:
+ case StoreBarrier:
+ case GetStack: {
+ // This node should never be visible at this stage of compilation. It is
+ // inserted by fixup(), which follows this phase.
+ DFG_CRASH(m_graph, node, "Unexpected node during prediction propagation");
+ break;
+ }
+
+ case Phi:
+ // Phis should not be visible here since we're iterating the all-but-Phi's
+ // part of basic blocks.
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+
+ case Upsilon:
+ // These don't get inserted until we go into SSA.
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+
+ case GetScope:
+ changed |= setPrediction(SpecObjectOther);
+ break;
+
+ case In:
+ changed |= setPrediction(SpecBoolean);
+ break;
+
+ case GetEnumerableLength: {
+ changed |= setPrediction(SpecInt32);
+ break;
+ }
+ case HasGenericProperty:
+ case HasStructureProperty:
+ case HasIndexedProperty: {
+ changed |= setPrediction(SpecBoolean);
+ break;
+ }
+ case GetPropertyEnumerator: {
+ changed |= setPrediction(SpecCell);
+ break;
+ }
+ case GetEnumeratorStructurePname: {
+ changed |= setPrediction(SpecCell | SpecOther);
+ break;
+ }
+ case GetEnumeratorGenericPname: {
+ changed |= setPrediction(SpecCell | SpecOther);
+ break;
+ }
+ case ToIndexString: {
+ changed |= setPrediction(SpecString);
+ break;
+ }
+
+#ifndef NDEBUG
+ // These get ignored because they don't return anything.
+ case PutByValDirect:
+ case PutByVal:
+ case PutClosureVar:
+ case PutToArguments:
+ case Return:
+ case Throw:
+ case PutById:
+ case PutByIdFlush:
+ case PutByIdDirect:
+ case PutByOffset:
+ case MultiPutByOffset:
+ case DFG::Jump:
+ case Branch:
+ case Switch:
+ case Breakpoint:
+ case ProfileWillCall:
+ case ProfileDidCall:
+ case ProfileType:
+ case ProfileControlFlow:
+ case CheckHasInstance:
+ case ThrowReferenceError:
+ case ForceOSRExit:
+ case SetArgument:
+ case CheckStructure:
+ case CheckCell:
+ case CheckNotEmpty:
+ case CheckIdent:
+ case CheckBadCell:
+ case PutStructure:
+ case VarInjectionWatchpoint:
+ case Phantom:
+ case Check:
+ case PutGlobalVar:
+ case CheckWatchdogTimer:
+ case Unreachable:
+ case LoopHint:
+ case NotifyWrite:
+ case ConstantStoragePointer:
+ case MovHint:
+ case ZombieHint:
+ case LoadVarargs:
+ break;
+
+ // This gets ignored because it only pretends to produce a value.
+ case BottomValue:
+ break;
+
+ // This gets ignored because it already has a prediction.
+ case ExtractOSREntryLocal:
+ break;
+
+ // These gets ignored because it doesn't do anything.
+ case CountExecution:
+ case PhantomLocal:
+ case Flush:
+ break;
+
+ case LastNodeType:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+#else
+ default:
+ break;
+#endif
+ }
+
+ m_changed |= changed;
+ }
+
+ void propagateForward()
+ {
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = 0; i < block->size(); ++i) {
+ m_currentNode = block->at(i);
+ propagate(m_currentNode);
+ }
+ }
+ }
+
+ void propagateBackward()
+ {
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = block->size(); i--;) {
+ m_currentNode = block->at(i);
+ propagate(m_currentNode);
+ }
+ }
+ }
+
+ void doDoubleVoting(Node* node, float weight)
+ {
+ // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate
+ // that we actually don't know they weight. Assume that they execute once. This turns
+ // out to be an OK assumption since the pre-header doesn't have any meaningful code.
+ if (weight != weight)
+ weight = 1;
+
+ switch (node->op()) {
+ case ValueAdd:
+ case ArithAdd:
+ case ArithSub: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ DoubleBallot ballot;
+
+ if (isFullNumberSpeculation(left)
+ && isFullNumberSpeculation(right)
+ && !m_graph.addShouldSpeculateInt32(node, m_pass)
+ && !m_graph.addShouldSpeculateMachineInt(node))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
+
+ m_graph.voteNode(node->child1(), ballot, weight);
+ m_graph.voteNode(node->child2(), ballot, weight);
+ break;
+ }
+
+ case ArithMul: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ DoubleBallot ballot;
+
+ if (isFullNumberSpeculation(left)
+ && isFullNumberSpeculation(right)
+ && !m_graph.mulShouldSpeculateInt32(node, m_pass)
+ && !m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
+
+ m_graph.voteNode(node->child1(), ballot, weight);
+ m_graph.voteNode(node->child2(), ballot, weight);
+ break;
+ }
+
+ case ArithMin:
+ case ArithMax:
+ case ArithMod:
+ case ArithDiv: {
+ SpeculatedType left = node->child1()->prediction();
+ SpeculatedType right = node->child2()->prediction();
+
+ DoubleBallot ballot;
+
+ if (isFullNumberSpeculation(left)
+ && isFullNumberSpeculation(right)
+ && !(Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInt32(m_pass)))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
+
+ m_graph.voteNode(node->child1(), ballot, weight);
+ m_graph.voteNode(node->child2(), ballot, weight);
+ break;
+ }
+
+ case ArithAbs:
+ DoubleBallot ballot;
+ if (node->child1()->shouldSpeculateNumber()
+ && !(node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(m_pass)))
+ ballot = VoteDouble;
+ else
+ ballot = VoteValue;
+
+ m_graph.voteNode(node->child1(), ballot, weight);
+ break;
+
+ case ArithSqrt:
+ case ArithCos:
+ case ArithSin:
+ case ArithLog:
+ if (node->child1()->shouldSpeculateNumber())
+ m_graph.voteNode(node->child1(), VoteDouble, weight);
+ else
+ m_graph.voteNode(node->child1(), VoteValue, weight);
+ break;
+
+ case SetLocal: {
+ SpeculatedType prediction = node->child1()->prediction();
+ if (isDoubleSpeculation(prediction))
+ node->variableAccessData()->vote(VoteDouble, weight);
+ else if (
+ !isFullNumberSpeculation(prediction)
+ || isInt32Speculation(prediction) || isMachineIntSpeculation(prediction))
+ node->variableAccessData()->vote(VoteValue, weight);
+ break;
+ }
+
+ case PutByValDirect:
+ case PutByVal:
+ case PutByValAlias: {
+ Edge child1 = m_graph.varArgChild(node, 0);
+ Edge child2 = m_graph.varArgChild(node, 1);
+ Edge child3 = m_graph.varArgChild(node, 2);
+ m_graph.voteNode(child1, VoteValue, weight);
+ m_graph.voteNode(child2, VoteValue, weight);
+ switch (node->arrayMode().type()) {
+ case Array::Double:
+ m_graph.voteNode(child3, VoteDouble, weight);
+ break;
+ default:
+ m_graph.voteNode(child3, VoteValue, weight);
+ break;
+ }
+ break;
+ }
+
+ case MovHint:
+ // Ignore these since they have no effect on in-DFG execution.
+ break;
+
+ default:
+ m_graph.voteChildren(node, VoteValue, weight);
+ break;
+ }
+ }
+
+ void doRoundOfDoubleVoting()
+ {
+ for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
+ m_graph.m_variableAccessData[i].find()->clearVotes();
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ ASSERT(block->isReachable);
+ for (unsigned i = 0; i < block->size(); ++i) {
+ m_currentNode = block->at(i);
+ doDoubleVoting(m_currentNode, block->executionCount);
+ }
+ }
+ for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
+ VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
+ if (!variableAccessData->isRoot())
+ continue;
+ m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
+ }
+ propagateThroughArgumentPositions();
+ for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
+ VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
+ if (!variableAccessData->isRoot())
+ continue;
+ m_changed |= variableAccessData->makePredictionForDoubleFormat();
+ }
+ }
+
+ void propagateThroughArgumentPositions()
+ {
+ for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i)
+ m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness();
+ }
+
+ Node* m_currentNode;
+ bool m_changed;
+ PredictionPass m_pass; // We use different logic for considering predictions depending on how far along we are in propagation.
+};
+
+bool performPredictionPropagation(Graph& graph)
+{
+ SamplingRegion samplingRegion("DFG Prediction Propagation Phase");
+ return runPhase<PredictionPropagationPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+