DFG should not change its mind about what type speculations a node does, by encoding the checks in the NodeType, UseKind, and ArrayMode
https://bugs.webkit.org/show_bug.cgi?id=109371
Reviewed by Oliver Hunt.
FixupPhase now locks in the speculations that each node will do. The DFG then
remembers those speculations, and doesn't change its mind about them even if the
graph is transformed - for example if a node's child is repointed to a different
node as part of CSE, CFG simplification, or folding. Each node ensures that it
executes the speculations promised by its edges. This is true even for Phantom
nodes.
This still leaves some craziness on the table for future work, like the
elimination of speculating SetLocal's due to CFG simplification
(webkit.org/b/109388) and elimination of nodes via DCE (webkit.org/b/109389).
In all, this allows for a huge simplification of the DFG. Instead of having to
execute the right speculation heuristic each time you want to decide what a node
does (for example Node::shouldSpeculateInteger(child1, child2) &&
node->canSpeculateInteger()), you just ask for the use kinds of its children
(typically node->binaryUseKind() == Int32Use). Because the use kinds are
discrete, you can often just switch over them. This makes many parts of the code
more clear than they were before.
Having UseKinds describe the speculations being performed also makes it far
easier to perform analyses that need to know what speculations are done. This is
so far only used to simplify large parts of the CFA.
To have a larger vocabulary of UseKinds, this also changes the node allocator to
be able to round up Node sizes to the nearest multiple of 16.
This appears to be neutral on benchmarks, except for some goofy speed-ups, like
8% on Octane/box2d.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::startExecuting):
(DFG):
(JSC::DFG::AbstractState::executeEdges):
(JSC::DFG::AbstractState::verifyEdge):
(JSC::DFG::AbstractState::verifyEdges):
(JSC::DFG::AbstractState::executeEffects):
(JSC::DFG::AbstractState::execute):
* dfg/DFGAbstractState.h:
(AbstractState):
(JSC::DFG::AbstractState::filterEdgeByUse):
(JSC::DFG::AbstractState::filterByType):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::filter):
* dfg/DFGAdjacencyList.h:
(JSC::DFG::AdjacencyList::AdjacencyList):
(JSC::DFG::AdjacencyList::child):
(JSC::DFG::AdjacencyList::setChild):
(JSC::DFG::AdjacencyList::reset):
(JSC::DFG::AdjacencyList::firstChild):
(JSC::DFG::AdjacencyList::setFirstChild):
(JSC::DFG::AdjacencyList::numChildren):
(JSC::DFG::AdjacencyList::setNumChildren):
(AdjacencyList):
* dfg/DFGAllocator.h:
(DFG):
(Allocator):
(JSC::DFG::Allocator::cellSize):
(JSC::DFG::Allocator::Region::headerSize):
(JSC::DFG::Allocator::Region::numberOfThingsPerRegion):
(JSC::DFG::Allocator::Region::payloadSize):
(JSC::DFG::Allocator::Region::payloadBegin):
(JSC::DFG::Allocator::Region::payloadEnd):
(JSC::DFG::Allocator::Region::isInThisRegion):
(JSC::DFG::::Allocator):
(JSC::DFG::::~Allocator):
(JSC::DFG::::allocate):
(JSC::DFG::::free):
(JSC::DFG::::freeAll):
(JSC::DFG::::reset):
(JSC::DFG::::indexOf):
(JSC::DFG::::allocatorOf):
(JSC::DFG::::bumpAllocate):
(JSC::DFG::::freeListAllocate):
(JSC::DFG::::allocateSlow):
(JSC::DFG::::freeRegionsStartingAt):
(JSC::DFG::::startBumpingIn):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addToGraph):
(JSC::DFG::ByteCodeParser::handleMinMax):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::setLocalStoreElimination):
(JSC::DFG::CSEPhase::eliminateIrrelevantPhantomChildren):
(JSC::DFG::CSEPhase::setReplacement):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCommon.h:
(DFG):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGEdge.cpp:
(JSC::DFG::Edge::dump):
* dfg/DFGEdge.h:
(JSC::DFG::Edge::useKindUnchecked):
(JSC::DFG::Edge::useKind):
(JSC::DFG::Edge::shift):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::run):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::checkArray):
(JSC::DFG::FixupPhase::blessArrayOperation):
(JSC::DFG::FixupPhase::fixIntEdge):
(JSC::DFG::FixupPhase::fixDoubleEdge):
(JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
(FixupPhase):
(JSC::DFG::FixupPhase::truncateConstantToInt32):
(JSC::DFG::FixupPhase::truncateConstantsIfNecessary):
(JSC::DFG::FixupPhase::attemptToMakeIntegerAdd):
* dfg/DFGGraph.cpp:
(DFG):
(JSC::DFG::Graph::refChildren):
(JSC::DFG::Graph::derefChildren):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::ref):
(JSC::DFG::Graph::deref):
(JSC::DFG::Graph::performSubstitution):
(JSC::DFG::Graph::isPredictedNumerical):
(JSC::DFG::Graph::addImmediateShouldSpeculateInteger):
(DFG):
* dfg/DFGNode.h:
(JSC::DFG::Node::Node):
(JSC::DFG::Node::convertToGetByOffset):
(JSC::DFG::Node::convertToPutByOffset):
(JSC::DFG::Node::willHaveCodeGenOrOSR):
(JSC::DFG::Node::child1):
(JSC::DFG::Node::child2):
(JSC::DFG::Node::child3):
(JSC::DFG::Node::binaryUseKind):
(Node):
(JSC::DFG::Node::isBinaryUseKind):
* dfg/DFGNodeAllocator.h:
(DFG):
* dfg/DFGNodeFlags.cpp:
(JSC::DFG::nodeFlagsAsString):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculationCheck):
(DFG):
(JSC::DFG::SpeculativeJIT::speculationWatchpoint):
(JSC::DFG::SpeculativeJIT::forwardSpeculationCheck):
(JSC::DFG::SpeculativeJIT::terminateSpeculativeExecution):
(JSC::DFG::SpeculativeJIT::typeCheck):
(JSC::DFG::SpeculativeJIT::forwardTypeCheck):
(JSC::DFG::SpeculativeJIT::fillStorage):
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
(JSC::DFG::SpeculativeJIT::compileValueToInt32):
(JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
(JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
(JSC::DFG::SpeculativeJIT::compileInstanceOf):
(JSC::DFG::SpeculativeJIT::compileAdd):
(JSC::DFG::SpeculativeJIT::compileArithSub):
(JSC::DFG::SpeculativeJIT::compileArithNegate):
(JSC::DFG::SpeculativeJIT::compileArithMul):
(JSC::DFG::SpeculativeJIT::compileArithMod):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::speculateInt32):
(JSC::DFG::SpeculativeJIT::speculateNumber):
(JSC::DFG::SpeculativeJIT::speculateRealNumber):
(JSC::DFG::SpeculativeJIT::speculateBoolean):
(JSC::DFG::SpeculativeJIT::speculateCell):
(JSC::DFG::SpeculativeJIT::speculateObject):
(JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
(JSC::DFG::SpeculativeJIT::speculateString):
(JSC::DFG::SpeculativeJIT::speculateNotCell):
(JSC::DFG::SpeculativeJIT::speculateOther):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::valueOfNumberConstant):
(JSC::DFG::SpeculativeJIT::needsTypeCheck):
(JSC::DFG::IntegerOperand::IntegerOperand):
(JSC::DFG::IntegerOperand::edge):
(IntegerOperand):
(JSC::DFG::IntegerOperand::node):
(JSC::DFG::IntegerOperand::gpr):
(JSC::DFG::IntegerOperand::use):
(JSC::DFG::JSValueOperand::JSValueOperand):
(JSValueOperand):
(JSC::DFG::JSValueOperand::edge):
(JSC::DFG::JSValueOperand::node):
(JSC::DFG::JSValueOperand::gpr):
(JSC::DFG::JSValueOperand::fill):
(JSC::DFG::JSValueOperand::use):
(JSC::DFG::StorageOperand::StorageOperand):
(JSC::DFG::StorageOperand::edge):
(StorageOperand):
(JSC::DFG::StorageOperand::node):
(JSC::DFG::StorageOperand::gpr):
(JSC::DFG::StorageOperand::use):
(JSC::DFG::SpeculateIntegerOperand::SpeculateIntegerOperand):
(SpeculateIntegerOperand):
(JSC::DFG::SpeculateIntegerOperand::edge):
(JSC::DFG::SpeculateIntegerOperand::node):
(JSC::DFG::SpeculateIntegerOperand::gpr):
(JSC::DFG::SpeculateIntegerOperand::use):
(JSC::DFG::SpeculateStrictInt32Operand::SpeculateStrictInt32Operand):
(SpeculateStrictInt32Operand):
(JSC::DFG::SpeculateStrictInt32Operand::edge):
(JSC::DFG::SpeculateStrictInt32Operand::node):
(JSC::DFG::SpeculateStrictInt32Operand::gpr):
(JSC::DFG::SpeculateStrictInt32Operand::use):
(JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand):
(SpeculateDoubleOperand):
(JSC::DFG::SpeculateDoubleOperand::edge):
(JSC::DFG::SpeculateDoubleOperand::node):
(JSC::DFG::SpeculateDoubleOperand::fpr):
(JSC::DFG::SpeculateDoubleOperand::use):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
(SpeculateCellOperand):
(JSC::DFG::SpeculateCellOperand::edge):
(JSC::DFG::SpeculateCellOperand::node):
(JSC::DFG::SpeculateCellOperand::gpr):
(JSC::DFG::SpeculateCellOperand::use):
(JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):
(JSC::DFG::SpeculateBooleanOperand::edge):
(SpeculateBooleanOperand):
(JSC::DFG::SpeculateBooleanOperand::node):
(JSC::DFG::SpeculateBooleanOperand::gpr):
(JSC::DFG::SpeculateBooleanOperand::use):
(DFG):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::fillInteger):
(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt):
(JSC::DFG::SpeculativeJIT::fillSpeculateIntStrict):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::fillInteger):
(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt):
(JSC::DFG::SpeculativeJIT::fillSpeculateIntStrict):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compileObjectEquality):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):
* dfg/DFGUseKind.cpp: Added.
(WTF):
(WTF::printInternal):
* dfg/DFGUseKind.h: Added.
(DFG):
(JSC::DFG::typeFilterFor):
(JSC::DFG::isNumerical):
(WTF):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::reportValidationContext):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@143654 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index b388b7a..efde5d1 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -45,6 +45,9 @@
bool run()
{
+ ASSERT(m_graph.m_fixpointState == BeforeFixpoint);
+ ASSERT(m_graph.m_form == ThreadedCPS);
+
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
fixupBlock(m_graph.m_blocks[blockIndex].get());
return true;
@@ -76,50 +79,262 @@
#endif
switch (op) {
- case GetById: {
- if (m_graph.m_fixpointState > BeforeFixpoint)
+ case SetLocal: {
+ VariableAccessData* variable = node->variableAccessData();
+
+ if (variable->isCaptured()
+ || m_graph.isCreatedThisArgument(variable->local()))
break;
- if (!isInt32Speculation(node->prediction()))
+ if (variable->shouldUseDoubleFormat()) {
+ fixDoubleEdge(node->child1(), NumberUse, ForwardSpeculation);
break;
- if (codeBlock()->identifier(node->identifierNumber()) != globalData().propertyNames->length)
+ }
+
+ SpeculatedType predictedType = variable->argumentAwarePrediction();
+ if (isInt32Speculation(predictedType))
+ node->child1().setUseKind(Int32Use);
+ else if (isCellSpeculation(predictedType))
+ node->child1().setUseKind(CellUse);
+ else if (isBooleanSpeculation(predictedType))
+ node->child1().setUseKind(BooleanUse);
+ break;
+ }
+
+ case BitAnd:
+ case BitOr:
+ case BitXor:
+ case BitRShift:
+ case BitLShift:
+ case BitURShift: {
+ fixIntEdge(node->child1());
+ fixIntEdge(node->child2());
+ break;
+ }
+
+ case UInt32ToNumber: {
+ node->child1().setUseKind(KnownInt32Use);
+ break;
+ }
+
+ case DoubleAsInt32: {
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ case ValueToInt32: {
+ if (node->child1()->shouldSpeculateInteger()) {
+ node->child1().setUseKind(Int32Use);
break;
- ArrayProfile* arrayProfile =
- m_graph.baselineCodeBlockFor(node->codeOrigin)->getArrayProfile(
- node->codeOrigin.bytecodeIndex);
- ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
- if (arrayProfile) {
- arrayProfile->computeUpdatedPrediction(m_graph.baselineCodeBlockFor(node->codeOrigin));
- arrayMode = ArrayMode::fromObserved(arrayProfile, Array::Read, false);
- arrayMode = arrayMode.refine(
- node->child1()->prediction(), node->prediction());
- if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
- m_insertionSet.insertNode(
- m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure,
- node->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
- node->child1().node());
+ }
+
+ if (node->child1()->shouldSpeculateNumber()) {
+ node->child1().setUseKind(NumberUse);
+ break;
+ }
+
+ if (node->child1()->shouldSpeculateBoolean()) {
+ node->child1().setUseKind(BooleanUse);
+ break;
+ }
+
+ node->child1().setUseKind(NotCellUse);
+ break;
+ }
+
+ case Int32ToDouble: {
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ case ValueAdd: {
+ if (attemptToMakeIntegerAdd(node))
+ break;
+ if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
+ break;
+ }
+ break;
+ }
+
+ case ArithAdd:
+ case ArithSub: {
+ if (attemptToMakeIntegerAdd(node))
+ break;
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
+ break;
+ }
+
+ case ArithNegate: {
+ if (m_graph.negateShouldSpeculateInteger(node)) {
+ node->child1().setUseKind(Int32Use);
+ break;
+ }
+ fixDoubleEdge(node->child1());
+ break;
+ }
+
+ case ArithMul: {
+ if (m_graph.mulShouldSpeculateInteger(node)) {
+ node->child1().setUseKind(Int32Use);
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
+ break;
+ }
+
+ case ArithDiv: {
+ if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInteger()) {
+ if (isX86() || isARMv7s()) {
+ node->child1().setUseKind(Int32Use);
+ node->child2().setUseKind(Int32Use);
+ break;
}
- } else
- arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
- if (!arrayMode.supportsLength())
+ injectInt32ToDoubleNode(node->child1());
+ injectInt32ToDoubleNode(node->child2());
+
+ // We don't need to do ref'ing on the children because we're stealing them from
+ // the original division.
+ Node* newDivision = m_insertionSet.insertNode(
+ m_indexInBlock, DontRefChildren, RefNode, SpecDouble, *node);
+
+ node->setOp(DoubleAsInt32);
+ node->children.initialize(Edge(newDivision, KnownNumberUse), Edge(), Edge());
break;
- node->setOp(GetArrayLength);
- ASSERT(node->flags() & NodeMustGenerate);
- node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
- m_graph.deref(node);
- node->setArrayMode(arrayMode);
-
- Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage, node->shouldGenerate());
- if (!storage)
- break;
-
- node->children.child2() = Edge(storage);
+ }
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
break;
}
- case GetIndexedPropertyStorage: {
- ASSERT(node->arrayMode().canCSEStorage());
+
+ case ArithMin:
+ case ArithMax:
+ case ArithMod: {
+ if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInteger()) {
+ node->child1().setUseKind(Int32Use);
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
break;
}
+
+ case ArithAbs: {
+ if (node->child1()->shouldSpeculateIntegerForArithmetic()
+ && node->canSpeculateInteger()) {
+ node->child1().setUseKind(Int32Use);
+ break;
+ }
+ fixDoubleEdge(node->child1());
+ break;
+ }
+
+ case ArithSqrt: {
+ fixDoubleEdge(node->child1());
+ break;
+ }
+
+ case LogicalNot: {
+ if (node->child1()->shouldSpeculateBoolean())
+ node->child1().setUseKind(BooleanUse);
+ else if (node->child1()->shouldSpeculateObjectOrOther())
+ node->child1().setUseKind(ObjectOrOtherUse);
+ else if (node->child1()->shouldSpeculateInteger())
+ node->child1().setUseKind(Int32Use);
+ else if (node->child1()->shouldSpeculateNumber())
+ fixDoubleEdge(node->child1());
+ break;
+ }
+
+ case TypeOf: {
+ if (node->child1()->shouldSpeculateString())
+ node->child1().setUseKind(StringUse);
+ else if (node->child1()->shouldSpeculateCell())
+ node->child1().setUseKind(CellUse);
+ break;
+ }
+
+ case CompareEq:
+ case CompareEqConstant:
+ case CompareLess:
+ case CompareLessEq:
+ case CompareGreater:
+ case CompareGreaterEq: {
+ if (node->op() == CompareEqConstant)
+ break;
+ if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
+ node->child1().setUseKind(Int32Use);
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+ if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
+ break;
+ }
+ if (node->op() != CompareEq)
+ break;
+ if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString())
+ break;
+ if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+ node->child1().setUseKind(ObjectUse);
+ node->child2().setUseKind(ObjectUse);
+ break;
+ }
+ if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
+ node->child1().setUseKind(ObjectUse);
+ node->child2().setUseKind(ObjectOrOtherUse);
+ break;
+ }
+ if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
+ node->child1().setUseKind(ObjectOrOtherUse);
+ node->child2().setUseKind(ObjectUse);
+ break;
+ }
+ break;
+ }
+
+ case CompareStrictEq:
+ case CompareStrictEqConstant: {
+ if (node->op() == CompareStrictEqConstant)
+ break;
+ if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
+ node->child1().setUseKind(Int32Use);
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+ if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
+ fixDoubleEdge(node->child1());
+ fixDoubleEdge(node->child2());
+ break;
+ }
+ if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString())
+ break;
+ if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+ node->child1().setUseKind(ObjectUse);
+ node->child2().setUseKind(ObjectUse);
+ break;
+ }
+ break;
+ }
+
+ case StringCharAt:
+ case StringCharCodeAt: {
+ // Currently we have no good way of refining these.
+ ASSERT(node->arrayMode() == ArrayMode(Array::String));
+ blessArrayOperation(node->child1(), node->child2(), node->child3());
+ node->child1().setUseKind(KnownCellUse);
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+
case GetByVal: {
node->setArrayMode(
node->arrayMode().refine(
@@ -127,7 +342,7 @@
node->child2()->prediction(),
SpecNone, node->flags()));
- blessArrayOperation(node->child1(), node->child2(), 2);
+ blessArrayOperation(node->child1(), node->child2(), node->child3());
ArrayMode arrayMode = node->arrayMode();
if (arrayMode.type() == Array::Double
@@ -138,13 +353,92 @@
&& !(node->flags() & NodeUsedAsOther))
node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+ switch (node->arrayMode().type()) {
+ case Array::SelectUsingPredictions:
+ case Array::Unprofiled:
+ case Array::Undecided:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ case Array::Generic:
+#if USE(JSVALUE32_64)
+ node->child1().setUseKind(CellUse); // Speculating cell due to register pressure on 32-bit.
+#endif
+ break;
+ case Array::ForceExit:
+ break;
+ default:
+ node->child1().setUseKind(KnownCellUse);
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+
break;
}
- case StringCharAt:
- case StringCharCodeAt: {
- // Currently we have no good way of refining these.
- ASSERT(node->arrayMode() == ArrayMode(Array::String));
- blessArrayOperation(node->child1(), node->child2(), 2);
+
+ 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);
+
+ node->setArrayMode(
+ node->arrayMode().refine(
+ child1->prediction(),
+ child2->prediction(),
+ child3->prediction()));
+
+ blessArrayOperation(child1, child2, m_graph.varArgChild(node, 3));
+
+ switch (node->arrayMode().modeForPut().type()) {
+ case Array::SelectUsingPredictions:
+ case Array::Unprofiled:
+ case Array::Undecided:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ case Array::ForceExit:
+ case Array::Generic:
+#if USE(JSVALUE32_64)
+ // Due to register pressure on 32-bit, we speculate cell and
+ // ignore the base-is-not-cell case entirely by letting the
+ // baseline JIT handle it.
+ child1.setUseKind(CellUse);
+#endif
+ break;
+ case Array::Int32:
+ child1.setUseKind(KnownCellUse);
+ child2.setUseKind(Int32Use);
+ child3.setUseKind(Int32Use);
+ break;
+ case Array::Double:
+ child1.setUseKind(KnownCellUse);
+ child2.setUseKind(Int32Use);
+ fixDoubleEdge(child3, RealNumberUse);
+ break;
+ case Array::Int8Array:
+ case Array::Int16Array:
+ case Array::Int32Array:
+ case Array::Uint8Array:
+ case Array::Uint8ClampedArray:
+ case Array::Uint16Array:
+ case Array::Uint32Array:
+ child1.setUseKind(KnownCellUse);
+ child2.setUseKind(Int32Use);
+ if (child3->shouldSpeculateInteger())
+ child3.setUseKind(Int32Use);
+ else
+ fixDoubleEdge(child3);
+ break;
+ case Array::Float32Array:
+ case Array::Float64Array:
+ child1.setUseKind(KnownCellUse);
+ child2.setUseKind(Int32Use);
+ fixDoubleEdge(child3);
+ break;
+ default:
+ child1.setUseKind(KnownCellUse);
+ child2.setUseKind(Int32Use);
+ break;
+ }
break;
}
@@ -163,11 +457,15 @@
node->child1()->prediction() & SpecCell,
SpecInt32,
node->child2()->prediction()));
- blessArrayOperation(node->child1(), Edge(), 2);
+ blessArrayOperation(node->child1(), Edge(), node->child3());
+ node->child1().setUseKind(KnownCellUse);
switch (node->arrayMode().type()) {
+ case Array::Int32:
+ node->child2().setUseKind(Int32Use);
+ break;
case Array::Double:
- fixDoubleEdge(1);
+ fixDoubleEdge(node->child2());
break;
default:
break;
@@ -176,49 +474,27 @@
}
case ArrayPop: {
- blessArrayOperation(node->child1(), Edge(), 1);
+ blessArrayOperation(node->child1(), Edge(), node->child2());
+ node->child1().setUseKind(KnownCellUse);
break;
}
- case BitAnd:
- case BitOr:
- case BitXor:
- case BitRShift:
- case BitLShift:
- case BitURShift: {
- fixIntEdge(node->children.child1());
- fixIntEdge(node->children.child2());
- break;
- }
-
- case CompareEq:
- case CompareLess:
- case CompareLessEq:
- case CompareGreater:
- case CompareGreaterEq:
- case CompareStrictEq: {
- if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node()))
- break;
- if (!Node::shouldSpeculateNumber(node->child1().node(), node->child2().node()))
- break;
- fixDoubleEdge(0);
- fixDoubleEdge(1);
- break;
- }
-
- case LogicalNot: {
- if (node->child1()->shouldSpeculateInteger())
- break;
- if (!node->child1()->shouldSpeculateNumber())
- break;
- fixDoubleEdge(0);
+ case RegExpExec:
+ case RegExpTest: {
+ node->child1().setUseKind(CellUse);
+ node->child2().setUseKind(CellUse);
break;
}
case Branch: {
- if (!node->child1()->shouldSpeculateInteger()
- && node->child1()->shouldSpeculateNumber())
- fixDoubleEdge(0);
+ if (node->child1()->shouldSpeculateBoolean())
+ node->child1().setUseKind(BooleanUse);
+ else if (node->child1()->shouldSpeculateObjectOrOther())
+ node->child1().setUseKind(ObjectOrOtherUse);
+ else if (node->child1()->shouldSpeculateInteger())
+ node->child1().setUseKind(Int32Use);
+ else if (node->child1()->shouldSpeculateNumber())
+ fixDoubleEdge(node->child1());
Node* logicalNot = node->child1().node();
if (logicalNot->op() == LogicalNot
@@ -261,131 +537,11 @@
break;
}
- case SetLocal: {
- if (node->variableAccessData()->isCaptured())
- break;
- if (!node->variableAccessData()->shouldUseDoubleFormat())
- break;
- fixDoubleEdge(0, ForwardSpeculation);
- break;
- }
-
- case ArithAdd:
- case ValueAdd: {
- if (m_graph.addShouldSpeculateInteger(node))
- break;
- if (!Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node()))
- break;
- fixDoubleEdge(0);
- fixDoubleEdge(1);
- break;
- }
-
- case ArithSub: {
- if (m_graph.addShouldSpeculateInteger(node)
- && node->canSpeculateInteger())
- break;
- fixDoubleEdge(0);
- fixDoubleEdge(1);
- break;
- }
-
- case ArithNegate: {
- if (m_graph.negateShouldSpeculateInteger(node))
- break;
- fixDoubleEdge(0);
- break;
- }
-
- case ArithMin:
- case ArithMax:
- case ArithMod: {
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger())
- break;
- fixDoubleEdge(0);
- fixDoubleEdge(1);
- break;
- }
-
- case ArithMul: {
- if (m_graph.mulShouldSpeculateInteger(node))
- break;
- fixDoubleEdge(0);
- fixDoubleEdge(1);
- break;
- }
-
- case ArithDiv: {
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
- if (isX86() || isARMv7s())
- break;
- injectInt32ToDoubleNode(0);
- injectInt32ToDoubleNode(1);
-
- // We don't need to do ref'ing on the children because we're stealing them from
- // the original division.
- Node* newDivision = m_insertionSet.insertNode(
- m_indexInBlock, DontRefChildren, RefNode, SpecDouble, *node);
-
- node->setOp(DoubleAsInt32);
- node->children.initialize(Edge(newDivision, DoubleUse), Edge(), Edge());
- break;
- }
- fixDoubleEdge(0);
- fixDoubleEdge(1);
- break;
- }
-
- case ArithAbs: {
- if (node->child1()->shouldSpeculateIntegerForArithmetic()
- && node->canSpeculateInteger())
- break;
- fixDoubleEdge(0);
- break;
- }
-
- case ArithSqrt: {
- fixDoubleEdge(0);
- 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);
-
- node->setArrayMode(
- node->arrayMode().refine(
- child1->prediction(),
- child2->prediction(),
- child3->prediction()));
-
- blessArrayOperation(child1, child2, 3);
-
- switch (node->arrayMode().modeForPut().type()) {
- case Array::Double:
- fixDoubleEdge(2);
- break;
- case Array::Int8Array:
- case Array::Int16Array:
- case Array::Int32Array:
- case Array::Uint8Array:
- case Array::Uint8ClampedArray:
- case Array::Uint16Array:
- case Array::Uint32Array:
- if (!child3->shouldSpeculateInteger())
- fixDoubleEdge(2);
- break;
- case Array::Float32Array:
- case Array::Float64Array:
- fixDoubleEdge(2);
- break;
- default:
- break;
- }
+ case ToPrimitive: {
+ if (node->child1()->shouldSpeculateInteger())
+ node->child1().setUseKind(Int32Use);
+ // FIXME: Add string speculation here.
+ // https://bugs.webkit.org/show_bug.cgi?id=110175
break;
}
@@ -395,15 +551,252 @@
leastUpperBoundOfIndexingTypeAndType(
node->indexingType(), m_graph.varArgChild(node, i)->prediction()));
}
- if (node->indexingType() == ArrayWithDouble) {
- for (unsigned i = m_graph.varArgNumChildren(node); i--;)
- fixDoubleEdge(i);
+ switch (node->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ CRASH();
+ break;
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ if (node->numChildren()) {
+ // This will only happen if the children have no type predictions. We
+ // would have already exited by now, but insert a forced exit just to
+ // be safe.
+ m_insertionSet.insertNode(
+ m_indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit,
+ node->codeOrigin);
+ }
+ break;
+ case ALL_INT32_INDEXING_TYPES:
+ for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
+ m_graph.m_varArgChildren[node->firstChild() + operandIndex].setUseKind(Int32Use);
+ break;
+ case ALL_DOUBLE_INDEXING_TYPES:
+ for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
+ m_graph.m_varArgChildren[node->firstChild() + operandIndex].setUseKind(RealNumberUse);
+ break;
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ break;
+ default:
+ CRASH();
+ break;
}
break;
}
+ case NewArrayWithSize: {
+ node->child1().setUseKind(Int32Use);
+ break;
+ }
+
+ case ConvertThis: {
+ // FIXME: Use Phantom(type check) and Identity instead.
+ // https://bugs.webkit.org/show_bug.cgi?id=110395
+ if (isOtherSpeculation(node->child1()->prediction()))
+ node->child1().setUseKind(OtherUse);
+ else if (isObjectSpeculation(node->child1()->prediction()))
+ node->child1().setUseKind(ObjectUse);
+ break;
+ }
+
+ case CreateThis: {
+ node->child1().setUseKind(CellUse);
+ break;
+ }
+
+ case GetMyArgumentByVal:
+ case GetMyArgumentByValSafe: {
+ node->child1().setUseKind(Int32Use);
+ break;
+ }
+
+ case GetScopeRegisters:
+ case PutScopedVar:
+ case SkipTopScope:
+ case SkipScope:
+ case SetCallee:
+ case SetMyScope:
+ case PutStructure:
+ case AllocatePropertyStorage:
+ case ReallocatePropertyStorage:
+ case GetScope:
+ case GetButterfly: {
+ node->child1().setUseKind(KnownCellUse);
+ break;
+ }
+
+ case GetById: {
+ if (!node->child1()->shouldSpeculateCell())
+ break;
+ node->child1().setUseKind(CellUse);
+ if (!isInt32Speculation(node->prediction()))
+ break;
+ if (codeBlock()->identifier(node->identifierNumber()) != globalData().propertyNames->length)
+ break;
+ ArrayProfile* arrayProfile =
+ m_graph.baselineCodeBlockFor(node->codeOrigin)->getArrayProfile(
+ node->codeOrigin.bytecodeIndex);
+ ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
+ if (arrayProfile) {
+ arrayProfile->computeUpdatedPrediction(m_graph.baselineCodeBlockFor(node->codeOrigin));
+ arrayMode = ArrayMode::fromObserved(arrayProfile, Array::Read, false);
+ arrayMode = arrayMode.refine(
+ node->child1()->prediction(), node->prediction());
+ if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
+ m_insertionSet.insertNode(
+ m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure,
+ node->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
+ node->child1());
+ }
+ } else
+ arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
+ if (!arrayMode.supportsLength())
+ break;
+ node->setOp(GetArrayLength);
+ ASSERT(node->flags() & NodeMustGenerate);
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
+ node->child1().setUseKind(KnownCellUse);
+ m_graph.deref(node);
+ node->setArrayMode(arrayMode);
+
+ Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage, node->shouldGenerate());
+ if (!storage)
+ break;
+
+ node->child2() = Edge(storage);
+ break;
+ }
+
+ case GetByIdFlush: {
+ if (node->child1()->shouldSpeculateCell())
+ node->child1().setUseKind(CellUse);
+ break;
+ }
+
+ case CheckExecutable:
+ case CheckStructure:
+ case ForwardCheckStructure:
+ case StructureTransitionWatchpoint:
+ case ForwardStructureTransitionWatchpoint:
+ case CheckFunction:
+ case PutById:
+ case PutByIdDirect:
+ case CheckHasInstance: {
+ node->child1().setUseKind(CellUse);
+ break;
+ }
+
+ case CheckArray: {
+ switch (node->arrayMode().type()) {
+ case Array::String:
+ node->child1().setUseKind(StringUse);
+ break;
+ default:
+ node->child1().setUseKind(CellUse);
+ break;
+ }
+ break;
+ }
+
+ case Arrayify:
+ case ArrayifyToStructure: {
+ node->child1().setUseKind(CellUse);
+ if (node->child2())
+ node->child2().setUseKind(Int32Use);
+ break;
+ }
+
+ case GetByOffset: {
+ if (!node->child1()->hasStorageResult())
+ node->child1().setUseKind(KnownCellUse);
+ break;
+ }
+
+ case PutByOffset: {
+ if (!node->child1()->hasStorageResult())
+ node->child1().setUseKind(KnownCellUse);
+ node->child2().setUseKind(KnownCellUse);
+ break;
+ }
+
+ case InstanceOf: {
+ // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
+ // check. https://bugs.webkit.org/show_bug.cgi?id=107479
+ if (!(node->child1()->prediction() & ~SpecCell))
+ node->child1().setUseKind(CellUse);
+ node->child2().setUseKind(CellUse);
+ break;
+ }
+
+ case GetArrayLength:
+ case Identity:
+ case Nop:
+ case Phi:
+ case ForwardInt32ToDouble:
+ case PhantomPutStructure:
+ case GetIndexedPropertyStorage:
+ case LastNodeType:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+
+#if !ASSERT_DISABLED
+ // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
+ case SetArgument:
+ case Phantom:
+ case JSConstant:
+ case WeakJSConstant:
+ case GetLocal:
+ case GetCallee:
+ case Flush:
+ case PhantomLocal:
+ case GetLocalUnlinked:
+ case InlineStart:
+ case GetMyScope:
+ case GetScopedVar:
+ case GetGlobalVar:
+ case PutGlobalVar:
+ case GlobalVarWatchpoint:
+ case PutGlobalVarCheck:
+ case AllocationProfileWatchpoint:
+ case Call:
+ case Construct:
+ case NewObject:
+ case NewArrayBuffer:
+ case NewRegexp:
+ case Resolve:
+ case ResolveBase:
+ case ResolveBaseStrictPut:
+ case ResolveGlobal:
+ case Breakpoint:
+ case IsUndefined:
+ case IsBoolean:
+ case IsNumber:
+ case IsString:
+ case IsObject:
+ case IsFunction:
+ case StrCat:
+ case CreateActivation:
+ case TearOffActivation:
+ case CreateArguments:
+ case PhantomArguments:
+ case TearOffArguments:
+ case GetMyArgumentsLength:
+ case GetMyArgumentsLengthSafe:
+ case CheckArgumentsNotCreated:
+ case NewFunction:
+ case NewFunctionNoCheck:
+ case NewFunctionExpression:
+ case Jump:
+ case Return:
+ case Throw:
+ case ThrowReferenceError:
+ case GarbageValue:
+ case CountExecution:
+ case ForceOSRExit:
+ break;
+#else
default:
break;
+#endif
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
@@ -421,6 +814,8 @@
Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
+ Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
+
if (arrayMode.doesConversion()) {
if (structure) {
if (m_indexInBlock > 0) {
@@ -435,21 +830,21 @@
m_insertionSet.insertNode(
m_indexInBlock, RefChildren, DontRefNode, SpecNone, ArrayifyToStructure, codeOrigin,
- OpInfo(structure), OpInfo(arrayMode.asWord()), array, index);
+ OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
} else {
m_insertionSet.insertNode(
m_indexInBlock, RefChildren, DontRefNode, SpecNone, Arrayify, codeOrigin,
- OpInfo(arrayMode.asWord()), array, index);
+ OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
}
} else {
if (structure) {
m_insertionSet.insertNode(
m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure, codeOrigin,
- OpInfo(m_graph.addStructureSet(structure)), array);
+ OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
} else {
m_insertionSet.insertNode(
m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckArray, codeOrigin,
- OpInfo(arrayMode.asWord()), array);
+ OpInfo(arrayMode.asWord()), Edge(array, CellUse));
}
}
@@ -461,21 +856,18 @@
m_indexInBlock,
shouldGenerate ? RefChildren : DontRefChildren,
shouldGenerate ? RefNode : DontRefNode,
- SpecNone, GetButterfly, codeOrigin, array);
+ SpecNone, GetButterfly, codeOrigin, Edge(array, KnownCellUse));
}
return m_insertionSet.insertNode(
m_indexInBlock,
shouldGenerate ? RefChildren : DontRefChildren,
shouldGenerate ? RefNode : DontRefNode,
- SpecNone, GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode.asWord()), array);
+ SpecNone, GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
}
- void blessArrayOperation(Edge base, Edge index, unsigned storageChildIdx)
+ void blessArrayOperation(Edge base, Edge index, Edge& storageChild)
{
- if (m_graph.m_fixpointState > BeforeFixpoint)
- return;
-
Node* node = m_currentNode;
switch (node->arrayMode().type()) {
@@ -499,7 +891,7 @@
if (!storage)
return;
- m_graph.child(node, storageChildIdx) = Edge(storage);
+ storageChild = Edge(storage);
return;
} }
}
@@ -507,48 +899,92 @@
void fixIntEdge(Edge& edge)
{
Node* node = edge.node();
- if (node->op() != ValueToInt32)
+ if (node->op() != ValueToInt32) {
+ edge.setUseKind(KnownInt32Use);
return;
-
- if (!node->child1()->shouldSpeculateInteger())
- return;
+ }
Edge oldEdge = edge;
Edge newEdge = node->child1();
+ if (newEdge.useKind() != Int32Use) {
+ edge.setUseKind(KnownInt32Use);
+ return;
+ }
+
+ ASSERT(newEdge->shouldSpeculateInteger());
+
m_graph.ref(newEdge);
m_graph.deref(oldEdge);
edge = newEdge;
}
- void fixDoubleEdge(unsigned childIndex, SpeculationDirection direction = BackwardSpeculation)
+ void fixDoubleEdge(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
{
- Node* source = m_currentNode;
- Edge& edge = m_graph.child(source, childIndex);
-
if (edge->prediction() & SpecDouble) {
- edge.setUseKind(DoubleUse);
+ edge.setUseKind(useKind);
return;
}
- injectInt32ToDoubleNode(childIndex, direction);
+ injectInt32ToDoubleNode(edge, useKind, direction);
}
- void injectInt32ToDoubleNode(unsigned childIndex, SpeculationDirection direction = BackwardSpeculation)
+ void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
{
Node* result = m_insertionSet.insertNode(
m_indexInBlock, DontRefChildren, RefNode, SpecDouble,
direction == BackwardSpeculation ? Int32ToDouble : ForwardInt32ToDouble,
- m_currentNode->codeOrigin, m_graph.child(m_currentNode, childIndex).node());
+ m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF(
"(replacing @%u->@%u with @%u->@%u) ",
- m_currentNode->index(), m_graph.child(m_currentNode, childIndex)->index(), m_currentNode->index(), result->index());
+ m_currentNode->index(), edge->index(), m_currentNode->index(), result->index());
#endif
- m_graph.child(m_currentNode, childIndex) = Edge(result, DoubleUse);
+ edge = Edge(result, useKind);
+ }
+
+ void truncateConstantToInt32(Edge& edge)
+ {
+ Node* oldNode = edge.node();
+
+ ASSERT(oldNode->hasConstant());
+ JSValue value = m_graph.valueOfJSConstant(oldNode);
+ if (value.isInt32())
+ return;
+
+ value = jsNumber(JSC::toInt32(value.asNumber()));
+ ASSERT(value.isInt32());
+ edge.setNode(m_insertionSet.insertNode(
+ m_indexInBlock, DontRefChildren, RefNode, SpecInt32, JSConstant,
+ m_currentNode->codeOrigin, OpInfo(codeBlock()->addOrFindConstant(value))));
+ m_graph.deref(oldNode);
+ }
+
+ void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
+ {
+ if (mode != SpeculateIntegerAndTruncateConstants)
+ return;
+
+ ASSERT(node->child1()->hasConstant() || node->child2()->hasConstant());
+ if (node->child1()->hasConstant())
+ truncateConstantToInt32(node->child1());
+ else
+ truncateConstantToInt32(node->child2());
+ }
+
+ bool attemptToMakeIntegerAdd(Node* node)
+ {
+ AddSpeculationMode mode = m_graph.addSpeculationMode(node);
+ if (mode == DontSpeculateInteger)
+ return false;
+
+ truncateConstantsIfNecessary(node, mode);
+ node->child1().setUseKind(Int32Use);
+ node->child2().setUseKind(Int32Use);
+ return true;
}
BasicBlock* m_block;