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/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 102c2b2..3bd6823 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -113,6 +113,7 @@
dfg/DFGStructureCheckHoistingPhase.cpp
dfg/DFGThunks.cpp
dfg/DFGUnificationPhase.cpp
+ dfg/DFGUseKind.cpp
dfg/DFGValueSource.cpp
dfg/DFGVariableAccessDataDump.cpp
dfg/DFGVariableEvent.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index fbb98b5..fe003b4 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,288 @@
+2013-02-20 Filip Pizlo <fpizlo@apple.com>
+
+ 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):
+
2013-02-20 Mark Hahnenberg <mhahnenberg@apple.com>
Objective-C API: Need a way to use the Objective-C JavaScript API with WebKit
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index c5ecd88..e8a1f2b 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -272,6 +272,8 @@
Source/JavaScriptCore/dfg/DFGThunks.h \
Source/JavaScriptCore/dfg/DFGUnificationPhase.cpp \
Source/JavaScriptCore/dfg/DFGUnificationPhase.h \
+ Source/JavaScriptCore/dfg/DFGUseKind.cpp \
+ Source/JavaScriptCore/dfg/DFGUseKind.h \
Source/JavaScriptCore/dfg/DFGValueRecoveryOverride.h \
Source/JavaScriptCore/dfg/DFGValueSource.cpp \
Source/JavaScriptCore/dfg/DFGValueSource.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index fadb1e2..bfe00b4 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -109,6 +109,8 @@
0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */; };
0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 65987F2F16828A7E003C2F8D /* UnusedPointer.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */; };
+ 0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F34B14816D4200E001CDA5A /* DFGUseKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F34B14C16D43E0D001CDA5A /* PolymorphicAccessStructureList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F34B14B16D43E0C001CDA5A /* PolymorphicAccessStructureList.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */; };
0F3B3A1B153E68F4003ED0FF /* DFGConstantFoldingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3B3A18153E68EF003ED0FF /* DFGConstantFoldingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1001,6 +1003,8 @@
0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = "<group>"; };
0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = "<group>"; };
0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGCodeBlocks.h; sourceTree = "<group>"; };
+ 0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGUseKind.cpp; path = dfg/DFGUseKind.cpp; sourceTree = "<group>"; };
+ 0F34B14816D4200E001CDA5A /* DFGUseKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGUseKind.h; path = dfg/DFGUseKind.h; sourceTree = "<group>"; };
0F34B14B16D43E0C001CDA5A /* PolymorphicAccessStructureList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolymorphicAccessStructureList.h; sourceTree = "<group>"; };
0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGConstantFoldingPhase.cpp; path = dfg/DFGConstantFoldingPhase.cpp; sourceTree = "<group>"; };
0F3B3A18153E68EF003ED0FF /* DFGConstantFoldingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGConstantFoldingPhase.h; path = dfg/DFGConstantFoldingPhase.h; sourceTree = "<group>"; };
@@ -2709,6 +2713,8 @@
0FC097A0146B28C700CF2442 /* DFGThunks.h */,
0FBE0F6F16C1DB010082C5E8 /* DFGUnificationPhase.cpp */,
0FBE0F7016C1DB010082C5E8 /* DFGUnificationPhase.h */,
+ 0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */,
+ 0F34B14816D4200E001CDA5A /* DFGUseKind.h */,
0F3B3A2915474FF4003ED0FF /* DFGValidate.cpp */,
0F3B3A2A15474FF4003ED0FF /* DFGValidate.h */,
0F2BDC3F1522801700CD8910 /* DFGValueRecoveryOverride.h */,
@@ -3251,6 +3257,7 @@
868916B0155F286300CB2B9A /* PrivateName.h in Headers */,
BC18C4500E16F5CD00B34460 /* Profile.h in Headers */,
95CD45770E1C4FDD0085358E /* ProfileGenerator.h in Headers */,
+ 0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */,
BC18C4510E16F5CD00B34460 /* ProfileNode.h in Headers */,
0FF729A5166AD351000F5BA3 /* ProfilerBytecode.h in Headers */,
0FF729B9166AD360000F5BA3 /* ProfilerBytecodes.h in Headers */,
@@ -3957,6 +3964,7 @@
0FF729B0166AD35C000F5BA3 /* ProfilerCompilationKind.cpp in Sources */,
0FF729B1166AD35C000F5BA3 /* ProfilerCompiledBytecode.cpp in Sources */,
0FF729B2166AD35C000F5BA3 /* ProfilerDatabase.cpp in Sources */,
+ 0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */,
0FF729B3166AD35C000F5BA3 /* ProfilerOrigin.cpp in Sources */,
0FF729B4166AD35C000F5BA3 /* ProfilerOriginStack.cpp in Sources */,
0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */,
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 13b73b0..bd9f0c3 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -149,6 +149,7 @@
dfg/DFGStructureCheckHoistingPhase.cpp \
dfg/DFGThunks.cpp \
dfg/DFGUnificationPhase.cpp \
+ dfg/DFGUseKind.cpp \
dfg/DFGValueSource.cpp \
dfg/DFGVariableAccessDataDump.cpp \
dfg/DFGVariableEvent.cpp \
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 8e92de9..fde3771 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -234,30 +234,61 @@
return UnknownBooleanResult;
}
-bool AbstractState::execute(unsigned indexInBlock)
+bool AbstractState::startExecuting(Node* node)
{
ASSERT(m_block);
ASSERT(m_isValid);
m_didClobber = false;
- Node* node = m_block->at(indexInBlock);
-
+ node->setCanExit(false);
+
if (!node->shouldGenerate())
- return true;
-
+ return false;
+
+ return true;
+}
+
+bool AbstractState::startExecuting(unsigned indexInBlock)
+{
+ return startExecuting(m_block->at(indexInBlock));
+}
+
+void AbstractState::executeEdges(Node* node)
+{
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, filterEdgeByUse);
+}
+
+void AbstractState::executeEdges(unsigned indexInBlock)
+{
+ executeEdges(m_block->at(indexInBlock));
+}
+
+void AbstractState::verifyEdge(Node*, Edge edge)
+{
+ RELEASE_ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())));
+}
+
+void AbstractState::verifyEdges(Node* node)
+{
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
+}
+
+bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
+{
+ if (!ASSERT_DISABLED)
+ verifyEdges(node);
+
switch (node->op()) {
case JSConstant:
case WeakJSConstant:
case PhantomArguments: {
forNode(node).set(m_graph.valueOfJSConstant(node));
- node->setCanExit(false);
break;
}
case Identity: {
forNode(node) = forNode(node->child1());
- node->setCanExit(false);
break;
}
@@ -265,19 +296,16 @@
VariableAccessData* variableAccessData = node->variableAccessData();
if (variableAccessData->prediction() == SpecNone) {
m_isValid = false;
- node->setCanExit(true);
break;
}
- bool canExit = false;
AbstractValue value = m_variables.operand(variableAccessData->local());
if (!variableAccessData->isCaptured()) {
if (value.isClear())
- canExit |= true;
+ node->setCanExit(true);
}
if (value.value())
m_foundConstants = true;
forNode(node) = value;
- node->setCanExit(canExit);
break;
}
@@ -286,35 +314,10 @@
if (value.value())
m_foundConstants = true;
forNode(node) = value;
- node->setCanExit(false);
break;
}
case SetLocal: {
- if (node->variableAccessData()->isCaptured()
- || m_graph.isCreatedThisArgument(node->local())) {
- m_variables.operand(node->local()) = forNode(node->child1());
- node->setCanExit(false);
- break;
- }
-
- if (node->variableAccessData()->shouldUseDoubleFormat()) {
- speculateNumberUnary(node);
- m_variables.operand(node->local()).set(SpecDouble);
- break;
- }
-
- SpeculatedType predictedType = node->variableAccessData()->argumentAwarePrediction();
- if (isInt32Speculation(predictedType))
- speculateInt32Unary(node);
- else if (isCellSpeculation(predictedType)) {
- node->setCanExit(!isCellSpeculation(forNode(node->child1()).m_type));
- forNode(node->child1()).filter(SpecCell);
- } else if (isBooleanSpeculation(predictedType))
- speculateBooleanUnary(node);
- else
- node->setCanExit(false);
-
m_variables.operand(node->local()) = forNode(node->child1());
break;
}
@@ -322,7 +325,6 @@
case SetArgument:
// Assert that the state of arguments has been set.
ASSERT(!m_block->valuesAtHead.operand(node->local()).isClear());
- node->setCanExit(false);
break;
case BitAnd:
@@ -362,11 +364,9 @@
}
if (constantWasSet) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
}
- speculateInt32Binary(node);
forNode(node).set(SpecInt32);
break;
}
@@ -377,20 +377,17 @@
ASSERT(child.isInt32());
if (trySetConstant(node, JSValue(child.asUInt32()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
}
- if (!node->canSpeculateInteger()) {
+ if (!node->canSpeculateInteger())
forNode(node).set(SpecDouble);
- node->setCanExit(false);
- } else {
+ else {
forNode(node).set(SpecInt32);
node->setCanExit(true);
}
break;
}
-
case DoubleAsInt32: {
JSValue child = forNode(node->child1()).value();
@@ -404,7 +401,6 @@
}
}
node->setCanExit(true);
- forNode(node->child1()).filter(SpecNumber);
forNode(node).set(SpecInt32);
break;
}
@@ -419,20 +415,9 @@
constantWasSet = trySetConstant(node, JSValue(JSC::toInt32(child.asDouble())));
if (constantWasSet) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
}
- if (node->child1()->shouldSpeculateInteger())
- speculateInt32Unary(node);
- else if (node->child1()->shouldSpeculateBoolean())
- speculateBooleanUnary(node);
- else if (node->child1()->shouldSpeculateNumber())
- speculateNumberUnary(node);
- else {
- node->setCanExit(forNode(node->child1()).m_type & SpecCell);
- forNode(node->child1()).filter(~SpecCell);
- }
forNode(node).set(SpecInt32);
break;
@@ -444,10 +429,8 @@
if (child && child.isNumber()
&& trySetConstant(node, JSValue(JSValue::EncodeAsDouble, child.asNumber()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- speculateNumberUnary(node);
if (isInt32Speculation(forNode(node->child1()).m_type))
forNode(node).set(SpecDoubleReal);
else
@@ -455,10 +438,6 @@
break;
}
- case CheckNumber:
- forNode(node->child1()).filter(SpecNumber);
- break;
-
case ValueAdd:
case ArithAdd: {
JSValue left = forNode(node->child1()).value();
@@ -466,33 +445,27 @@
if (left && right && left.isNumber() && right.isNumber()
&& trySetConstant(node, JSValue(left.asNumber() + right.asNumber()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- if (m_graph.addShouldSpeculateInteger(node)) {
- speculateInt32Binary(
- node, !nodeCanTruncateInteger(node->arithNodeFlags()));
+ switch (node->binaryUseKind()) {
+ case Int32Use:
forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setCanExit(true);
break;
- }
- if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
- speculateNumberBinary(node);
+ case NumberUse:
if (isRealNumberSpeculation(forNode(node->child1()).m_type)
&& isRealNumberSpeculation(forNode(node->child2()).m_type))
forNode(node).set(SpecDoubleReal);
else
forNode(node).set(SpecDouble);
break;
- }
- if (node->op() == ValueAdd) {
+ default:
+ RELEASE_ASSERT(node->op() == ValueAdd);
clobberWorld(node->codeOrigin, indexInBlock);
forNode(node).set(SpecString | SpecInt32 | SpecNumber);
- node->setCanExit(false);
break;
}
- // We don't handle this yet. :-(
- m_isValid = false;
- node->setCanExit(true);
break;
}
@@ -502,17 +475,21 @@
if (left && right && left.isNumber() && right.isNumber()
&& trySetConstant(node, JSValue(left.asNumber() - right.asNumber()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- if (m_graph.addShouldSpeculateInteger(node)) {
- speculateInt32Binary(
- node, !nodeCanTruncateInteger(node->arithNodeFlags()));
+ switch (node->binaryUseKind()) {
+ case Int32Use:
forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberBinary(node);
- forNode(node).set(SpecDouble);
break;
}
@@ -521,17 +498,21 @@
if (child && child.isNumber()
&& trySetConstant(node, JSValue(-child.asNumber()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- if (m_graph.negateShouldSpeculateInteger(node)) {
- speculateInt32Unary(
- node, !nodeCanTruncateInteger(node->arithNodeFlags()));
+ switch (node->child1().useKind()) {
+ case Int32Use:
forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags()))
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberUnary(node);
- forNode(node).set(SpecDouble);
break;
}
@@ -541,23 +522,26 @@
if (left && right && left.isNumber() && right.isNumber()
&& trySetConstant(node, JSValue(left.asNumber() * right.asNumber()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- if (m_graph.mulShouldSpeculateInteger(node)) {
- speculateInt32Binary(
- node,
- !nodeCanTruncateInteger(node->arithNodeFlags())
- || !nodeCanIgnoreNegativeZero(node->arithNodeFlags()));
+ switch (node->binaryUseKind()) {
+ case Int32Use:
forNode(node).set(SpecInt32);
+ if (!nodeCanTruncateInteger(node->arithNodeFlags())
+ || !nodeCanIgnoreNegativeZero(node->arithNodeFlags()))
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ if (isRealNumberSpeculation(forNode(node->child1()).m_type)
+ || isRealNumberSpeculation(forNode(node->child2()).m_type))
+ forNode(node).set(SpecDoubleReal);
+ else
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberBinary(node);
- if (isRealNumberSpeculation(forNode(node->child1()).m_type)
- || isRealNumberSpeculation(forNode(node->child2()).m_type))
- forNode(node).set(SpecDoubleReal);
- else
- forNode(node).set(SpecDouble);
break;
}
@@ -591,18 +575,21 @@
}
if (constantWasSet) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
}
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
- speculateInt32Binary(node, true); // forcing can-exit, which is a bit on the conservative side.
+ switch (node->binaryUseKind()) {
+ case Int32Use:
forNode(node).set(SpecInt32);
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberBinary(node);
- forNode(node).set(SpecDouble);
break;
}
@@ -611,17 +598,20 @@
if (child && child.isNumber()
&& trySetConstant(node, JSValue(fabs(child.asNumber())))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- if (node->child1()->shouldSpeculateIntegerForArithmetic()
- && node->canSpeculateInteger()) {
- speculateInt32Unary(node, true);
+ switch (node->child1().useKind()) {
+ case Int32Use:
forNode(node).set(SpecInt32);
+ node->setCanExit(true);
+ break;
+ case NumberUse:
+ forNode(node).set(SpecDouble);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
- speculateNumberUnary(node);
- forNode(node).set(SpecDouble);
break;
}
@@ -630,10 +620,8 @@
if (child && child.isNumber()
&& trySetConstant(node, JSValue(sqrt(child.asNumber())))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- speculateNumberUnary(node);
forNode(node).set(SpecDouble);
break;
}
@@ -652,21 +640,21 @@
}
if (didSetConstant) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- Node* child = node->child1().node();
- if (isBooleanSpeculation(child->prediction()))
- speculateBooleanUnary(node);
- else if (child->shouldSpeculateObjectOrOther()) {
+ switch (node->child1().useKind()) {
+ case BooleanUse:
+ case Int32Use:
+ case NumberUse:
+ case UntypedUse:
+ break;
+ case ObjectOrOtherUse:
node->setCanExit(true);
- forNode(child).filter((SpecCell & ~SpecString) | SpecOther);
- } else if (child->shouldSpeculateInteger())
- speculateInt32Unary(node);
- else if (child->shouldSpeculateNumber())
- speculateNumberUnary(node);
- else
- node->setCanExit(false);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
forNode(node).set(SpecBoolean);
break;
}
@@ -764,14 +752,17 @@
break;
}
}
-
- Node* childNode = node->child1().node();
- if (isCellSpeculation(childNode->prediction())) {
- if (isStringSpeculation(childNode->prediction()))
- forNode(childNode).filter(SpecString);
- else
- forNode(childNode).filter(SpecCell);
+
+ switch (node->child1().useKind()) {
+ case StringUse:
+ case CellUse:
node->setCanExit(true);
+ break;
+ case UntypedUse:
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
forNode(node).set(SpecString);
break;
@@ -823,65 +814,18 @@
if (constantWasSet) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
forNode(node).set(SpecBoolean);
- if (node->op() == CompareEqConstant) {
- // We can exit if we haven't fired the MasqueradesAsUndefind watchpoint yet.
- node->setCanExit(m_codeBlock->globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
- break;
- }
-
- Node* left = node->child1().node();
- Node* right = node->child2().node();
- SpeculatedType filter;
- SpeculatedTypeChecker checker;
- if (Node::shouldSpeculateInteger(left, right)) {
- filter = SpecInt32;
- checker = isInt32Speculation;
- } else if (Node::shouldSpeculateNumber(left, right)) {
- filter = SpecNumber;
- checker = isNumberSpeculation;
- } else if (node->op() == CompareEq) {
- if (left->shouldSpeculateString() || right->shouldSpeculateString()) {
- node->setCanExit(false);
- break;
- }
- if (left->shouldSpeculateObject() && right->shouldSpeculateObject()) {
- node->setCanExit(true);
- forNode(left).filter(SpecObject);
- forNode(right).filter(SpecObject);
- break;
- }
- if (left->shouldSpeculateObject() && right->shouldSpeculateObjectOrOther()) {
- node->setCanExit(true);
- forNode(left).filter(SpecObject);
- forNode(right).filter(SpecObject | SpecOther);
- break;
- }
- if (left->shouldSpeculateObjectOrOther() && right->shouldSpeculateObject()) {
- node->setCanExit(true);
- forNode(left).filter(SpecObject | SpecOther);
- forNode(right).filter(SpecObject);
- break;
- }
-
- filter = SpecTop;
- checker = isAnySpeculation;
- clobberWorld(node->codeOrigin, indexInBlock);
- } else {
- filter = SpecTop;
- checker = isAnySpeculation;
- clobberWorld(node->codeOrigin, indexInBlock);
- }
- node->setCanExit(
- !checker(forNode(left).m_type)
- || !checker(forNode(right).m_type));
- forNode(left).filter(filter);
- forNode(right).filter(filter);
+ // This is overly conservative. But the only thing this prevents is store elimination,
+ // and how likely is it, really, that you'll have redundant stores across a comparison
+ // operation? Comparison operations are typically at the end of basic blocks, so
+ // unless we have global store elimination (super unlikely given how unprofitable that
+ // optimization is to begin with), you aren't going to be wanting to store eliminate
+ // across an equality op.
+ node->setCanExit(true);
break;
}
@@ -894,47 +838,20 @@
if (left && right && left.isNumber() && right.isNumber()
&& trySetConstant(node, jsBoolean(left.asNumber() == right.asNumber()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
forNode(node).set(SpecBoolean);
- if (node->op() == CompareStrictEqConstant) {
- node->setCanExit(false);
- break;
- }
- if (Node::shouldSpeculateInteger(leftNode, rightNode)) {
- speculateInt32Binary(node);
- break;
- }
- if (Node::shouldSpeculateNumber(leftNode, rightNode)) {
- speculateNumberBinary(node);
- break;
- }
- if (leftNode->shouldSpeculateString() || rightNode->shouldSpeculateString()) {
- node->setCanExit(false);
- break;
- }
- if (leftNode->shouldSpeculateObject() && rightNode->shouldSpeculateObject()) {
- node->setCanExit(true);
- forNode(leftNode).filter(SpecObject);
- forNode(rightNode).filter(SpecObject);
- break;
- }
- node->setCanExit(false);
+ node->setCanExit(true); // This is overly conservative.
break;
}
case StringCharCodeAt:
node->setCanExit(true);
- forNode(node->child1()).filter(SpecString);
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case StringCharAt:
node->setCanExit(true);
- forNode(node->child1()).filter(SpecString);
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecString);
break;
@@ -954,15 +871,12 @@
forNode(node).makeTop();
break;
case Array::String:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecString);
break;
case Array::Arguments:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).makeTop();
break;
case Array::Int32:
- forNode(node->child2()).filter(SpecInt32);
if (node->arrayMode().isOutOfBounds()) {
clobberWorld(node->codeOrigin, indexInBlock);
forNode(node).makeTop();
@@ -970,7 +884,6 @@
forNode(node).set(SpecInt32);
break;
case Array::Double:
- forNode(node->child2()).filter(SpecInt32);
if (node->arrayMode().isOutOfBounds()) {
clobberWorld(node->codeOrigin, indexInBlock);
forNode(node).makeTop();
@@ -982,48 +895,38 @@
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
- forNode(node->child2()).filter(SpecInt32);
if (node->arrayMode().isOutOfBounds())
clobberWorld(node->codeOrigin, indexInBlock);
forNode(node).makeTop();
break;
case Array::Int8Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case Array::Int16Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case Array::Int32Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case Array::Uint8Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case Array::Uint8ClampedArray:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case Array::Uint16Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecInt32);
break;
case Array::Uint32Array:
- forNode(node->child2()).filter(SpecInt32);
if (node->shouldSpeculateInteger())
forNode(node).set(SpecInt32);
else
forNode(node).set(SpecDouble);
break;
case Array::Float32Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecDouble);
break;
case Array::Float64Array:
- forNode(node->child2()).filter(SpecInt32);
forNode(node).set(SpecDouble);
break;
default:
@@ -1036,9 +939,6 @@
case PutByVal:
case PutByValAlias: {
node->setCanExit(true);
- Edge child1 = m_graph.varArgChild(node, 0);
- Edge child2 = m_graph.varArgChild(node, 1);
- Edge child3 = m_graph.varArgChild(node, 2);
switch (node->arrayMode().modeForPut().type()) {
case Array::ForceExit:
m_isValid = false;
@@ -1047,104 +947,23 @@
clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::Int32:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecInt32);
if (node->arrayMode().isOutOfBounds())
clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::Double:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecRealNumber);
if (node->arrayMode().isOutOfBounds())
clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::Contiguous:
case Array::ArrayStorage:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
if (node->arrayMode().isOutOfBounds())
clobberWorld(node->codeOrigin, indexInBlock);
break;
case Array::SlowPutArrayStorage:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
if (node->arrayMode().mayStoreToHole())
clobberWorld(node->codeOrigin, indexInBlock);
break;
- case Array::Arguments:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- break;
- case Array::Int8Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Int16Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Int32Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint8Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint8ClampedArray:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint16Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Uint32Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- if (child3->shouldSpeculateInteger())
- forNode(child3).filter(SpecInt32);
- else
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Float32Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecNumber);
- break;
- case Array::Float64Array:
- forNode(child1).filter(SpecCell);
- forNode(child2).filter(SpecInt32);
- forNode(child3).filter(SpecNumber);
- break;
default:
- CRASH();
break;
}
break;
@@ -1152,16 +971,6 @@
case ArrayPush:
node->setCanExit(true);
- switch (node->arrayMode().type()) {
- case Array::Int32:
- forNode(node->child2()).filter(SpecInt32);
- break;
- case Array::Double:
- forNode(node->child2()).filter(SpecRealNumber);
- break;
- default:
- break;
- }
clobberWorld(node->codeOrigin, indexInBlock);
forNode(node).set(SpecNumber);
break;
@@ -1174,16 +983,10 @@
case RegExpExec:
case RegExpTest:
- node->setCanExit(
- !isCellSpeculation(forNode(node->child1()).m_type)
- || !isCellSpeculation(forNode(node->child2()).m_type));
- forNode(node->child1()).filter(SpecCell);
- forNode(node->child2()).filter(SpecCell);
forNode(node).makeTop();
break;
case Jump:
- node->setCanExit(false);
break;
case Branch: {
@@ -1191,36 +994,23 @@
BooleanResult result = booleanResult(node, forNode(child));
if (result == DefinitelyTrue) {
m_branchDirection = TakeTrue;
- node->setCanExit(false);
break;
}
if (result == DefinitelyFalse) {
m_branchDirection = TakeFalse;
- node->setCanExit(false);
break;
}
// FIXME: The above handles the trivial cases of sparse conditional
// constant propagation, but we can do better:
// We can specialize the source variable's value on each direction of
// the branch.
- if (child->shouldSpeculateBoolean())
- speculateBooleanUnary(node);
- else if (child->shouldSpeculateObjectOrOther()) {
- node->setCanExit(true);
- forNode(child).filter(SpecObject | SpecOther);
- } else if (child->shouldSpeculateInteger())
- speculateInt32Unary(node);
- else if (child->shouldSpeculateNumber())
- speculateNumberUnary(node);
- else
- node->setCanExit(false);
+ node->setCanExit(true); // This is overly conservative.
m_branchDirection = TakeBoth;
break;
}
case Return:
m_isValid = false;
- node->setCanExit(false);
break;
case Throw:
@@ -1230,22 +1020,18 @@
break;
case ToPrimitive: {
- Node* child = node->child1().node();
-
- JSValue childConst = forNode(child).value();
+ JSValue childConst = forNode(node->child1()).value();
if (childConst && childConst.isNumber() && trySetConstant(node, childConst)) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
- if (child->shouldSpeculateInteger()) {
- speculateInt32Unary(node);
+ if (node->child1().useKind() == Int32Use) {
forNode(node).set(SpecInt32);
break;
}
- AbstractValue& source = forNode(child);
+ AbstractValue& source = forNode(node->child1());
AbstractValue& destination = forNode(node);
// NB. The more canonical way of writing this would have been:
@@ -1275,39 +1061,15 @@
type |= SpecString;
}
destination.set(type);
- node->setCanExit(false);
break;
}
case StrCat:
- node->setCanExit(false);
forNode(node).set(SpecString);
break;
case NewArray:
node->setCanExit(true);
- switch (node->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- CRASH();
- break;
- case ALL_UNDECIDED_INDEXING_TYPES:
- ASSERT(!node->numChildren());
- break;
- case ALL_INT32_INDEXING_TYPES:
- for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
- forNode(m_graph.m_varArgChildren[node->firstChild() + operandIndex]).filter(SpecInt32);
- break;
- case ALL_DOUBLE_INDEXING_TYPES:
- for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
- forNode(m_graph.m_varArgChildren[node->firstChild() + operandIndex]).filter(SpecRealNumber);
- break;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- break;
- default:
- CRASH();
- break;
- }
forNode(node).set(m_graph.globalObjectFor(node->codeOrigin)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
m_haveStructures = true;
break;
@@ -1320,19 +1082,16 @@
case NewArrayWithSize:
node->setCanExit(true);
- forNode(node->child1()).filter(SpecInt32);
forNode(node).set(SpecArray);
m_haveStructures = true;
break;
case NewRegexp:
- node->setCanExit(false);
forNode(node).set(m_graph.globalObjectFor(node->codeOrigin)->regExpStructure());
m_haveStructures = true;
break;
case ConvertThis: {
- Node* child = node->child1().node();
AbstractValue& source = forNode(node->child1());
AbstractValue& destination = forNode(node);
@@ -1341,38 +1100,31 @@
// object, so there's nothing to do. I don't think this case will
// be hit, but then again, you never know.
destination = source;
- node->setCanExit(false);
m_foundConstants = true; // Tell the constant folder to turn this into Identity.
break;
}
node->setCanExit(true);
-
- if (isOtherSpeculation(child->prediction())) {
- source.filter(SpecOther);
+ switch (node->child1().useKind()) {
+ case OtherUse:
destination.set(SpecObjectOther);
break;
- }
-
- if (isObjectSpeculation(child->prediction())) {
- source.filter(SpecObject);
+ case ObjectUse:
destination = source;
break;
+ case UntypedUse:
+ destination = source;
+ destination.merge(SpecObjectOther);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
-
- destination = source;
- destination.merge(SpecObjectOther);
break;
}
case CreateThis: {
- AbstractValue& source = forNode(node->child1());
- AbstractValue& destination = forNode(node);
-
- node->setCanExit(!isCellSpeculation(source.m_type));
-
- source.filter(SpecFunction);
- destination.set(SpecFinalObject);
+ forNode(node).set(SpecFinalObject);
break;
}
@@ -1381,36 +1133,31 @@
break;
case NewObject:
- node->setCanExit(false);
forNode(node).set(node->structure());
m_haveStructures = true;
break;
case CreateActivation:
- node->setCanExit(false);
forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->activationStructure());
m_haveStructures = true;
break;
case CreateArguments:
- node->setCanExit(false);
forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->argumentsStructure());
m_haveStructures = true;
break;
case TearOffActivation:
case TearOffArguments:
- node->setCanExit(false);
// Does nothing that is user-visible.
break;
case CheckArgumentsNotCreated:
if (isEmptySpeculation(
m_variables.operand(
- m_graph.argumentsRegisterFor(node->codeOrigin)).m_type)) {
- node->setCanExit(false);
+ m_graph.argumentsRegisterFor(node->codeOrigin)).m_type))
m_foundConstants = true;
- } else
+ else
node->setCanExit(true);
break;
@@ -1430,7 +1177,6 @@
break;
case GetMyArgumentsLengthSafe:
- node->setCanExit(false);
// This potentially clobbers all structures if the arguments object had a getter
// installed on the length property.
clobberWorld(node->codeOrigin, indexInBlock);
@@ -1444,7 +1190,6 @@
// We know that this executable does not escape its arguments, so we can optimize
// the arguments a bit. Note that this ends up being further optimized by the
// ArgumentsSimplificationPhase.
- forNode(node->child1()).filter(SpecInt32);
forNode(node).makeTop();
break;
@@ -1453,8 +1198,6 @@
// This potentially clobbers all structures if the property we're accessing has
// a getter. We don't speculate against this.
clobberWorld(node->codeOrigin, indexInBlock);
- // But we do speculate that the index is an integer.
- forNode(node->child1()).filter(SpecInt32);
// And the result is unknown.
forNode(node).makeTop();
break;
@@ -1462,29 +1205,24 @@
case NewFunction:
case NewFunctionExpression:
case NewFunctionNoCheck:
- node->setCanExit(false);
forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->functionStructure());
break;
case GetCallee:
- node->setCanExit(false);
forNode(node).set(SpecFunction);
break;
case SetCallee:
case SetMyScope:
- node->setCanExit(false);
break;
case GetScope: // FIXME: We could get rid of these if we know that the JSFunction is a constant. https://bugs.webkit.org/show_bug.cgi?id=106202
case GetMyScope:
case SkipTopScope:
- node->setCanExit(false);
forNode(node).set(SpecCellOther);
break;
case SkipScope: {
- node->setCanExit(false);
JSValue child = forNode(node->child1()).value();
if (child && trySetConstant(node, JSValue(jsCast<JSScope*>(child.asCell())->next()))) {
m_foundConstants = true;
@@ -1495,18 +1233,14 @@
}
case GetScopeRegisters:
- node->setCanExit(false);
- forNode(node->child1()).filter(SpecCell);
forNode(node).clear(); // The result is not a JS value.
break;
case GetScopedVar:
- node->setCanExit(false);
forNode(node).makeTop();
break;
case PutScopedVar:
- node->setCanExit(false);
clobberCapturedVars(node->codeOrigin);
break;
@@ -1518,8 +1252,6 @@
break;
}
if (isCellSpeculation(node->child1()->prediction())) {
- forNode(node->child1()).filter(SpecCell);
-
if (Structure* structure = forNode(node->child1()).bestProvenStructure()) {
GetByIdStatus status = GetByIdStatus::computeFor(
m_graph.m_globalData, structure,
@@ -1555,7 +1287,6 @@
// more thoroughly. https://bugs.webkit.org/show_bug.cgi?id=106200
// FIXME: We could eliminate these entirely if we know the exact value that flows into this.
// https://bugs.webkit.org/show_bug.cgi?id=106201
- forNode(node->child1()).filter(SpecCell);
node->setCanExit(true);
break;
}
@@ -1564,6 +1295,7 @@
case ForwardCheckStructure: {
// FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
AbstractValue& value = forNode(node->child1());
+ ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
// If this structure check is attempting to prove knowledge already held in
// the futurePossibleStructure set then the constant folding phase should
// turn this into a watchpoint instead.
@@ -1571,9 +1303,8 @@
if (value.m_futurePossibleStructure.isSubsetOf(set)
|| value.m_currentKnownStructure.isSubsetOf(set))
m_foundConstants = true;
- node->setCanExit(
- !value.m_currentKnownStructure.isSubsetOf(set)
- || !isCellSpeculation(value.m_type));
+ if (!value.m_currentKnownStructure.isSubsetOf(set))
+ node->setCanExit(true);
value.filter(set);
m_haveStructures = true;
break;
@@ -1591,7 +1322,6 @@
// infinity of structures.
ASSERT(value.m_futurePossibleStructure.isSubsetOf(StructureSet(node->structure())));
- ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
value.filter(node->structure());
m_haveStructures = true;
node->setCanExit(true);
@@ -1600,7 +1330,6 @@
case PutStructure:
case PhantomPutStructure:
- node->setCanExit(false);
if (!forNode(node->child1()).m_currentKnownStructure.isClear()) {
clobberStructures(indexInBlock);
forNode(node->child1()).set(node->structureTransitionData().newStructure);
@@ -1610,14 +1339,11 @@
case GetButterfly:
case AllocatePropertyStorage:
case ReallocatePropertyStorage:
- node->setCanExit(!isCellSpeculation(forNode(node->child1()).m_type));
- forNode(node->child1()).filter(SpecCell);
forNode(node).clear(); // The result is not a JS value.
break;
case CheckArray: {
if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
node->setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here.
@@ -1630,7 +1356,6 @@
case Array::Contiguous:
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
- forNode(node->child1()).filter(SpecCell);
break;
case Array::Arguments:
forNode(node->child1()).filter(SpecArguments);
@@ -1673,15 +1398,11 @@
case Arrayify: {
if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
m_foundConstants = true;
- node->setCanExit(false);
break;
}
ASSERT(node->arrayMode().conversion() == Array::Convert
|| node->arrayMode().conversion() == Array::RageConvert);
node->setCanExit(true);
- forNode(node->child1()).filter(SpecCell);
- if (node->child2())
- forNode(node->child2()).filter(SpecInt32);
clobberStructures(indexInBlock);
forNode(node->child1()).filterArrayModes(node->arrayMode().arrayModesThatPassFiltering());
m_haveStructures = true;
@@ -1694,35 +1415,21 @@
|| value.m_currentKnownStructure.isSubsetOf(set))
m_foundConstants = true;
node->setCanExit(true);
- if (node->child2())
- forNode(node->child2()).filter(SpecInt32);
clobberStructures(indexInBlock);
value.filter(set);
m_haveStructures = true;
break;
}
case GetIndexedPropertyStorage: {
- node->setCanExit(false);
forNode(node).clear();
break;
}
- case GetByOffset:
- if (!node->child1()->hasStorageResult()) {
- node->setCanExit(!isCellSpeculation(forNode(node->child1()).m_type));
- forNode(node->child1()).filter(SpecCell);
- }
+ case GetByOffset: {
forNode(node).makeTop();
break;
+ }
case PutByOffset: {
- bool canExit = false;
- if (!node->child1()->hasStorageResult()) {
- canExit |= !isCellSpeculation(forNode(node->child1()).m_type);
- forNode(node->child1()).filter(SpecCell);
- }
- canExit |= !isCellSpeculation(forNode(node->child2()).m_type);
- forNode(node->child2()).filter(SpecCell);
- node->setCanExit(canExit);
break;
}
@@ -1731,7 +1438,6 @@
if (value == node->function()) {
m_foundConstants = true;
ASSERT(value);
- node->setCanExit(false);
break;
}
@@ -1766,12 +1472,10 @@
break;
}
}
- forNode(node->child1()).filter(SpecCell);
clobberWorld(node->codeOrigin, indexInBlock);
break;
case GetGlobalVar:
- node->setCanExit(false);
forNode(node).makeTop();
break;
@@ -1781,34 +1485,23 @@
case PutGlobalVar:
case PutGlobalVarCheck:
- node->setCanExit(false);
break;
case CheckHasInstance:
node->setCanExit(true);
- forNode(node->child1()).filter(SpecCell);
// Sadly, we don't propagate the fact that we've done CheckHasInstance
break;
case InstanceOf:
node->setCanExit(true);
// Again, sadly, we don't propagate the fact that we've done 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) && !(forNode(node->child1()).m_type & ~SpecCell))
- forNode(node->child1()).filter(SpecCell);
- forNode(node->child2()).filter(SpecCell);
forNode(node).set(SpecBoolean);
break;
case Phi:
case Flush:
case PhantomLocal:
- node->setCanExit(false);
- break;
-
case Breakpoint:
- node->setCanExit(false);
break;
case Call:
@@ -1836,7 +1529,6 @@
case InlineStart:
case Nop:
case CountExecution:
- node->setCanExit(false);
break;
case LastNodeType:
@@ -1847,6 +1539,21 @@
return m_isValid;
}
+bool AbstractState::executeEffects(unsigned indexInBlock)
+{
+ return executeEffects(indexInBlock, m_block->at(indexInBlock));
+}
+
+bool AbstractState::execute(unsigned indexInBlock)
+{
+ Node* node = m_block->at(indexInBlock);
+ if (!startExecuting(node))
+ return true;
+
+ executeEdges(node);
+ return executeEffects(indexInBlock, node);
+}
+
inline void AbstractState::clobberWorld(const CodeOrigin& codeOrigin, unsigned indexInBlock)
{
clobberCapturedVars(codeOrigin);
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index 6198613..b04d719 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -158,7 +158,52 @@
// if execution should continue past this node. Notably, it will return true
// for block terminals, so long as those terminals are not Return or variants
// of Throw.
- bool execute(unsigned);
+ //
+ // This is guaranteed to be equivalent to doing:
+ //
+ // if (state.startExecuting(index)) {
+ // state.executeEdges(index);
+ // result = state.executeEffects(index);
+ // } else
+ // result = true;
+ bool execute(unsigned indexInBlock);
+
+ // Indicate the start of execution of the node. It resets any state in the node,
+ // that is progressively built up by executeEdges() and executeEffects(). In
+ // particular, this resets canExit(), so if you want to "know" between calls of
+ // startExecuting() and executeEdges()/Effects() whether the last run of the
+ // analysis concluded that the node can exit, you should probably set that
+ // information aside prior to calling startExecuting().
+ bool startExecuting(Node*);
+ bool startExecuting(unsigned indexInBlock);
+
+ // Abstractly execute the edges of the given node. This runs filterEdgeByUse()
+ // on all edges of the node. You can skip this step, if you have already used
+ // filterEdgeByUse() (or some equivalent) on each edge.
+ void executeEdges(Node*);
+ void executeEdges(unsigned indexInBlock);
+
+ ALWAYS_INLINE void filterEdgeByUse(Node* node, Edge edge)
+ {
+#if !ASSERT_DISABLED
+ switch (edge.useKind()) {
+ case KnownInt32Use:
+ case KnownNumberUse:
+ case KnownCellUse:
+ ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())));
+ break;
+ default:
+ break;
+ }
+#endif // !ASSERT_DISABLED
+
+ filterByType(node, edge.node(), typeFilterFor(edge.useKind()));
+ }
+
+ // Abstractly execute the effects of the given node. This changes the abstract
+ // state assuming that edges have already been filtered.
+ bool executeEffects(unsigned indexInBlock);
+ bool executeEffects(unsigned indexInBlock, Node*);
// Did the last executed node clobber the world?
bool didClobber() const { return m_didClobber; }
@@ -191,50 +236,6 @@
static bool mergeVariableBetweenBlocks(AbstractValue& destination, AbstractValue& source, Node* destinationNode, Node* sourceNode);
- void speculateInt32Unary(Node* node, bool forceCanExit = false)
- {
- AbstractValue& childValue = forNode(node->child1());
- node->setCanExit(forceCanExit || !isInt32Speculation(childValue.m_type));
- childValue.filter(SpecInt32);
- }
-
- void speculateNumberUnary(Node* node)
- {
- AbstractValue& childValue = forNode(node->child1());
- node->setCanExit(!isNumberSpeculation(childValue.m_type));
- childValue.filter(SpecNumber);
- }
-
- void speculateBooleanUnary(Node* node)
- {
- AbstractValue& childValue = forNode(node->child1());
- node->setCanExit(!isBooleanSpeculation(childValue.m_type));
- childValue.filter(SpecBoolean);
- }
-
- void speculateInt32Binary(Node* node, bool forceCanExit = false)
- {
- AbstractValue& childValue1 = forNode(node->child1());
- AbstractValue& childValue2 = forNode(node->child2());
- node->setCanExit(
- forceCanExit
- || !isInt32Speculation(childValue1.m_type)
- || !isInt32Speculation(childValue2.m_type));
- childValue1.filter(SpecInt32);
- childValue2.filter(SpecInt32);
- }
-
- void speculateNumberBinary(Node* node)
- {
- AbstractValue& childValue1 = forNode(node->child1());
- AbstractValue& childValue2 = forNode(node->child2());
- node->setCanExit(
- !isNumberSpeculation(childValue1.m_type)
- || !isNumberSpeculation(childValue2.m_type));
- childValue1.filter(SpecNumber);
- childValue2.filter(SpecNumber);
- }
-
enum BooleanResult {
UnknownBooleanResult,
DefinitelyFalse,
@@ -259,6 +260,17 @@
return true;
}
+ ALWAYS_INLINE void filterByType(Node* node, Node* child, SpeculatedType type)
+ {
+ AbstractValue& value = forNode(child);
+ if (value.m_type & ~type)
+ node->setCanExit(true);
+ value.filter(type);
+ }
+
+ void verifyEdge(Node*, Edge);
+ void verifyEdges(Node*);
+
CodeBlock* m_codeBlock;
Graph& m_graph;
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index ab96aee..a80cd58 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -234,6 +234,9 @@
void filter(const StructureSet& other)
{
+ // FIXME: This could be optimized for the common case of m_type not
+ // having structures, array modes, or a specific value.
+ // https://bugs.webkit.org/show_bug.cgi?id=109663
m_type &= other.speculationFromStructures();
m_arrayModes &= other.arrayModesFromStructures();
m_currentKnownStructure.filter(other);
diff --git a/Source/JavaScriptCore/dfg/DFGAdjacencyList.h b/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
index ff95e75..ad7e225 100644
--- a/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
+++ b/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
@@ -47,9 +47,6 @@
AdjacencyList() { }
AdjacencyList(Kind kind)
-#if !ASSERT_DISABLED
- : m_kind(kind)
-#endif
{
if (kind == Variable) {
m_words[0].m_encodedWord = UINT_MAX;
@@ -57,19 +54,13 @@
}
}
- AdjacencyList(Kind kind, Node* child1, Node* child2, Node* child3)
-#if !ASSERT_DISABLED
- : m_kind(Fixed)
-#endif
+ AdjacencyList(Kind kind, Edge child1, Edge child2, Edge child3)
{
ASSERT_UNUSED(kind, kind == Fixed);
initialize(child1, child2, child3);
}
AdjacencyList(Kind kind, unsigned firstChild, unsigned numChildren)
-#if !ASSERT_DISABLED
- : m_kind(Variable)
-#endif
{
ASSERT_UNUSED(kind, kind == Variable);
setFirstChild(firstChild);
@@ -79,21 +70,18 @@
const Edge& child(unsigned i) const
{
ASSERT(i < Size);
- ASSERT(m_kind == Fixed);
return m_words[i];
}
Edge& child(unsigned i)
{
ASSERT(i < Size);
- ASSERT(m_kind == Fixed);
return m_words[i];
}
void setChild(unsigned i, Edge nodeUse)
{
ASSERT(i < Size);
- ASSERT(m_kind == Fixed);
m_words[i] = nodeUse;
}
@@ -125,9 +113,6 @@
void reset()
{
-#if !ASSERT_DISABLED
- m_kind = Fixed;
-#endif
initialize();
}
@@ -142,34 +127,24 @@
unsigned firstChild() const
{
- ASSERT(m_kind == Variable);
return m_words[0].m_encodedWord;
}
void setFirstChild(unsigned firstChild)
{
- ASSERT(m_kind == Variable);
m_words[0].m_encodedWord = firstChild;
}
unsigned numChildren() const
{
- ASSERT(m_kind == Variable);
return m_words[1].m_encodedWord;
}
void setNumChildren(unsigned numChildren)
{
- ASSERT(m_kind == Variable);
m_words[1].m_encodedWord = numChildren;
}
-#if !ASSERT_DISABLED
- Kind kind() const { return m_kind; }
-#endif
private:
Edge m_words[Size];
-#if !ASSERT_DISABLED
- Kind m_kind;
-#endif
};
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGAllocator.h b/Source/JavaScriptCore/dfg/DFGAllocator.h
index f4d3eb5..5f42a05 100644
--- a/Source/JavaScriptCore/dfg/DFGAllocator.h
+++ b/Source/JavaScriptCore/dfg/DFGAllocator.h
@@ -43,7 +43,11 @@
// anything. You can just call freeAll() instead.
// - You call free() on all T's that you allocated, and never use freeAll().
-template<typename T>
+// forcedCellSize: set this to 0 if you're happy with the default alignment, or set it
+// to a non-zero value if you want to forcibly align the allocations to a certain
+// value. When you do this, Allocator will ASSERT that forcedCellAlignment >= sizeof(T).
+
+template<typename T, unsigned forcedCellAlignment>
class Allocator {
public:
Allocator();
@@ -63,13 +67,24 @@
void* bumpAllocate();
void* freeListAllocate();
void* allocateSlow();
-
+
+ static size_t cellSize()
+ {
+ if (!forcedCellAlignment)
+ return sizeof(T);
+
+ ASSERT(forcedCellAlignment >= sizeof(T));
+ return forcedCellAlignment;
+ }
+
struct Region {
static size_t size() { return 64 * KB; }
- static size_t headerSize() { return std::max(sizeof(Region), sizeof(T)); }
- static unsigned numberOfThingsPerRegion() { return (size() - headerSize()) / sizeof(T); }
- T* data() { return bitwise_cast<T*>(bitwise_cast<char*>(this) + headerSize()); }
- bool isInThisRegion(const T* pointer) { return static_cast<unsigned>(pointer - data()) < numberOfThingsPerRegion(); }
+ static size_t headerSize() { return std::max(sizeof(Region), cellSize()); }
+ static unsigned numberOfThingsPerRegion() { return (size() - headerSize()) / cellSize(); }
+ static size_t payloadSize() { return numberOfThingsPerRegion() * cellSize(); }
+ char* payloadBegin() { return bitwise_cast<char*>(this) + headerSize(); }
+ char* payloadEnd() { return payloadBegin() + payloadSize(); }
+ bool isInThisRegion(const T* pointer) { return static_cast<size_t>(bitwise_cast<char*>(pointer) - payloadBegin()) < payloadSize(); }
static Region* regionFor(const T* pointer) { return bitwise_cast<Region*>(bitwise_cast<uintptr_t>(pointer) & ~(size() - 1)); }
PageAllocationAligned m_allocation;
@@ -82,26 +97,26 @@
Region* m_regionHead;
void** m_freeListHead;
- T* m_bumpEnd;
- unsigned m_bumpRemaining;
+ char* m_bumpEnd;
+ size_t m_bumpRemaining;
};
-template<typename T>
-inline Allocator<T>::Allocator()
+template<typename T, unsigned forcedCellAlignment>
+inline Allocator<T, forcedCellAlignment>::Allocator()
: m_regionHead(0)
, m_freeListHead(0)
, m_bumpRemaining(0)
{
}
-template<typename T>
-inline Allocator<T>::~Allocator()
+template<typename T, unsigned forcedCellAlignment>
+inline Allocator<T, forcedCellAlignment>::~Allocator()
{
reset();
}
-template<typename T>
-ALWAYS_INLINE void* Allocator<T>::allocate()
+template<typename T, unsigned forcedCellAlignment>
+ALWAYS_INLINE void* Allocator<T, forcedCellAlignment>::allocate()
{
void* result = bumpAllocate();
if (LIKELY(!!result))
@@ -109,8 +124,8 @@
return freeListAllocate();
}
-template<typename T>
-void Allocator<T>::free(T* object)
+template<typename T, unsigned forcedCellAlignment>
+void Allocator<T, forcedCellAlignment>::free(T* object)
{
object->~T();
@@ -119,8 +134,8 @@
m_freeListHead = cell;
}
-template<typename T>
-void Allocator<T>::freeAll()
+template<typename T, unsigned forcedCellAlignment>
+void Allocator<T, forcedCellAlignment>::freeAll()
{
if (!m_regionHead) {
ASSERT(!m_bumpRemaining);
@@ -142,8 +157,8 @@
startBumpingIn(m_regionHead);
}
-template<typename T>
-void Allocator<T>::reset()
+template<typename T, unsigned forcedCellAlignment>
+void Allocator<T, forcedCellAlignment>::reset()
{
freeRegionsStartingAt(m_regionHead);
@@ -152,38 +167,38 @@
m_bumpRemaining = 0;
}
-template<typename T>
-unsigned Allocator<T>::indexOf(const T* object)
+template<typename T, unsigned forcedCellAlignment>
+unsigned Allocator<T, forcedCellAlignment>::indexOf(const T* object)
{
unsigned baseIndex = 0;
for (Region* region = m_regionHead; region; region = region->m_next) {
if (region->isInThisRegion(object))
- return baseIndex + (object - region->data());
+ return baseIndex + (bitwise_cast<char*>(object) - region->payloadBegin()) / cellSize();
baseIndex += Region::numberOfThingsPerRegion();
}
CRASH();
return 0;
}
-template<typename T>
-Allocator<T>* Allocator<T>::allocatorOf(const T* object)
+template<typename T, unsigned forcedCellAlignment>
+Allocator<T, forcedCellAlignment>* Allocator<T, forcedCellAlignment>::allocatorOf(const T* object)
{
return Region::regionFor(object)->m_allocator;
}
-template<typename T>
-ALWAYS_INLINE void* Allocator<T>::bumpAllocate()
+template<typename T, unsigned forcedCellAlignment>
+ALWAYS_INLINE void* Allocator<T, forcedCellAlignment>::bumpAllocate()
{
- if (unsigned remaining = m_bumpRemaining) {
- remaining--;
+ if (size_t remaining = m_bumpRemaining) {
+ remaining -= cellSize();
m_bumpRemaining = remaining;
- return m_bumpEnd - (remaining + 1);
+ return m_bumpEnd - (remaining + cellSize());
}
return 0;
}
-template<typename T>
-void* Allocator<T>::freeListAllocate()
+template<typename T, unsigned forcedCellAlignment>
+void* Allocator<T, forcedCellAlignment>::freeListAllocate()
{
void** result = m_freeListHead;
if (UNLIKELY(!result))
@@ -192,8 +207,8 @@
return result;
}
-template<typename T>
-void* Allocator<T>::allocateSlow()
+template<typename T, unsigned forcedCellAlignment>
+void* Allocator<T, forcedCellAlignment>::allocateSlow()
{
ASSERT(!m_freeListHead);
ASSERT(!m_bumpRemaining);
@@ -216,8 +231,8 @@
return result;
}
-template<typename T>
-void Allocator<T>::freeRegionsStartingAt(typename Allocator<T>::Region* region)
+template<typename T, unsigned forcedCellAlignment>
+void Allocator<T, forcedCellAlignment>::freeRegionsStartingAt(typename Allocator<T, forcedCellAlignment>::Region* region)
{
while (region) {
Region* nextRegion = region->m_next;
@@ -226,11 +241,11 @@
}
}
-template<typename T>
-void Allocator<T>::startBumpingIn(typename Allocator<T>::Region* region)
+template<typename T, unsigned forcedCellAlignment>
+void Allocator<T, forcedCellAlignment>::startBumpingIn(typename Allocator<T, forcedCellAlignment>::Region* region)
{
- m_bumpEnd = region->data() + Region::numberOfThingsPerRegion();
- m_bumpRemaining = Region::numberOfThingsPerRegion();
+ m_bumpEnd = region->payloadEnd();
+ m_bumpRemaining = Region::payloadSize();
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 75f2139..419f9e4 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -698,6 +698,18 @@
{
Node* result = m_graph.addNode(
DontRefChildren, DontRefNode, SpecNone,
+ op, currentCodeOrigin(), Edge(child1), Edge(child2), Edge(child3));
+ ASSERT(op != Phi);
+ m_currentBlock->append(result);
+
+ if (defaultFlags(op) & NodeMustGenerate)
+ m_graph.refChildren(result);
+ return result;
+ }
+ Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
+ {
+ Node* result = m_graph.addNode(
+ DontRefChildren, DontRefNode, SpecNone,
op, currentCodeOrigin(), child1, child2, child3);
ASSERT(op != Phi);
m_currentBlock->append(result);
@@ -710,7 +722,7 @@
{
Node* result = m_graph.addNode(
DontRefChildren, DontRefNode, SpecNone,
- op, currentCodeOrigin(), info, child1, child2, child3);
+ op, currentCodeOrigin(), info, Edge(child1), Edge(child2), Edge(child3));
if (op == Phi)
m_currentBlock->phis.append(result);
else
@@ -724,7 +736,7 @@
{
Node* result = m_graph.addNode(
DontRefChildren, DontRefNode, SpecNone,
- op, currentCodeOrigin(), info1, info2, child1, child2, child3);
+ op, currentCodeOrigin(), info1, info2, Edge(child1), Edge(child2), Edge(child3));
ASSERT(op != Phi);
m_currentBlock->append(result);
@@ -1465,7 +1477,7 @@
if (argumentCountIncludingThis == 2) { // Math.min(x)
Node* result = get(registerOffset + argumentToOperand(1));
- addToGraph(CheckNumber, result);
+ addToGraph(Phantom, Edge(result, NumberUse));
setIntrinsicResult(usesResult, resultOperand, result);
return true;
}
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 0a5602e..cf07c22 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -969,7 +969,7 @@
case GetByVal:
// If this is accessing arguments then it's potentially accessing locals.
- if (node->child1()->shouldSpeculateArguments())
+ if (node->arrayMode().type() == Array::Arguments)
result.mayBeAccessed = true;
break;
@@ -1002,6 +1002,8 @@
Edge edge = node->children.child(i);
if (!edge)
continue;
+ if (edge.useKind() != UntypedUse)
+ continue; // Keep the type check.
if (edge->flags() & NodeRelevantToOSR)
continue;
@@ -1014,18 +1016,11 @@
}
}
- enum PredictionHandlingMode { RequireSamePrediction, AllowPredictionMismatch };
- bool setReplacement(Node* replacement, PredictionHandlingMode predictionHandlingMode = RequireSamePrediction)
+ bool setReplacement(Node* replacement)
{
if (!replacement)
return false;
- // Be safe. Don't try to perform replacements if the predictions don't
- // agree.
- if (predictionHandlingMode == RequireSamePrediction
- && m_currentNode->prediction() != replacement->prediction())
- return false;
-
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLogF(" Replacing @%u -> @%u", m_currentNode->index(), replacement->index());
#endif
@@ -1230,7 +1225,7 @@
case JSConstant:
// This is strange, but necessary. Some phases will convert nodes to constants,
// which may result in duplicated constants. We use CSE to clean this up.
- setReplacement(constantCSE(node), AllowPredictionMismatch);
+ setReplacement(constantCSE(node));
break;
case WeakJSConstant:
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index 6a275cc..bdc80fa 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -83,12 +83,6 @@
static void dump(Node* value, PrintStream& out);
};
-enum UseKind {
- UntypedUse,
- DoubleUse,
- LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
-};
-
// Use RefChildren if the child ref counts haven't already been adjusted using
// other means and either of the following is true:
// - The node you're creating is MustGenerate.
@@ -106,19 +100,6 @@
DontRefNode
};
-inline const char* useKindToString(UseKind useKind)
-{
- switch (useKind) {
- case UntypedUse:
- return "";
- case DoubleUse:
- return "d";
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return 0;
- }
-}
-
inline bool isARMv7s()
{
#if CPU(APPLE_ARMV7S)
@@ -236,6 +217,8 @@
GloballyUnified
};
+enum OperandSpeculationMode { AutomaticOperandSpeculation, ManualOperandSpeculation };
+
enum SpeculationDirection { ForwardSpeculation, BackwardSpeculation };
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 3dae83e..06c7d6e 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -103,10 +103,9 @@
set = node->structure();
else
set = node->structureSet();
- if (!isCellSpeculation(value.m_type))
- break;
if (value.m_currentKnownStructure.isSubsetOf(set)) {
ASSERT(node->refCount() == 1);
+ m_state.execute(indexInBlock); // Catch the fact that we may filter on cell.
node->setOpAndDefaultFlags(Phantom);
eliminated = true;
break;
@@ -114,8 +113,11 @@
StructureAbstractValue& structureValue = value.m_futurePossibleStructure;
if (structureValue.isSubsetOf(set)
&& structureValue.hasSingleton()) {
- node->convertToStructureTransitionWatchpoint(structureValue.singleton());
- changed = true;
+ Structure* structure = structureValue.singleton();
+ m_state.execute(indexInBlock); // Catch the fact that we may filter on cell.
+ node->convertToStructureTransitionWatchpoint(structure);
+ eliminated = true;
+ break;
}
break;
}
@@ -149,10 +151,11 @@
case GetById:
case GetByIdFlush: {
CodeOrigin codeOrigin = node->codeOrigin;
- Node* child = node->child1().node();
+ Edge childEdge = node->child1();
+ Node* child = childEdge.node();
unsigned identifierNumber = node->identifierNumber();
- if (!isCellSpeculation(child->prediction()))
+ if (childEdge.useKind() != CellUse)
break;
Structure* structure = m_state.forNode(child).bestProvenStructure();
@@ -164,8 +167,11 @@
GetByIdStatus status = GetByIdStatus::computeFor(
globalData(), structure, codeBlock()->identifier(identifierNumber));
- if (!status.isSimple())
+ if (!status.isSimple()) {
+ // FIXME: We could handle prototype cases.
+ // https://bugs.webkit.org/show_bug.cgi?id=110386
break;
+ }
ASSERT(status.structureSet().size() == 1);
ASSERT(status.chain().isEmpty());
@@ -181,18 +187,24 @@
ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
m_insertionSet.insertNode(
indexInBlock, RefChildren, DontRefNode, SpecNone,
- StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
+ StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), childEdge);
+ } else if (m_state.forNode(child).m_type & ~SpecCell) {
+ m_insertionSet.insertNode(
+ indexInBlock, RefChildren, DontRefNode, SpecNone,
+ Phantom, codeOrigin, childEdge);
}
- Node* propertyStorage;
+ childEdge.setUseKind(KnownCellUse);
+
+ Edge propertyStorage;
child->ref();
if (isInlineOffset(status.offset()))
- propertyStorage = child;
+ propertyStorage = childEdge;
else {
- propertyStorage = m_insertionSet.insertNode(
+ propertyStorage = Edge(m_insertionSet.insertNode(
indexInBlock, DontRefChildren, RefNode, SpecNone, GetButterfly, codeOrigin,
- child);
+ childEdge));
}
node->convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
@@ -207,9 +219,12 @@
case PutById:
case PutByIdDirect: {
CodeOrigin codeOrigin = node->codeOrigin;
- Node* child = node->child1().node();
+ Edge childEdge = node->child1();
+ Node* child = childEdge.node();
unsigned identifierNumber = node->identifierNumber();
+ ASSERT(childEdge.useKind() == CellUse);
+
Structure* structure = m_state.forNode(child).bestProvenStructure();
if (!structure)
break;
@@ -238,9 +253,15 @@
ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
m_insertionSet.insertNode(
indexInBlock, RefChildren, DontRefNode, SpecNone,
- StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
+ StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), childEdge);
+ } else if (m_state.forNode(child).m_type & ~SpecCell) {
+ m_insertionSet.insertNode(
+ indexInBlock, RefChildren, DontRefNode, SpecNone,
+ Phantom, codeOrigin, childEdge);
}
+ childEdge.setUseKind(KnownCellUse);
+
StructureTransitionData* transitionData = 0;
if (status.isSimpleTransition()) {
transitionData = m_graph.addStructureTransitionData(
@@ -264,38 +285,38 @@
}
}
- Node* propertyStorage;
+ Edge propertyStorage;
if (isInlineOffset(status.offset())) {
child->ref(); // The child will be used as the property index, so ref it to reflect the double use.
- propertyStorage = child;
+ propertyStorage = childEdge;
} else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
- propertyStorage = m_insertionSet.insertNode(
- indexInBlock, RefChildren, RefNode, SpecNone, GetButterfly, codeOrigin, child);
+ propertyStorage = Edge(m_insertionSet.insertNode(
+ indexInBlock, RefChildren, RefNode, SpecNone, GetButterfly, codeOrigin, childEdge));
} else if (!structure->outOfLineCapacity()) {
ASSERT(status.newStructure()->outOfLineCapacity());
ASSERT(!isInlineOffset(status.offset()));
- propertyStorage = m_insertionSet.insertNode(
+ propertyStorage = Edge(m_insertionSet.insertNode(
indexInBlock, RefChildren, RefNode, SpecNone, AllocatePropertyStorage,
- codeOrigin, OpInfo(transitionData), child);
+ codeOrigin, OpInfo(transitionData), childEdge));
} else {
ASSERT(structure->outOfLineCapacity());
ASSERT(status.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity());
ASSERT(!isInlineOffset(status.offset()));
- propertyStorage = m_insertionSet.insertNode(
+ propertyStorage = Edge(m_insertionSet.insertNode(
indexInBlock, RefChildren, RefNode, SpecNone, ReallocatePropertyStorage,
codeOrigin, OpInfo(transitionData),
- child,
- m_insertionSet.insertNode(
+ childEdge,
+ Edge(m_insertionSet.insertNode(
indexInBlock, DontRefChildren, DontRefNode, SpecNone, GetButterfly,
- codeOrigin, child));
+ codeOrigin, childEdge))));
}
if (status.isSimpleTransition()) {
m_insertionSet.insertNode(
indexInBlock, RefChildren, DontRefNode, SpecNone, PutStructure, codeOrigin,
- OpInfo(transitionData), child);
+ OpInfo(transitionData), childEdge);
}
node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
@@ -340,7 +361,7 @@
m_graph.convertToConstant(node, value);
Node* phantom = m_insertionSet.insertNode(
indexInBlock, DontRefChildren, DontRefNode, SpecNone, PhantomLocal,
- codeOrigin, OpInfo(variable), phi);
+ codeOrigin, OpInfo(variable), Edge(phi));
block->variablesAtHead.operand(variable->local()) = phantom;
block->variablesAtTail.operand(variable->local()) = phantom;
@@ -391,13 +412,13 @@
if (cell->structure()->transitionWatchpointSetIsStillValid()) {
m_insertionSet.insertNode(
indexInBlock, RefChildren, DontRefNode, SpecNone, StructureTransitionWatchpoint,
- codeOrigin, OpInfo(cell->structure()), weakConstant);
+ codeOrigin, OpInfo(cell->structure()), Edge(weakConstant, CellUse));
return;
}
m_insertionSet.insertNode(
indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure, codeOrigin,
- OpInfo(m_graph.addStructureSet(cell->structure())), weakConstant);
+ OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse));
}
// This is necessary because the CFA may reach conclusions about constants based on its
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index ad2b794..7e102da 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -144,8 +144,6 @@
if (!changed)
break;
- dfg.resetExitStates();
- performFixup(dfg);
performCPSRethreading(dfg);
}
diff --git a/Source/JavaScriptCore/dfg/DFGEdge.cpp b/Source/JavaScriptCore/dfg/DFGEdge.cpp
index 3cb69b9..bc921e9 100644
--- a/Source/JavaScriptCore/dfg/DFGEdge.cpp
+++ b/Source/JavaScriptCore/dfg/DFGEdge.cpp
@@ -34,7 +34,9 @@
void Edge::dump(PrintStream& out) const
{
- out.print(useKindToString(useKind()), node());
+ if (useKind() != UntypedUse)
+ out.print(useKind(), ":");
+ out.print(node());
}
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGEdge.h b/Source/JavaScriptCore/dfg/DFGEdge.h
index c475d0d..e6703ed 100644
--- a/Source/JavaScriptCore/dfg/DFGEdge.h
+++ b/Source/JavaScriptCore/dfg/DFGEdge.h
@@ -31,6 +31,7 @@
#if ENABLE(DFG_JIT)
#include "DFGCommon.h"
+#include "DFGUseKind.h"
namespace JSC { namespace DFG {
@@ -62,12 +63,18 @@
m_encodedWord = makeWord(node, useKind());
}
+ UseKind useKindUnchecked() const
+ {
+ unsigned masked = m_encodedWord & (((1 << shift()) - 1));
+ ASSERT(masked < LastUseKind);
+ UseKind result = static_cast<UseKind>(masked);
+ ASSERT(node() || result == UntypedUse);
+ return result;
+ }
UseKind useKind() const
{
ASSERT(node());
- unsigned masked = m_encodedWord & (((1 << shift()) - 1));
- ASSERT(masked < LastUseKind);
- return static_cast<UseKind>(masked);
+ return useKindUnchecked();
}
void setUseKind(UseKind useKind)
{
@@ -96,7 +103,7 @@
private:
friend class AdjacencyList;
- static uint32_t shift() { return 2; }
+ static uint32_t shift() { return 4; }
static uintptr_t makeWord(Node* node, UseKind useKind)
{
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;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index f019ce4..eed8286 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -346,45 +346,14 @@
}
}
-// FIXME: Convert this to be iterative, not recursive.
-#define DO_TO_CHILDREN(node, thingToDo) do { \
- Node* _node = (node); \
- if (_node->flags() & NodeHasVarArgs) { \
- for (unsigned _childIdx = _node->firstChild(); \
- _childIdx < _node->firstChild() + _node->numChildren(); \
- _childIdx++) { \
- if (!!m_varArgChildren[_childIdx]) \
- thingToDo(m_varArgChildren[_childIdx]); \
- } \
- } else { \
- if (!_node->child1()) { \
- ASSERT( \
- !_node->child2() \
- && !_node->child3()); \
- break; \
- } \
- thingToDo(_node->child1()); \
- \
- if (!_node->child2()) { \
- ASSERT(!_node->child3()); \
- break; \
- } \
- thingToDo(_node->child2()); \
- \
- if (!_node->child3()) \
- break; \
- thingToDo(_node->child3()); \
- } \
- } while (false)
-
void Graph::refChildren(Node* op)
{
- DO_TO_CHILDREN(op, ref);
+ DFG_NODE_DO_TO_CHILDREN(*this, op, ref);
}
void Graph::derefChildren(Node* op)
{
- DO_TO_CHILDREN(op, deref);
+ DFG_NODE_DO_TO_CHILDREN(*this, op, deref);
}
void Graph::dethread()
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 1cf695e..3e71018 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -77,7 +77,7 @@
enum AddSpeculationMode {
DontSpeculateInteger,
- SpeculateIntegerButAlwaysWatchOverflow,
+ SpeculateIntegerAndTruncateConstants,
SpeculateInteger
};
@@ -100,10 +100,14 @@
refChildren(node);
return node;
}
- Edge ref(Edge nodeUse)
+ Edge ref(Edge edge)
{
- ref(nodeUse.node());
- return nodeUse;
+ ref(edge.node());
+ return edge;
+ }
+ Edge ref(Node*, Edge edge)
+ {
+ return ref(edge);
}
void deref(Node* node)
@@ -115,9 +119,13 @@
if (node->postfixDeref() == 1)
derefChildren(node);
}
- void deref(Edge nodeUse)
+ void deref(Edge edge)
{
- deref(nodeUse.node());
+ deref(edge.node());
+ }
+ void deref(Node*, Edge edge)
+ {
+ deref(edge);
}
// When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
@@ -174,9 +182,9 @@
for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
performSubstitutionForEdge(m_varArgChildren[childIdx], shouldGenerate);
} else {
- performSubstitutionForEdge(node->children.child1(), shouldGenerate);
- performSubstitutionForEdge(node->children.child2(), shouldGenerate);
- performSubstitutionForEdge(node->children.child3(), shouldGenerate);
+ performSubstitutionForEdge(node->child1(), shouldGenerate);
+ performSubstitutionForEdge(node->child2(), shouldGenerate);
+ performSubstitutionForEdge(node->child3(), shouldGenerate);
}
}
@@ -530,9 +538,7 @@
bool isPredictedNumerical(Node* node)
{
- SpeculatedType left = node->child1()->prediction();
- SpeculatedType right = node->child2()->prediction();
- return isNumberSpeculation(left) && isNumberSpeculation(right);
+ return isNumerical(node->child1().useKind()) && isNumerical(node->child2().useKind());
}
// Note that a 'true' return does not actually mean that the ByVal access clobbers nothing.
@@ -781,7 +787,7 @@
if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48)
return DontSpeculateInteger;
- return nodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateIntegerButAlwaysWatchOverflow : DontSpeculateInteger;
+ return nodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateIntegerAndTruncateConstants : DontSpeculateInteger;
}
bool mulImmediateShouldSpeculateInteger(Node* mul, Node* variable, Node* immediate)
@@ -830,6 +836,36 @@
return *binarySearch<BlockIndex, unsigned>(linkingTargets, linkingTargets.size(), bytecodeBegin, GetBytecodeBeginForBlock(*this));
}
+#define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \
+ Node* _node = (node); \
+ if (_node->flags() & NodeHasVarArgs) { \
+ for (unsigned _childIdx = _node->firstChild(); \
+ _childIdx < _node->firstChild() + _node->numChildren(); \
+ _childIdx++) { \
+ if (!!(graph).m_varArgChildren[_childIdx]) \
+ thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \
+ } \
+ } else { \
+ if (!_node->child1()) { \
+ ASSERT( \
+ !_node->child2() \
+ && !_node->child3()); \
+ break; \
+ } \
+ thingToDo(_node, _node->child1()); \
+ \
+ if (!_node->child2()) { \
+ ASSERT(!_node->child3()); \
+ break; \
+ } \
+ thingToDo(_node, _node->child2()); \
+ \
+ if (!_node->child3()) \
+ break; \
+ thingToDo(_node, _node->child3()); \
+ } \
+ } while (false)
+
} } // namespace JSC::DFG
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 28ec073..bc0172f 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -95,11 +95,10 @@
, m_prediction(SpecNone)
{
setOpAndDefaultFlags(op);
- ASSERT(!!(m_flags & NodeHasVarArgs) == (children.kind() == AdjacencyList::Variable));
}
// Construct a node with up to 3 children, no immediate value.
- Node(NodeType op, CodeOrigin codeOrigin, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
+ Node(NodeType op, CodeOrigin codeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
: codeOrigin(codeOrigin)
, children(AdjacencyList::Fixed, child1, child2, child3)
, m_virtualRegister(InvalidVirtualRegister)
@@ -111,7 +110,7 @@
}
// Construct a node with up to 3 children and an immediate value.
- Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
+ Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
: codeOrigin(codeOrigin)
, children(AdjacencyList::Fixed, child1, child2, child3)
, m_virtualRegister(InvalidVirtualRegister)
@@ -124,7 +123,7 @@
}
// Construct a node with up to 3 children and two immediate values.
- Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
+ Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge())
: codeOrigin(codeOrigin)
, children(AdjacencyList::Fixed, child1, child2, child3)
, m_virtualRegister(InvalidVirtualRegister)
@@ -294,22 +293,22 @@
convertToStructureTransitionWatchpoint(structureSet().singletonStructure());
}
- void convertToGetByOffset(unsigned storageAccessDataIndex, Node* storage)
+ void convertToGetByOffset(unsigned storageAccessDataIndex, Edge storage)
{
ASSERT(m_op == GetById || m_op == GetByIdFlush);
m_opInfo = storageAccessDataIndex;
- children.setChild1(Edge(storage));
+ children.setChild1(storage);
m_op = GetByOffset;
m_flags &= ~NodeClobbersWorld;
}
- void convertToPutByOffset(unsigned storageAccessDataIndex, Node* storage)
+ void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage)
{
ASSERT(m_op == PutById || m_op == PutByIdDirect);
m_opInfo = storageAccessDataIndex;
children.setChild3(children.child2());
children.setChild2(children.child1());
- children.setChild1(Edge(storage));
+ children.setChild1(storage);
m_op = PutByOffset;
m_flags &= ~NodeClobbersWorld;
}
@@ -949,9 +948,10 @@
case DoubleAsInt32:
case PhantomArguments:
return true;
- case Phantom:
case Nop:
return false;
+ case Phantom:
+ return child1().useKindUnchecked() != UntypedUse || child2().useKindUnchecked() != UntypedUse || child3().useKindUnchecked() != UntypedUse;
default:
return shouldGenerate();
}
@@ -995,7 +995,7 @@
return m_refCount--;
}
- Edge child1()
+ Edge& child1()
{
ASSERT(!(m_flags & NodeHasVarArgs));
return children.child1();
@@ -1009,13 +1009,13 @@
return children.child1Unchecked();
}
- Edge child2()
+ Edge& child2()
{
ASSERT(!(m_flags & NodeHasVarArgs));
return children.child2();
}
- Edge child3()
+ Edge& child3()
{
ASSERT(!(m_flags & NodeHasVarArgs));
return children.child3();
@@ -1033,6 +1033,17 @@
return children.numChildren();
}
+ UseKind binaryUseKind()
+ {
+ ASSERT(child1().useKind() == child2().useKind());
+ return child1().useKind();
+ }
+
+ bool isBinaryUseKind(UseKind useKind)
+ {
+ return child1().useKind() == useKind && child2().useKind() == useKind;
+ }
+
SpeculatedType prediction()
{
return m_prediction;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeAllocator.h b/Source/JavaScriptCore/dfg/DFGNodeAllocator.h
index afd72e5..f5765bf 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeAllocator.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeAllocator.h
@@ -35,7 +35,16 @@
namespace JSC { namespace DFG {
-typedef Allocator<Node> NodeAllocator;
+// The second template argument to Allocator is the expected size of Node rounded up to
+// 16 bytes. This is baked in to give us assertion coverage for when Node increases in
+// size. We don't want its size to increase for no good reason. The multiple-of-16
+// property is asserted by DFG::Edge, which expects to never see any of the low 4 bits
+// of a Node* being non-zero.
+#if USE(JSVALUE64)
+typedef Allocator<Node, 112> NodeAllocator;
+#else
+typedef Allocator<Node, 80> NodeAllocator;
+#endif
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
index 1e83fae..d00006c 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
+++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
@@ -34,7 +34,7 @@
const char* nodeFlagsAsString(NodeFlags flags)
{
- if (!flags)
+ if (!(flags ^ NodeDoesNotExit))
return "<empty>";
static const int size = 128;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 0e80a7b..86a5e3f 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -96,8 +96,6 @@
macro(ForwardInt32ToDouble, NodeResultNumber) \
/* Used to speculate that a double value is actually an integer. */\
macro(DoubleAsInt32, NodeResultInt32) \
- /* Used to record places where we must check if a value is a number. */\
- macro(CheckNumber, NodeMustGenerate) \
\
/* Nodes for arithmetic operations. */\
macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index a63fc6d..ed27080 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -805,7 +805,6 @@
case PutStructure:
case TearOffActivation:
case TearOffArguments:
- case CheckNumber:
case CheckArgumentsNotCreated:
case GlobalVarWatchpoint:
case GarbageValue:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index e5f4665..617b9a3 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -108,14 +108,14 @@
{
if (!m_compileOkay)
return;
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
m_jit.appendExitInfo(jumpToFail);
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size()));
}
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail);
}
@@ -123,7 +123,7 @@
{
if (!m_compileOkay)
return OSRExitJumpPlaceholder();
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
unsigned index = m_jit.codeBlock()->numberOfOSRExits();
m_jit.appendExitInfo();
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size()));
@@ -132,7 +132,7 @@
OSRExitJumpPlaceholder SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
return speculationCheck(kind, jsValueSource, nodeUse.node());
}
@@ -140,14 +140,14 @@
{
if (!m_compileOkay)
return;
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
m_jit.appendExitInfo(jumpsToFail);
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size()));
}
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, const MacroAssembler::JumpList& jumpsToFail)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
speculationCheck(kind, jsValueSource, nodeUse.node(), jumpsToFail);
}
@@ -155,7 +155,7 @@
{
if (!m_compileOkay)
return;
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
m_jit.codeBlock()->appendSpeculationRecovery(recovery);
m_jit.appendExitInfo(jumpToFail);
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.graph().methodOfGettingAValueProfileFor(node), this, m_stream->size(), m_jit.codeBlock()->numberOfSpeculationRecoveries()));
@@ -163,7 +163,7 @@
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
speculationCheck(kind, jsValueSource, nodeUse.node(), jumpToFail, recovery);
}
@@ -174,11 +174,16 @@
convertLastOSRExitToForward();
}
+void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery, SpeculationDirection direction)
+{
+ speculationCheck(kind, jsValueSource, edge.node(), jumpToFail, recovery, direction);
+}
+
JumpReplacementWatchpoint* SpeculativeJIT::speculationWatchpoint(ExitKind kind, JSValueSource jsValueSource, Node* node)
{
if (!m_compileOkay)
return 0;
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
m_jit.appendExitInfo(JITCompiler::JumpList());
OSRExit& exit = m_jit.codeBlock()->osrExit(
m_jit.codeBlock()->appendOSRExit(OSRExit(
@@ -280,14 +285,14 @@
void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
speculationCheck(kind, jsValueSource, node, jumpToFail);
convertLastOSRExitToForward(valueRecovery);
}
void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, Node* node, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
speculationCheck(kind, jsValueSource, node, jumpsToFail);
convertLastOSRExitToForward(valueRecovery);
}
@@ -300,9 +305,14 @@
speculationCheck(kind, jsValueSource, node, jumpToFail);
}
+void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge edge, MacroAssembler::Jump jumpToFail, SpeculationDirection direction)
+{
+ speculationCheck(kind, jsValueSource, edge.node(), jumpToFail, direction);
+}
+
void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("SpeculativeJIT was terminated.\n");
#endif
@@ -314,13 +324,13 @@
void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Edge nodeUse)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
terminateSpeculativeExecution(kind, jsValueRegs, nodeUse.node());
}
void SpeculativeJIT::terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, Node* node, SpeculationDirection direction)
{
- ASSERT(m_isCheckingArgumentTypes || m_currentNode->canExit());
+ ASSERT(m_isCheckingArgumentTypes || m_canExit);
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("SpeculativeJIT was terminated.\n");
#endif
@@ -330,6 +340,26 @@
m_compileOkay = false;
}
+void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail)
+{
+ ASSERT(needsTypeCheck(edge, typesPassedThrough));
+ m_state.forNode(edge).filter(typesPassedThrough);
+ speculationCheck(BadType, source, edge, jumpToFail);
+}
+
+void SpeculativeJIT::forwardTypeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery& valueRecovery)
+{
+ typeCheck(source, edge, typesPassedThrough, jumpToFail);
+ convertLastOSRExitToForward(valueRecovery);
+}
+
+void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, SpeculationDirection direction)
+{
+ typeCheck(source, edge, typesPassedThrough, jumpToFail);
+ if (direction == ForwardSpeculation)
+ convertLastOSRExitToForward();
+}
+
void SpeculativeJIT::addSlowPathGenerator(PassOwnPtr<SlowPathGenerator> slowPathGenerator)
{
m_slowPathGenerators.append(slowPathGenerator.leakPtr());
@@ -872,9 +902,9 @@
arrayify(node, base.gpr(), property.gpr());
}
-GPRReg SpeculativeJIT::fillStorage(Node* node)
+GPRReg SpeculativeJIT::fillStorage(Edge edge)
{
- VirtualRegister virtualRegister = node->virtualRegister();
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
@@ -888,7 +918,7 @@
}
// Must be a cell; fill it as a cell and then return the pointer.
- return fillSpeculateCell(node, BackwardSpeculation);
+ return fillSpeculateCell(edge, BackwardSpeculation);
}
case DataFormatStorage: {
@@ -898,7 +928,7 @@
}
default:
- return fillSpeculateCell(node, BackwardSpeculation);
+ return fillSpeculateCell(edge, BackwardSpeculation);
}
}
@@ -1509,20 +1539,20 @@
// so can be no intervening nodes to also reference the compare.
ASSERT(node->adjustedRefCount() == 1);
- if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node()))
+ if (node->isBinaryUseKind(Int32Use))
compilePeepHoleIntegerBranch(node, branchNode, condition);
- else if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node()))
+ else if (node->isBinaryUseKind(NumberUse))
compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
else if (node->op() == CompareEq) {
- if (node->child1()->shouldSpeculateString() || node->child2()->shouldSpeculateString()) {
+ if (node->isBinaryUseKind(StringUse)) {
nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
return true;
}
- if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject())
+ if (node->isBinaryUseKind(ObjectUse))
compilePeepHoleObjectEquality(node, branchNode);
- else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther())
+ else if (node->child1().useKind() == ObjectUse && node->child2().useKind() == ObjectOrOtherUse)
compilePeepHoleObjectToObjectOrOtherEquality(node->child1(), node->child2(), branchNode);
- else if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject())
+ else if (node->child1().useKind() == ObjectOrOtherUse && node->child2().useKind() == ObjectUse)
compilePeepHoleObjectToObjectOrOtherEquality(node->child2(), node->child1(), branchNode);
else {
nonSpeculativePeepholeBranch(node, branchNode, condition, operation);
@@ -1645,6 +1675,10 @@
for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
m_currentNode = block[m_indexInBlock];
+#if !ASSERT_DISABLED
+ m_canExit = m_currentNode->canExit();
+#endif
+ bool shouldExecuteEffects = m_state.startExecuting(m_currentNode);
m_jit.setForNode(m_currentNode);
m_codeOriginForOSR = m_currentNode->codeOrigin;
if (!m_currentNode->shouldGenerate()) {
@@ -1711,9 +1745,17 @@
}
} else {
+ if (verboseCompilationEnabled()) {
+ dataLogF(
+ "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x",
+ (int)m_currentNode->index(),
+ m_currentNode->codeOrigin.bytecodeIndex, m_jit.debugOffset());
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_currentNode->index(), m_currentNode->codeOrigin.bytecodeIndex, m_jit.debugOffset());
+ dataLog(" ");
+#else
+ dataLog("\n");
#endif
+ }
#if DFG_ENABLE(JIT_BREAK_ON_EVERY_NODE)
m_jit.breakpoint();
#endif
@@ -1759,7 +1801,8 @@
#endif
// Make sure that the abstract state is rematerialized for the next node.
- m_state.execute(m_indexInBlock);
+ if (shouldExecuteEffects)
+ m_state.executeEffects(m_indexInBlock);
if (m_currentNode->shouldGenerate())
checkConsistency();
@@ -1906,13 +1949,10 @@
FPRReg valueReg = value.fpr();
- if (!isRealNumberSpeculation(m_state.forNode(child3).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(), child3, SpecRealNumber,
+ m_jit.branchDouble(
+ MacroAssembler::DoubleNotEqualOrUnordered, valueReg, valueReg));
if (!m_compileOkay)
return;
@@ -2104,7 +2144,8 @@
void SpeculativeJIT::compileValueToInt32(Node* node)
{
- if (node->child1()->shouldSpeculateInteger()) {
+ switch (node->child1().useKind()) {
+ case Int32Use: {
SpeculateIntegerOperand op1(this, node->child1());
GPRTemporary result(this, op1);
m_jit.move(op1.gpr(), result.gpr());
@@ -2112,58 +2153,53 @@
return;
}
- if (node->child1()->shouldSpeculateBoolean()) {
- SpeculateBooleanOperand op1(this, node->child1());
- GPRTemporary result(this, op1);
-
- m_jit.move(op1.gpr(), result.gpr());
- m_jit.and32(JITCompiler::TrustedImm32(1), result.gpr());
-
- integerResult(result.gpr(), node);
- return;
- }
-
- switch (checkGeneratedTypeForToInt32(node->child1().node())) {
- case GeneratedOperandInteger: {
- SpeculateIntegerOperand op1(this, node->child1());
- GPRTemporary result(this, op1);
- m_jit.move(op1.gpr(), result.gpr());
- integerResult(result.gpr(), node, op1.format());
- return;
- }
- case GeneratedOperandDouble: {
- GPRTemporary result(this);
- SpeculateDoubleOperand op1(this, Edge(node->child1().node(), DoubleUse)); // SpeculateDoubleOperand will assert that this is a double use. We force it to think that it was a double use, since we are inferring that we ought to emit a double use quite late.
- FPRReg fpr = op1.fpr();
- GPRReg gpr = result.gpr();
- JITCompiler::Jump notTruncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateFailed);
+ case NumberUse:
+ case NotCellUse: {
+ switch (checkGeneratedTypeForToInt32(node->child1().node())) {
+ case GeneratedOperandInteger: {
+ SpeculateIntegerOperand op1(this, node->child1(), BackwardSpeculation, ManualOperandSpeculation);
+ GPRTemporary result(this, op1);
+ m_jit.move(op1.gpr(), result.gpr());
+ integerResult(result.gpr(), node, op1.format());
+ return;
+ }
+ case GeneratedOperandDouble: {
+ GPRTemporary result(this);
+ SpeculateDoubleOperand op1(this, node->child1(), BackwardSpeculation, ManualOperandSpeculation);
+ FPRReg fpr = op1.fpr();
+ GPRReg gpr = result.gpr();
+ JITCompiler::Jump notTruncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateFailed);
- addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this, toInt32, gpr, fpr));
+ addSlowPathGenerator(slowPathCall(notTruncatedToInteger, this, toInt32, gpr, fpr));
- integerResult(gpr, node);
- return;
- }
- case GeneratedOperandJSValue: {
- GPRTemporary result(this);
+ integerResult(gpr, node);
+ return;
+ }
+ case GeneratedOperandJSValue: {
+ GPRTemporary result(this);
#if USE(JSVALUE64)
- JSValueOperand op1(this, node->child1());
+ JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
- GPRReg gpr = op1.gpr();
- GPRReg resultGpr = result.gpr();
- FPRTemporary tempFpr(this);
- FPRReg fpr = tempFpr.fpr();
+ GPRReg gpr = op1.gpr();
+ GPRReg resultGpr = result.gpr();
+ FPRTemporary tempFpr(this);
+ FPRReg fpr = tempFpr.fpr();
- JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
- JITCompiler::JumpList converted;
+ JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
+ JITCompiler::JumpList converted;
- if (!isNumberSpeculation(m_state.forNode(node->child1()).m_type)) {
- if (node->child1()->shouldSpeculateNumber())
- speculationCheck(BadType, JSValueRegs(gpr), node->child1(), m_jit.branchTest64(MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister));
- else {
+ if (node->child1().useKind() == NumberUse) {
+ DFG_TYPE_CHECK(
+ JSValueRegs(gpr), node->child1(), SpecNumber,
+ m_jit.branchTest64(
+ MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister));
+ } else {
JITCompiler::Jump isNumber = m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister);
- if (m_state.forNode(node->child1()).m_type & SpecCell)
- speculationCheck(BadType, JSValueRegs(gpr), node->child1(), m_jit.branchTest64(JITCompiler::Zero, gpr, GPRInfo::tagMaskRegister));
+ DFG_TYPE_CHECK(
+ JSValueRegs(gpr), node->child1(), ~SpecCell,
+ m_jit.branchTest64(
+ JITCompiler::Zero, gpr, GPRInfo::tagMaskRegister));
// It's not a cell: so true turns into 1 and all else turns into 0.
m_jit.compare64(JITCompiler::Equal, gpr, TrustedImm32(ValueTrue), resultGpr);
@@ -2171,52 +2207,56 @@
isNumber.link(&m_jit);
}
- }
- // First, if we get here we have a double encoded as a JSValue
- m_jit.move(gpr, resultGpr);
- unboxDouble(resultGpr, fpr);
+ // First, if we get here we have a double encoded as a JSValue
+ m_jit.move(gpr, resultGpr);
+ unboxDouble(resultGpr, fpr);
- silentSpillAllRegisters(resultGpr);
- callOperation(toInt32, resultGpr, fpr);
- silentFillAllRegisters(resultGpr);
+ silentSpillAllRegisters(resultGpr);
+ callOperation(toInt32, resultGpr, fpr);
+ silentFillAllRegisters(resultGpr);
- converted.append(m_jit.jump());
+ converted.append(m_jit.jump());
- isInteger.link(&m_jit);
- m_jit.zeroExtend32ToPtr(gpr, resultGpr);
+ isInteger.link(&m_jit);
+ m_jit.zeroExtend32ToPtr(gpr, resultGpr);
- converted.link(&m_jit);
+ converted.link(&m_jit);
#else
- Node* childNode = node->child1().node();
- VirtualRegister virtualRegister = childNode->virtualRegister();
- GenerationInfo& info = m_generationInfo[virtualRegister];
+ Node* childNode = node->child1().node();
+ VirtualRegister virtualRegister = childNode->virtualRegister();
+ GenerationInfo& info = m_generationInfo[virtualRegister];
- JSValueOperand op1(this, node->child1());
+ JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
- GPRReg payloadGPR = op1.payloadGPR();
- GPRReg resultGpr = result.gpr();
+ GPRReg payloadGPR = op1.payloadGPR();
+ GPRReg resultGpr = result.gpr();
- JITCompiler::JumpList converted;
+ JITCompiler::JumpList converted;
- if (info.registerFormat() == DataFormatJSInteger)
- m_jit.move(payloadGPR, resultGpr);
- else {
- GPRReg tagGPR = op1.tagGPR();
- FPRTemporary tempFpr(this);
- FPRReg fpr = tempFpr.fpr();
- FPRTemporary scratch(this);
+ if (info.registerFormat() == DataFormatJSInteger)
+ m_jit.move(payloadGPR, resultGpr);
+ else {
+ GPRReg tagGPR = op1.tagGPR();
+ FPRTemporary tempFpr(this);
+ FPRReg fpr = tempFpr.fpr();
+ FPRTemporary scratch(this);
- JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
+ JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
- if (!isNumberSpeculation(m_state.forNode(node->child1()).m_type)) {
- if (node->child1()->shouldSpeculateNumber())
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node->child1(), m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
- else {
+ if (node->child1().useKind() == NumberUse) {
+ DFG_TYPE_CHECK(
+ JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecNumber,
+ m_jit.branch32(
+ MacroAssembler::AboveOrEqual, tagGPR,
+ TrustedImm32(JSValue::LowestTag)));
+ } else {
JITCompiler::Jump isNumber = m_jit.branch32(MacroAssembler::Below, tagGPR, TrustedImm32(JSValue::LowestTag));
- if (m_state.forNode(node->child1()).m_type & SpecCell)
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node->child1(), m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::CellTag)));
+ DFG_TYPE_CHECK(
+ JSValueRegs(tagGPR, payloadGPR), node->child1(), ~SpecCell,
+ m_jit.branch32(
+ JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::CellTag)));
// It's not a cell: so true turns into 1 and all else turns into 0.
JITCompiler::Jump isBoolean = m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::BooleanTag));
@@ -2229,28 +2269,46 @@
isNumber.link(&m_jit);
}
+
+ unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
+
+ silentSpillAllRegisters(resultGpr);
+ callOperation(toInt32, resultGpr, fpr);
+ silentFillAllRegisters(resultGpr);
+
+ converted.append(m_jit.jump());
+
+ isInteger.link(&m_jit);
+ m_jit.move(payloadGPR, resultGpr);
+
+ converted.link(&m_jit);
}
-
- unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
-
- silentSpillAllRegisters(resultGpr);
- callOperation(toInt32, resultGpr, fpr);
- silentFillAllRegisters(resultGpr);
-
- converted.append(m_jit.jump());
-
- isInteger.link(&m_jit);
- m_jit.move(payloadGPR, resultGpr);
-
- converted.link(&m_jit);
- }
#endif
- integerResult(resultGpr, node);
+ integerResult(resultGpr, node);
+ return;
+ }
+ case GeneratedOperandTypeUnknown:
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
return;
}
- case GeneratedOperandTypeUnknown:
+
+ case BooleanUse: {
+ SpeculateBooleanOperand op1(this, node->child1());
+ GPRTemporary result(this, op1);
+
+ m_jit.move(op1.gpr(), result.gpr());
+ m_jit.and32(JITCompiler::TrustedImm32(1), result.gpr());
+
+ integerResult(result.gpr(), node);
+ return;
+ }
+
+ default:
ASSERT(!m_compileOkay);
- break;
+ return;
}
}
@@ -2313,14 +2371,14 @@
ASSERT(!isInt32Constant(node->child1().node())); // This should have been constant folded.
if (isInt32Speculation(m_state.forNode(node->child1()).m_type)) {
- SpeculateIntegerOperand op1(this, node->child1());
+ SpeculateIntegerOperand op1(this, node->child1(), BackwardSpeculation, ManualOperandSpeculation);
FPRTemporary result(this);
m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
doubleResult(result.fpr(), node);
return;
}
- JSValueOperand op1(this, node->child1());
+ JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
FPRTemporary result(this);
#if USE(JSVALUE64)
@@ -2333,15 +2391,15 @@
JITCompiler::Jump isInteger = m_jit.branch64(
MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister);
- if (!isNumberSpeculation(m_state.forNode(node->child1()).m_type)) {
+ if (needsTypeCheck(node->child1(), SpecNumber)) {
if (node->op() == ForwardInt32ToDouble) {
- forwardSpeculationCheck(
- BadType, JSValueRegs(op1GPR), node->child1().node(),
+ forwardTypeCheck(
+ JSValueRegs(op1GPR), node->child1(), SpecNumber,
m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister),
ValueRecovery::inGPR(op1GPR, DataFormatJS));
} else {
- speculationCheck(
- BadType, JSValueRegs(op1GPR), node->child1(),
+ typeCheck(
+ JSValueRegs(op1GPR), node->child1(), SpecNumber,
m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
}
}
@@ -2364,15 +2422,15 @@
JITCompiler::Jump isInteger = m_jit.branch32(
MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag));
- if (!isNumberSpeculation(m_state.forNode(node->child1()).m_type)) {
+ if (needsTypeCheck(node->child1(), SpecNumber)) {
if (node->op() == ForwardInt32ToDouble) {
- forwardSpeculationCheck(
- BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1().node(),
+ forwardTypeCheck(
+ JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecNumber,
m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)),
ValueRecovery::inPair(op1TagGPR, op1PayloadGPR));
} else {
- speculationCheck(
- BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(),
+ typeCheck(
+ JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecNumber,
m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
}
}
@@ -2525,49 +2583,64 @@
m_jit.move(Imm32(toInt32(d)), scratchReg);
value.adopt(scratch);
valueGPR = scratchReg;
- } else if (valueUse->shouldSpeculateInteger()) {
- SpeculateIntegerOperand valueOp(this, valueUse);
- GPRTemporary scratch(this);
- GPRReg scratchReg = scratch.gpr();
- m_jit.move(valueOp.gpr(), scratchReg);
- if (rounding == ClampRounding) {
- ASSERT(elementSize == 1);
- compileClampIntegerToByte(m_jit, scratchReg);
- }
- value.adopt(scratch);
- valueGPR = scratchReg;
- } else if (rounding == ClampRounding) {
- ASSERT(elementSize == 1);
- SpeculateDoubleOperand valueOp(this, valueUse);
- GPRTemporary result(this);
- FPRTemporary floatScratch(this);
- FPRReg fpr = valueOp.fpr();
- GPRReg gpr = result.gpr();
- compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
- value.adopt(result);
- valueGPR = gpr;
} else {
- SpeculateDoubleOperand valueOp(this, valueUse);
- GPRTemporary result(this);
- FPRReg fpr = valueOp.fpr();
- GPRReg gpr = result.gpr();
- MacroAssembler::Jump notNaN = m_jit.branchDouble(MacroAssembler::DoubleEqual, fpr, fpr);
- m_jit.xorPtr(gpr, gpr);
- MacroAssembler::Jump fixed = m_jit.jump();
- notNaN.link(&m_jit);
-
- MacroAssembler::Jump failed;
- if (signedness == SignedTypedArray)
- failed = m_jit.branchTruncateDoubleToInt32(fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
- else
- failed = m_jit.branchTruncateDoubleToUint32(fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
-
- addSlowPathGenerator(slowPathCall(failed, this, toInt32, gpr, fpr));
-
- fixed.link(&m_jit);
- value.adopt(result);
- valueGPR = gpr;
+ switch (valueUse.useKind()) {
+ case Int32Use: {
+ SpeculateIntegerOperand valueOp(this, valueUse);
+ GPRTemporary scratch(this);
+ GPRReg scratchReg = scratch.gpr();
+ m_jit.move(valueOp.gpr(), scratchReg);
+ if (rounding == ClampRounding) {
+ ASSERT(elementSize == 1);
+ compileClampIntegerToByte(m_jit, scratchReg);
+ }
+ value.adopt(scratch);
+ valueGPR = scratchReg;
+ break;
+ }
+
+ case NumberUse: {
+ if (rounding == ClampRounding) {
+ ASSERT(elementSize == 1);
+ SpeculateDoubleOperand valueOp(this, valueUse);
+ GPRTemporary result(this);
+ FPRTemporary floatScratch(this);
+ FPRReg fpr = valueOp.fpr();
+ GPRReg gpr = result.gpr();
+ compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
+ value.adopt(result);
+ valueGPR = gpr;
+ } else {
+ SpeculateDoubleOperand valueOp(this, valueUse);
+ GPRTemporary result(this);
+ FPRReg fpr = valueOp.fpr();
+ GPRReg gpr = result.gpr();
+ MacroAssembler::Jump notNaN = m_jit.branchDouble(MacroAssembler::DoubleEqual, fpr, fpr);
+ m_jit.xorPtr(gpr, gpr);
+ MacroAssembler::Jump fixed = m_jit.jump();
+ notNaN.link(&m_jit);
+
+ MacroAssembler::Jump failed;
+ if (signedness == SignedTypedArray)
+ failed = m_jit.branchTruncateDoubleToInt32(fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
+ else
+ failed = m_jit.branchTruncateDoubleToUint32(fpr, gpr, MacroAssembler::BranchIfTruncateFailed);
+
+ addSlowPathGenerator(slowPathCall(failed, this, toInt32, gpr, fpr));
+
+ fixed.link(&m_jit);
+ value.adopt(result);
+ valueGPR = gpr;
+ }
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
+
ASSERT_UNUSED(valueGPR, valueGPR != property);
ASSERT(valueGPR != base);
ASSERT(valueGPR != storageReg);
@@ -2709,8 +2782,7 @@
void SpeculativeJIT::compileInstanceOf(Node* node)
{
- if ((!!(node->child1()->prediction() & ~SpecCell) && !!(m_state.forNode(node->child1()).m_type & ~SpecCell))
- || node->child1()->adjustedRefCount() == 1) {
+ if (node->child1().useKind() == UntypedUse) {
// It might not be a cell. Speculate less aggressively.
// Or: it might only be used once (i.e. by us), so we get zero benefit
// from speculating any more aggressively than we absolutely need to.
@@ -2948,9 +3020,10 @@
void SpeculativeJIT::compileAdd(Node* node)
{
- if (m_jit.graph().addShouldSpeculateInteger(node)) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
if (isNumberConstant(node->child1().node())) {
- int32_t imm1 = valueOfNumberConstantAsInt32(node->child1().node());
+ int32_t imm1 = valueOfInt32Constant(node->child1().node());
SpeculateIntegerOperand op2(this, node->child2());
GPRTemporary result(this);
@@ -2966,7 +3039,7 @@
if (isNumberConstant(node->child2().node())) {
SpeculateIntegerOperand op1(this, node->child1());
- int32_t imm2 = valueOfNumberConstantAsInt32(node->child2().node());
+ int32_t imm2 = valueOfInt32Constant(node->child2().node());
GPRTemporary result(this);
if (nodeCanTruncateInteger(node->arithNodeFlags())) {
@@ -3008,8 +3081,8 @@
integerResult(gprResult, node);
return;
}
-
- if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
+
+ case NumberUse: {
SpeculateDoubleOperand op1(this, node->child1());
SpeculateDoubleOperand op2(this, node->child2());
FPRTemporary result(this, op1, op2);
@@ -3021,22 +3094,26 @@
doubleResult(result.fpr(), node);
return;
}
-
- if (node->op() == ValueAdd) {
+
+ case UntypedUse: {
+ RELEASE_ASSERT(node->op() == ValueAdd);
compileValueAdd(node);
return;
}
-
- // We don't handle this yet. :-(
- terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
void SpeculativeJIT::compileArithSub(Node* node)
{
- if (m_jit.graph().addShouldSpeculateInteger(node)) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
if (isNumberConstant(node->child2().node())) {
SpeculateIntegerOperand op1(this, node->child1());
- int32_t imm2 = valueOfNumberConstantAsInt32(node->child2().node());
+ int32_t imm2 = valueOfInt32Constant(node->child2().node());
GPRTemporary result(this);
if (nodeCanTruncateInteger(node->arithNodeFlags())) {
@@ -3056,7 +3133,7 @@
}
if (isNumberConstant(node->child1().node())) {
- int32_t imm1 = valueOfNumberConstantAsInt32(node->child1().node());
+ int32_t imm1 = valueOfInt32Constant(node->child1().node());
SpeculateIntegerOperand op2(this, node->child2());
GPRTemporary result(this);
@@ -3084,20 +3161,29 @@
return;
}
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
- FPRTemporary result(this, op1);
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
+ FPRTemporary result(this, op1);
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.subDouble(reg1, reg2, result.fpr());
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.subDouble(reg1, reg2, result.fpr());
- doubleResult(result.fpr(), node);
+ doubleResult(result.fpr(), node);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
}
void SpeculativeJIT::compileArithNegate(Node* node)
{
- if (m_jit.graph().negateShouldSpeculateInteger(node)) {
+ switch (node->child1().useKind()) {
+ case Int32Use: {
SpeculateIntegerOperand op1(this, node->child1());
GPRTemporary result(this);
@@ -3115,17 +3201,26 @@
return;
}
- SpeculateDoubleOperand op1(this, node->child1());
- FPRTemporary result(this);
-
- m_jit.negateDouble(op1.fpr(), result.fpr());
-
- doubleResult(result.fpr(), node);
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ FPRTemporary result(this);
+
+ m_jit.negateDouble(op1.fpr(), result.fpr());
+
+ doubleResult(result.fpr(), node);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
}
void SpeculativeJIT::compileArithMul(Node* node)
{
- if (m_jit.graph().mulShouldSpeculateInteger(node)) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
SpeculateIntegerOperand op1(this, node->child1());
SpeculateIntegerOperand op2(this, node->child2());
GPRTemporary result(this);
@@ -3156,17 +3251,25 @@
integerResult(result.gpr(), node);
return;
}
-
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
- FPRTemporary result(this, op1, op2);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.mulDouble(reg1, reg2, result.fpr());
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
+ FPRTemporary result(this, op1, op2);
- doubleResult(result.fpr(), node);
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+
+ m_jit.mulDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), node);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
}
#if CPU(X86) || CPU(X86_64)
@@ -3276,25 +3379,33 @@
void SpeculativeJIT::compileArithMod(Node* node)
{
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
compileSoftModulo(node);
return;
}
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
- FPRReg op1FPR = op1.fpr();
- FPRReg op2FPR = op2.fpr();
+ FPRReg op1FPR = op1.fpr();
+ FPRReg op2FPR = op2.fpr();
- flushRegisters();
+ flushRegisters();
- FPRResult result(this);
-
- callOperation(fmodAsDFGOperation, result.fpr(), op1FPR, op2FPR);
+ FPRResult result(this);
- doubleResult(result.fpr(), node);
+ callOperation(fmodAsDFGOperation, result.fpr(), op1FPR, op2FPR);
+
+ doubleResult(result.fpr(), node);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return;
+ }
}
// Returns true if the compare is fused with a subsequent branch.
@@ -3303,33 +3414,33 @@
if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
return true;
- if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
+ if (node->isBinaryUseKind(Int32Use)) {
compileIntegerCompare(node, condition);
return false;
}
-
- if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
+
+ if (node->isBinaryUseKind(NumberUse)) {
compileDoubleCompare(node, doubleCondition);
return false;
}
if (node->op() == CompareEq) {
- if (node->child1()->shouldSpeculateString() || node->child2()->shouldSpeculateString()) {
+ if (node->isBinaryUseKind(StringUse)) {
nonSpeculativeNonPeepholeCompare(node, condition, operation);
return false;
}
-
- if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+
+ if (node->isBinaryUseKind(ObjectUse)) {
compileObjectEquality(node);
return false;
}
- if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
+ if (node->child1().useKind() == ObjectUse && node->child2().useKind() == ObjectOrOtherUse) {
compileObjectToObjectOrOtherEquality(node->child1(), node->child2());
return false;
}
- if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
+ if (node->child1().useKind() == ObjectOrOtherUse && node->child2().useKind() == ObjectUse) {
compileObjectToObjectOrOtherEquality(node->child2(), node->child1());
return false;
}
@@ -3417,7 +3528,8 @@
bool SpeculativeJIT::compileStrictEq(Node* node)
{
- if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
unsigned branchIndexInBlock = detectPeepHoleBranch();
if (branchIndexInBlock != UINT_MAX) {
Node* branchNode = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
@@ -3431,8 +3543,8 @@
compileIntegerCompare(node, MacroAssembler::Equal);
return false;
}
-
- if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
+
+ case NumberUse: {
unsigned branchIndexInBlock = detectPeepHoleBranch();
if (branchIndexInBlock != UINT_MAX) {
Node* branchNode = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
@@ -3446,10 +3558,12 @@
compileDoubleCompare(node, MacroAssembler::DoubleEqual);
return false;
}
-
- if (node->child1()->shouldSpeculateString() || node->child2()->shouldSpeculateString())
+
+ case StringUse: {
return nonSpeculativeStrictEq(node);
- if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+ }
+
+ case ObjectUse: {
unsigned branchIndexInBlock = detectPeepHoleBranch();
if (branchIndexInBlock != UINT_MAX) {
Node* branchNode = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
@@ -3463,8 +3577,15 @@
compileObjectEquality(node);
return false;
}
-
- return nonSpeculativeStrictEq(node);
+
+ case UntypedUse: {
+ return nonSpeculativeStrictEq(node);
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+ }
}
void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node)
@@ -3802,6 +3923,241 @@
return temporary.gpr();
}
+void SpeculativeJIT::speculateInt32(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecInt32))
+ return;
+
+ (SpeculateIntegerOperand(this, edge)).gpr();
+}
+
+void SpeculativeJIT::speculateNumber(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecNumber))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+#if USE(JSVALUE64)
+ JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, operand.gpr(), GPRInfo::tagTypeNumberRegister);
+ typeCheck(
+ JSValueRegs(operand.gpr()), edge, SpecNumber,
+ m_jit.branchTest64(MacroAssembler::Zero, operand.gpr(), GPRInfo::tagTypeNumberRegister));
+ isInteger.link(&m_jit);
+#else
+ JSValueOperand op1(this, edge);
+ JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, operand.tagGPR(), TrustedImm32(JSValue::Int32Tag));
+ typeCheck(
+ JSValueRegs(operand.tagGPR(), op1.payloadGPR()), edge, SpecNumber,
+ m_jit.branch32(MacroAssembler::AboveOrEqual, operand.tagGPR(), TrustedImm32(JSValue::LowestTag)));
+ isInteger.link(&m_jit);
+#endif
+}
+
+void SpeculativeJIT::speculateRealNumber(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecRealNumber))
+ return;
+
+ SpeculateDoubleOperand operand(this, edge);
+ FPRReg fpr = operand.fpr();
+ DFG_TYPE_CHECK(
+ JSValueRegs(), edge, SpecRealNumber,
+ m_jit.branchDouble(
+ MacroAssembler::DoubleNotEqualOrUnordered, fpr, fpr));
+}
+
+void SpeculativeJIT::speculateBoolean(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecBoolean))
+ return;
+
+ (SpeculateBooleanOperand(this, edge)).gpr();
+}
+
+void SpeculativeJIT::speculateCell(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecCell))
+ return;
+
+ (SpeculateCellOperand(this, edge)).gpr();
+}
+
+void SpeculativeJIT::speculateObject(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecObject))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(operand.gpr()), edge, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(operand.gpr(), JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+}
+
+void SpeculativeJIT::speculateObjectOrOther(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecObject | SpecOther))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+#if USE(JSVALUE64)
+ GPRReg gpr = operand.gpr();
+ MacroAssembler::Jump notCell = m_jit.branchTest64(
+ MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister);
+ DFG_TYPE_CHECK(
+ JSValueRegs(operand.gpr()), edge, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(gpr, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ MacroAssembler::Jump done = m_jit.jump();
+ notCell.link(&m_jit);
+ if (needsTypeCheck(edge, SpecCell | SpecOther)) {
+ m_jit.move(gpr, tempGPR);
+ m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR);
+
+ typeCheck(
+ JSValueRegs(gpr), edge, SpecCell | SpecOther,
+ m_jit.branch64(
+ MacroAssembler::NotEqual, tempGPR,
+ MacroAssembler::TrustedImm64(ValueNull)));
+ }
+ done.link(&m_jit);
+#else
+ GPRReg tagGPR = operand.tagGPR();
+ GPRReg payloadGPR = operand.payloadGPR();
+ MacroAssembler::Jump notCell =
+ m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag));
+ DFG_TYPE_CHECK(
+ JSValueRegs(tagGPR, payloadGPR), edge, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(payloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ MacroAssembler::Jump done = m_jit.jump();
+ notCell.link(&m_jit);
+ if (needsTypeCheck(edge, SpecCell | SpecOther)) {
+ m_jit.move(tagGPR, tempGPR);
+ m_jit.or32(TrustedImm32(1), tempGPR);
+
+ typeCheck(
+ JSValueRegs(tagGPR, payloadGPR), edge, SpecCell | SpecOther,
+ m_jit.branch32(
+ MacroAssembler::NotEqual, tempGPR,
+ MacroAssembler::TrustedImm32(JSValue::NullTag)));
+ }
+ done.link(&m_jit);
+#endif
+}
+
+void SpeculativeJIT::speculateString(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecString))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(operand.gpr()), edge, SpecString, m_jit.branchPtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(operand.gpr(), JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+}
+
+void SpeculativeJIT::speculateNotCell(Edge edge)
+{
+ if (!needsTypeCheck(edge, ~SpecCell))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+#if USE(JSVALUE64)
+ typeCheck(
+ JSValueRegs(operand.gpr()), edge, ~SpecCell,
+ m_jit.branchTest64(
+ JITCompiler::Zero, operand.gpr(), GPRInfo::tagMaskRegister));
+#else
+ typeCheck(
+ JSValueRegs(operand.tagGPR(), operand.payloadGPR()), edge, ~SpecCell,
+ m_jit.branch32(
+ JITCompiler::Equal, operand.tagGPR(), TrustedImm32(JSValue::CellTag)));
+#endif
+}
+
+void SpeculativeJIT::speculateOther(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecOther))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+#if USE(JSVALUE64)
+ m_jit.move(operand.gpr(), tempGPR);
+ m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR);
+ typeCheck(
+ JSValueRegs(operand.gpr()), edge, SpecOther,
+ m_jit.branch64(
+ MacroAssembler::NotEqual, tempGPR,
+ MacroAssembler::TrustedImm64(ValueNull)));
+#else
+ m_jit.move(operand.tagGPR(), tempGPR);
+ m_jit.or32(TrustedImm32(1), tempGPR);
+ typeCheck(
+ JSValueRegs(operand.tagGPR(), operand.payloadGPR()), edge, SpecOther,
+ m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(JSValue::NullTag)));
+#endif
+}
+
+void SpeculativeJIT::speculate(Node*, Edge edge)
+{
+ switch (edge.useKind()) {
+ case UntypedUse:
+ break;
+ case KnownInt32Use:
+ ASSERT(!needsTypeCheck(edge, SpecInt32));
+ break;
+ case KnownNumberUse:
+ ASSERT(!needsTypeCheck(edge, SpecNumber));
+ break;
+ case KnownCellUse:
+ ASSERT(!needsTypeCheck(edge, SpecCell));
+ break;
+ case Int32Use:
+ speculateInt32(edge);
+ break;
+ case RealNumberUse:
+ speculateRealNumber(edge);
+ break;
+ case NumberUse:
+ speculateNumber(edge);
+ break;
+ case BooleanUse:
+ speculateBoolean(edge);
+ break;
+ case CellUse:
+ speculateCell(edge);
+ break;
+ case ObjectUse:
+ speculateObject(edge);
+ break;
+ case ObjectOrOtherUse:
+ speculateObjectOrOther(edge);
+ break;
+ case StringUse:
+ speculateString(edge);
+ break;
+ case NotCellUse:
+ speculateNotCell(edge);
+ break;
+ case OtherUse:
+ speculateOther(edge);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
} } // namespace JSC::DFG
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 247274b..94f63a1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -121,13 +121,13 @@
}
}
- GPRReg fillInteger(Node*, DataFormat& returnFormat);
+ GPRReg fillInteger(Edge, DataFormat& returnFormat);
#if USE(JSVALUE64)
- GPRReg fillJSValue(Node*);
+ GPRReg fillJSValue(Edge);
#elif USE(JSVALUE32_64)
- bool fillJSValue(Node*, GPRReg&, GPRReg&, FPRReg&);
+ bool fillJSValue(Edge, GPRReg&, GPRReg&, FPRReg&);
#endif
- GPRReg fillStorage(Node*);
+ GPRReg fillStorage(Edge);
// lock and unlock GPR & FPR registers.
void lock(GPRReg reg)
@@ -295,11 +295,11 @@
// Called by the speculative operand types, below, to fill operand to
// machine registers, implicitly generating speculation checks as needed.
- GPRReg fillSpeculateInt(Node*, DataFormat& returnFormat, SpeculationDirection);
- GPRReg fillSpeculateIntStrict(Node*);
- FPRReg fillSpeculateDouble(Node*, SpeculationDirection);
- GPRReg fillSpeculateCell(Node*, SpeculationDirection);
- GPRReg fillSpeculateBoolean(Node*, SpeculationDirection);
+ GPRReg fillSpeculateInt(Edge, DataFormat& returnFormat, SpeculationDirection);
+ GPRReg fillSpeculateIntStrict(Edge);
+ FPRReg fillSpeculateDouble(Edge, SpeculationDirection);
+ GPRReg fillSpeculateCell(Edge, SpeculationDirection);
+ GPRReg fillSpeculateBoolean(Edge, SpeculationDirection);
GeneratedOperandType checkGeneratedTypeForToInt32(Node*);
void addSlowPathGenerator(PassOwnPtr<SlowPathGenerator>);
@@ -540,12 +540,6 @@
bool isFunctionConstant(Node* node) { return m_jit.graph().isFunctionConstant(node); }
int32_t valueOfInt32Constant(Node* node) { return m_jit.graph().valueOfInt32Constant(node); }
double valueOfNumberConstant(Node* node) { return m_jit.graph().valueOfNumberConstant(node); }
- int32_t valueOfNumberConstantAsInt32(Node* node)
- {
- if (isInt32Constant(node))
- return valueOfInt32Constant(node);
- return JSC::toInt32(valueOfNumberConstant(node));
- }
#if USE(JSVALUE32_64)
void* addressOfDoubleConstant(Node* node) { return m_jit.addressOfDoubleConstant(node); }
#endif
@@ -2023,9 +2017,9 @@
void compileObjectEquality(Node*);
void compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild);
void compileValueAdd(Node*);
- void compileObjectOrOtherLogicalNot(Edge value, bool needSpeculationCheck);
+ void compileObjectOrOtherLogicalNot(Edge value);
void compileLogicalNot(Node*);
- void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken, bool needSpeculationCheck);
+ void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken);
void emitBranch(Node*);
void compileIntegerCompare(Node*, MacroAssembler::RelationalCondition);
@@ -2178,7 +2172,9 @@
void forwardSpeculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const ValueRecovery& = ValueRecovery());
void forwardSpeculationCheck(ExitKind, JSValueSource, Node*, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& = ValueRecovery());
void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, SpeculationDirection);
+ void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, SpeculationDirection);
void speculationCheck(ExitKind, JSValueSource, Node*, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&, SpeculationDirection);
+ void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&, SpeculationDirection);
// Called when we statically determine that a speculation will fail.
void terminateSpeculativeExecution(ExitKind, JSValueRegs, Node*);
void terminateSpeculativeExecution(ExitKind, JSValueRegs, Edge);
@@ -2188,6 +2184,24 @@
JumpReplacementWatchpoint* forwardSpeculationWatchpoint(ExitKind = UncountableWatchpoint);
JumpReplacementWatchpoint* speculationWatchpoint(ExitKind, SpeculationDirection);
+ // Helpers for performing type checks on an edge stored in the given registers.
+ bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_state.forNode(edge).m_type & ~typesPassedThrough; }
+ void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail);
+ void forwardTypeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, const ValueRecovery&);
+ void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, SpeculationDirection);
+
+ void speculateInt32(Edge);
+ void speculateNumber(Edge);
+ void speculateRealNumber(Edge);
+ void speculateBoolean(Edge);
+ void speculateCell(Edge);
+ void speculateObject(Edge);
+ void speculateObjectOrOther(Edge);
+ void speculateString(Edge);
+ void speculateNotCell(Edge);
+ void speculateOther(Edge);
+ void speculate(Node*, Edge);
+
const TypedArrayDescriptor* typedArrayDescriptor(ArrayMode);
JITCompiler::Jump jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, ArrayMode, IndexingType, bool invert);
@@ -2197,7 +2211,7 @@
void arrayify(Node*);
template<bool strict>
- GPRReg fillSpeculateIntInternal(Node*, DataFormat& returnFormat, SpeculationDirection);
+ GPRReg fillSpeculateIntInternal(Edge, DataFormat& returnFormat, SpeculationDirection);
// It is possible, during speculative generation, to reach a situation in which we
// can statically determine a speculation will fail (for example, when two nodes
@@ -2247,6 +2261,9 @@
// The current node being generated.
BlockIndex m_block;
Node* m_currentNode;
+#if !ASSERT_DISABLED
+ bool m_canExit;
+#endif
unsigned m_indexInBlock;
// Virtual and physical register maps.
Vector<GenerationInfo, 32> m_generationInfo;
@@ -2305,17 +2322,17 @@
class IntegerOperand {
public:
- explicit IntegerOperand(SpeculativeJIT* jit, Edge use)
+ explicit IntegerOperand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_gprOrInvalid(InvalidGPRReg)
#ifndef NDEBUG
, m_format(DataFormatNone)
#endif
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == KnownInt32Use);
+ if (jit->isFilled(edge.node()))
gpr();
}
@@ -2325,9 +2342,14 @@
m_jit->unlock(m_gprOrInvalid);
}
+ Edge edge() const
+ {
+ return m_edge;
+ }
+
Node* node() const
{
- return m_node;
+ return edge().node();
}
DataFormat format()
@@ -2340,27 +2362,27 @@
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillInteger(node(), m_format);
+ m_gprOrInvalid = m_jit->fillInteger(m_edge, m_format);
return m_gprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
GPRReg m_gprOrInvalid;
DataFormat m_format;
};
class JSValueOperand {
public:
- explicit JSValueOperand(SpeculativeJIT* jit, Edge use)
+ explicit JSValueOperand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
#if USE(JSVALUE64)
, m_gprOrInvalid(InvalidGPRReg)
#elif USE(JSVALUE32_64)
@@ -2368,14 +2390,14 @@
#endif
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
#if USE(JSVALUE64)
- if (jit->isFilled(m_node))
+ if (jit->isFilled(node()))
gpr();
#elif USE(JSVALUE32_64)
m_register.pair.tagGPR = InvalidGPRReg;
m_register.pair.payloadGPR = InvalidGPRReg;
- if (jit->isFilled(m_node))
+ if (jit->isFilled(node()))
fill();
#endif
}
@@ -2396,17 +2418,22 @@
}
#endif
}
+
+ Edge edge() const
+ {
+ return m_edge;
+ }
Node* node() const
{
- return m_node;
+ return edge().node();
}
#if USE(JSVALUE64)
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillJSValue(node());
+ m_gprOrInvalid = m_jit->fillJSValue(m_edge);
return m_gprOrInvalid;
}
JSValueRegs jsValueRegs()
@@ -2419,7 +2446,7 @@
void fill()
{
if (m_register.pair.tagGPR == InvalidGPRReg && m_register.pair.payloadGPR == InvalidGPRReg)
- m_isDouble = !m_jit->fillJSValue(node(), m_register.pair.tagGPR, m_register.pair.payloadGPR, m_register.fpr);
+ m_isDouble = !m_jit->fillJSValue(m_edge, m_register.pair.tagGPR, m_register.pair.payloadGPR, m_register.fpr);
}
GPRReg tagGPR()
@@ -2451,12 +2478,12 @@
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
#if USE(JSVALUE64)
GPRReg m_gprOrInvalid;
#elif USE(JSVALUE32_64)
@@ -2473,14 +2500,14 @@
class StorageOperand {
public:
- explicit StorageOperand(SpeculativeJIT* jit, Edge use)
+ explicit StorageOperand(SpeculativeJIT* jit, Edge edge)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT(edge.useKind() == UntypedUse || edge.useKind() == KnownCellUse);
+ if (jit->isFilled(node()))
gpr();
}
@@ -2490,26 +2517,31 @@
m_jit->unlock(m_gprOrInvalid);
}
+ Edge edge() const
+ {
+ return m_edge;
+ }
+
Node* node() const
{
- return m_node;
+ return edge().node();
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillStorage(node());
+ m_gprOrInvalid = m_jit->fillStorage(edge());
return m_gprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
GPRReg m_gprOrInvalid;
};
@@ -2641,9 +2673,9 @@
class SpeculateIntegerOperand {
public:
- explicit SpeculateIntegerOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation)
+ explicit SpeculateIntegerOperand(SpeculativeJIT* jit, Edge edge, SpeculationDirection direction = BackwardSpeculation, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_gprOrInvalid(InvalidGPRReg)
#ifndef NDEBUG
, m_format(DataFormatNone)
@@ -2651,8 +2683,8 @@
, m_direction(direction)
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
+ if (jit->isFilled(node()))
gpr();
}
@@ -2661,10 +2693,15 @@
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
+
+ Edge edge() const
+ {
+ return m_edge;
+ }
Node* node() const
{
- return m_node;
+ return edge().node();
}
DataFormat format()
@@ -2677,18 +2714,18 @@
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillSpeculateInt(node(), m_format, m_direction);
+ m_gprOrInvalid = m_jit->fillSpeculateInt(edge(), m_format, m_direction);
return m_gprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
GPRReg m_gprOrInvalid;
DataFormat m_format;
SpeculationDirection m_direction;
@@ -2696,14 +2733,14 @@
class SpeculateStrictInt32Operand {
public:
- explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, Edge use)
+ explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
+ if (jit->isFilled(node()))
gpr();
}
@@ -2712,41 +2749,46 @@
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
+
+ Edge edge() const
+ {
+ return m_edge;
+ }
Node* node() const
{
- return m_node;
+ return edge().node();
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillSpeculateIntStrict(node());
+ m_gprOrInvalid = m_jit->fillSpeculateIntStrict(edge());
return m_gprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
GPRReg m_gprOrInvalid;
};
class SpeculateDoubleOperand {
public:
- explicit SpeculateDoubleOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation)
+ explicit SpeculateDoubleOperand(SpeculativeJIT* jit, Edge edge, SpeculationDirection direction = BackwardSpeculation, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_fprOrInvalid(InvalidFPRReg)
, m_direction(direction)
{
ASSERT(m_jit);
- ASSERT(use.useKind() == DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == NumberUse || edge.useKind() == KnownNumberUse || edge.useKind() == RealNumberUse));
+ if (jit->isFilled(node()))
fpr();
}
@@ -2755,42 +2797,47 @@
ASSERT(m_fprOrInvalid != InvalidFPRReg);
m_jit->unlock(m_fprOrInvalid);
}
+
+ Edge edge() const
+ {
+ return m_edge;
+ }
Node* node() const
{
- return m_node;
+ return edge().node();
}
FPRReg fpr()
{
if (m_fprOrInvalid == InvalidFPRReg)
- m_fprOrInvalid = m_jit->fillSpeculateDouble(node(), m_direction);
+ m_fprOrInvalid = m_jit->fillSpeculateDouble(edge(), m_direction);
return m_fprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
FPRReg m_fprOrInvalid;
SpeculationDirection m_direction;
};
class SpeculateCellOperand {
public:
- explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation)
+ explicit SpeculateCellOperand(SpeculativeJIT* jit, Edge edge, SpeculationDirection direction = BackwardSpeculation, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_gprOrInvalid(InvalidGPRReg)
, m_direction(direction)
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == CellUse || edge.useKind() == KnownCellUse || edge.useKind() == ObjectUse || edge.useKind() == StringUse));
+ if (jit->isFilled(node()))
gpr();
}
@@ -2799,42 +2846,47 @@
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
+
+ Edge edge() const
+ {
+ return m_edge;
+ }
Node* node() const
{
- return m_node;
+ return edge().node();
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillSpeculateCell(node(), m_direction);
+ m_gprOrInvalid = m_jit->fillSpeculateCell(edge(), m_direction);
return m_gprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
GPRReg m_gprOrInvalid;
SpeculationDirection m_direction;
};
class SpeculateBooleanOperand {
public:
- explicit SpeculateBooleanOperand(SpeculativeJIT* jit, Edge use, SpeculationDirection direction = BackwardSpeculation)
+ explicit SpeculateBooleanOperand(SpeculativeJIT* jit, Edge edge, SpeculationDirection direction = BackwardSpeculation, OperandSpeculationMode mode = AutomaticOperandSpeculation)
: m_jit(jit)
- , m_node(use.node())
+ , m_edge(edge)
, m_gprOrInvalid(InvalidGPRReg)
, m_direction(direction)
{
ASSERT(m_jit);
- ASSERT(use.useKind() != DoubleUse);
- if (jit->isFilled(m_node))
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
+ if (jit->isFilled(node()))
gpr();
}
@@ -2844,30 +2896,41 @@
m_jit->unlock(m_gprOrInvalid);
}
+ Edge edge() const
+ {
+ return m_edge;
+ }
+
Node* node() const
{
- return m_node;
+ return edge().node();
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
- m_gprOrInvalid = m_jit->fillSpeculateBoolean(node(), m_direction);
+ m_gprOrInvalid = m_jit->fillSpeculateBoolean(edge(), m_direction);
return m_gprOrInvalid;
}
void use()
{
- m_jit->use(m_node);
+ m_jit->use(node());
}
private:
SpeculativeJIT* m_jit;
- Node* m_node;
+ Edge m_edge;
GPRReg m_gprOrInvalid;
SpeculationDirection m_direction;
};
+#define DFG_TYPE_CHECK(source, edge, typesPassedThrough, jumpToFail) do { \
+ if (!needsTypeCheck((edge), (typesPassedThrough))) \
+ break; \
+ typeCheck((source), (edge), (typesPassedThrough), (jumpToFail)); \
+ } while (0)
+
} } // namespace JSC::DFG
#endif
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index f9f807c..9e2ff94 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -40,23 +40,25 @@
#if USE(JSVALUE32_64)
-GPRReg SpeculativeJIT::fillInteger(Node* node, DataFormat& returnFormat)
+GPRReg SpeculativeJIT::fillInteger(Edge edge, DataFormat& returnFormat)
{
- VirtualRegister virtualRegister = node->virtualRegister();
+ ASSERT(!needsTypeCheck(edge, SpecInt32));
+
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (info.registerFormat() == DataFormatNone) {
GPRReg gpr = allocate();
- if (node->hasConstant()) {
+ if (edge->hasConstant()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- if (isInt32Constant(node))
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(node)), gpr);
- else if (isNumberConstant(node))
+ if (isInt32Constant(edge.node()))
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
+ else if (isNumberConstant(edge.node()))
RELEASE_ASSERT_NOT_REACHED();
else {
- ASSERT(isJSConstant(node));
- JSValue jsValue = valueOfJSConstant(node);
+ ASSERT(isJSConstant(edge.node()));
+ JSValue jsValue = valueOfJSConstant(edge.node());
m_jit.move(MacroAssembler::Imm32(jsValue.payload()), gpr);
}
} else {
@@ -113,25 +115,25 @@
}
}
-bool SpeculativeJIT::fillJSValue(Node* node, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
+bool SpeculativeJIT::fillJSValue(Edge edge, GPRReg& tagGPR, GPRReg& payloadGPR, FPRReg& fpr)
{
// FIXME: For double we could fill with a FPR.
UNUSED_PARAM(fpr);
- VirtualRegister virtualRegister = node->virtualRegister();
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
case DataFormatNone: {
- if (node->hasConstant()) {
+ if (edge->hasConstant()) {
tagGPR = allocate();
payloadGPR = allocate();
- m_jit.move(Imm32(valueOfJSConstant(node).tag()), tagGPR);
- m_jit.move(Imm32(valueOfJSConstant(node).payload()), payloadGPR);
+ m_jit.move(Imm32(valueOfJSConstant(edge.node()).tag()), tagGPR);
+ m_jit.move(Imm32(valueOfJSConstant(edge.node()).payload()), payloadGPR);
m_gprs.retain(tagGPR, virtualRegister, SpillOrderConstant);
m_gprs.retain(payloadGPR, virtualRegister, SpillOrderConstant);
- info.fillJSValue(*m_stream, tagGPR, payloadGPR, isInt32Constant(node) ? DataFormatJSInteger : DataFormatJS);
+ info.fillJSValue(*m_stream, tagGPR, payloadGPR, isInt32Constant(edge.node()) ? DataFormatJSInteger : DataFormatJS);
} else {
DataFormat spillFormat = info.spillFormat();
ASSERT(spillFormat != DataFormatNone && spillFormat != DataFormatStorage);
@@ -844,27 +846,30 @@
}
template<bool strict>
-GPRReg SpeculativeJIT::fillSpeculateIntInternal(Node* node, DataFormat& returnFormat, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateIntInternal(Edge edge, DataFormat& returnFormat, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecInt@%d ", node->index());
+ dataLogF("SpecInt@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32));
+ value.filter(SpecInt32);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
case DataFormatNone: {
- if ((node->hasConstant() && !isInt32Constant(node)) || info.spillFormat() == DataFormatDouble) {
+ if ((edge->hasConstant() && !isInt32Constant(edge.node())) || info.spillFormat() == DataFormatDouble) {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0, direction);
returnFormat = DataFormatInteger;
return allocate();
}
- if (node->hasConstant()) {
- ASSERT(isInt32Constant(node));
+ if (edge->hasConstant()) {
+ ASSERT(isInt32Constant(edge.node()));
GPRReg gpr = allocate();
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(node)), gpr);
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
@@ -875,8 +880,8 @@
ASSERT_UNUSED(spillFormat, (spillFormat & DataFormatJS) || spillFormat == DataFormatInteger);
// If we know this was spilled as an integer we can fill without checking.
- if (!isInt32Speculation(type))
- speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)), direction);
+ if (type & ~SpecInt32)
+ speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)), direction);
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
@@ -893,8 +898,8 @@
GPRReg payloadGPR = info.payloadGPR();
m_gprs.lock(tagGPR);
m_gprs.lock(payloadGPR);
- if (!isInt32Speculation(type))
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)), direction);
+ if (type & ~SpecInt32)
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::Int32Tag)), direction);
m_gprs.unlock(tagGPR);
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
@@ -929,40 +934,43 @@
}
}
-GPRReg SpeculativeJIT::fillSpeculateInt(Node* node, DataFormat& returnFormat, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateInt(Edge edge, DataFormat& returnFormat, SpeculationDirection direction)
{
- return fillSpeculateIntInternal<false>(node, returnFormat, direction);
+ return fillSpeculateIntInternal<false>(edge, returnFormat, direction);
}
-GPRReg SpeculativeJIT::fillSpeculateIntStrict(Node* node)
+GPRReg SpeculativeJIT::fillSpeculateIntStrict(Edge edge)
{
DataFormat mustBeDataFormatInteger;
- GPRReg result = fillSpeculateIntInternal<true>(node, mustBeDataFormatInteger, BackwardSpeculation);
+ GPRReg result = fillSpeculateIntInternal<true>(edge, mustBeDataFormatInteger, BackwardSpeculation);
ASSERT(mustBeDataFormatInteger == DataFormatInteger);
return result;
}
-FPRReg SpeculativeJIT::fillSpeculateDouble(Node* node, SpeculationDirection direction)
+FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecDouble@%d ", node->index());
+ dataLogF("SpecDouble@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ ASSERT(edge.useKind() != KnownNumberUse || !(value.m_type & ~SpecNumber));
+ value.filter(SpecNumber);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (info.registerFormat() == DataFormatNone) {
- if (node->hasConstant()) {
- if (isInt32Constant(node)) {
+ if (edge->hasConstant()) {
+ if (isInt32Constant(edge.node())) {
GPRReg gpr = allocate();
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(node)), gpr);
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
info.fillInteger(*m_stream, gpr);
unlock(gpr);
- } else if (isNumberConstant(node)) {
+ } else if (isNumberConstant(edge.node())) {
FPRReg fpr = fprAllocate();
- m_jit.loadDouble(addressOfDoubleConstant(node), fpr);
+ m_jit.loadDouble(addressOfDoubleConstant(edge.node()), fpr);
m_fprs.retain(fpr, virtualRegister, SpillOrderConstant);
info.fillDouble(*m_stream, fpr);
return fpr;
@@ -986,8 +994,8 @@
if (spillFormat != DataFormatJSInteger && spillFormat != DataFormatInteger) {
JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag));
- if (!isNumberSpeculation(type))
- speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), node, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag)), direction);
+ if (type & ~SpecNumber)
+ speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::AboveOrEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::LowestTag)), direction);
m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
hasUnboxedDouble = m_jit.jump();
@@ -1021,8 +1029,8 @@
if (info.registerFormat() != DataFormatJSInteger) {
FPRTemporary scratch(this);
JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
- if (!isNumberSpeculation(type))
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)), direction);
+ if (type & ~SpecNumber)
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)), direction);
unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
hasUnboxedDouble = m_jit.jump();
isInteger.link(&m_jit);
@@ -1076,20 +1084,23 @@
}
}
-GPRReg SpeculativeJIT::fillSpeculateCell(Node* node, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecCell@%d ", node->index());
+ dataLogF("SpecCell@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ ASSERT(edge.useKind() != KnownCellUse || !(value.m_type & ~SpecCell));
+ value.filter(SpecCell);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
case DataFormatNone: {
- if (node->hasConstant()) {
- JSValue jsValue = valueOfJSConstant(node);
+ if (edge->hasConstant()) {
+ JSValue jsValue = valueOfJSConstant(edge.node());
GPRReg gpr = allocate();
if (jsValue.isCell()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
@@ -1102,8 +1113,8 @@
}
ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell);
- if (!isCellSpeculation(type))
- speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)), direction);
+ if (type & ~SpecCell)
+ speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)), direction);
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
@@ -1123,8 +1134,8 @@
GPRReg payloadGPR = info.payloadGPR();
m_gprs.lock(tagGPR);
m_gprs.lock(payloadGPR);
- if (!isCellSpeculation(type))
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)), direction);
+ if (type & ~SpecCell)
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)), direction);
m_gprs.unlock(tagGPR);
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
@@ -1151,13 +1162,15 @@
}
}
-GPRReg SpeculativeJIT::fillSpeculateBoolean(Node* node, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
dataLogF("SpecBool@%d ", node->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ value.filter(SpecBoolean);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
@@ -1167,8 +1180,8 @@
return allocate();
}
- if (node->hasConstant()) {
- JSValue jsValue = valueOfJSConstant(node);
+ if (edge->hasConstant()) {
+ JSValue jsValue = valueOfJSConstant(edge.node());
GPRReg gpr = allocate();
if (jsValue.isBoolean()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
@@ -1182,8 +1195,8 @@
ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatBoolean);
- if (!isBooleanSpeculation(type))
- speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), node, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)), direction);
+ if (type & ~SpecBoolean)
+ speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)), direction);
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
@@ -1204,8 +1217,8 @@
GPRReg payloadGPR = info.payloadGPR();
m_gprs.lock(tagGPR);
m_gprs.lock(payloadGPR);
- if (!isBooleanSpeculation(type))
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)), direction);
+ if (type & ~SpecBoolean)
+ speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::BooleanTag)), direction);
m_gprs.unlock(tagGPR);
m_gprs.release(tagGPR);
@@ -1259,36 +1272,27 @@
GPRReg op2GPR = op2.gpr();
if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
- m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
- if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1296,14 +1300,11 @@
MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1327,7 +1328,7 @@
void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
{
SpeculateCellOperand op1(this, leftChild);
- JSValueOperand op2(this, rightChild);
+ JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
GPRTemporary result(this);
GPRReg op1GPR = op1.gpr();
@@ -1337,27 +1338,21 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1374,27 +1369,23 @@
// We know that within this branch, rightChild must be a cell.
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()), structureGPR);
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1412,12 +1403,12 @@
// We know that within this branch, rightChild must not be a cell. Check if that is enough to
// prove that it is either null or undefined.
- if ((m_state.forNode(rightChild).m_type & ~SpecCell) & ~SpecOther) {
+ if (needsTypeCheck(rightChild, SpecCell | SpecOther)) {
m_jit.move(op2TagGPR, resultGPR);
m_jit.or32(TrustedImm32(1), resultGPR);
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
+ typeCheck(
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
m_jit.branch32(
MacroAssembler::NotEqual, resultGPR,
MacroAssembler::TrustedImm32(JSValue::NullTag)));
@@ -1439,7 +1430,7 @@
BlockIndex notTaken = branchNode->notTakenBlockIndex();
SpeculateCellOperand op1(this, leftChild);
- JSValueOperand op2(this, rightChild);
+ JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
GPRTemporary result(this);
GPRReg op1GPR = op1.gpr();
@@ -1449,27 +1440,21 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1485,27 +1470,23 @@
// We know that within this branch, rightChild must be a cell.
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op2PayloadGPR, JSCell::structureOffset()), structureGPR);
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1520,7 +1501,7 @@
// We know that within this branch, rightChild must not be a cell. Check if that is enough to
// prove that it is either null or undefined.
- if ((m_state.forNode(rightChild).m_type & ~SpecCell) & ~SpecOther)
+ if (!needsTypeCheck(rightChild, SpecCell | SpecOther))
rightNotCell.link(&m_jit);
else {
jump(notTaken, ForceJump);
@@ -1529,8 +1510,8 @@
m_jit.move(op2TagGPR, resultGPR);
m_jit.or32(TrustedImm32(1), resultGPR);
- speculationCheck(
- BadType, JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild,
+ typeCheck(
+ JSValueRegs(op2TagGPR, op2PayloadGPR), rightChild, SpecCell | SpecOther,
m_jit.branch32(
MacroAssembler::NotEqual, resultGPR,
MacroAssembler::TrustedImm32(JSValue::NullTag)));
@@ -1587,9 +1568,9 @@
jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
}
-void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, bool needSpeculationCheck)
+void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
{
- JSValueOperand value(this, nodeUse);
+ JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
GPRTemporary resultPayload(this);
GPRReg valueTagGPR = value.tagGPR();
GPRReg valuePayloadGPR = value.payloadGPR();
@@ -1599,26 +1580,24 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()), structureGPR);
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
MacroAssembler::Jump isNotMasqueradesAsUndefined =
m_jit.branchTest8(
@@ -1640,10 +1619,11 @@
notCell.link(&m_jit);
COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
- if (needSpeculationCheck) {
+ if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
m_jit.move(valueTagGPR, resultPayloadGPR);
m_jit.or32(TrustedImm32(1), resultPayloadGPR);
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
+ typeCheck(
+ JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
m_jit.branch32(
MacroAssembler::NotEqual,
resultPayloadGPR,
@@ -1658,26 +1638,29 @@
void SpeculativeJIT::compileLogicalNot(Node* node)
{
- if (node->child1()->shouldSpeculateBoolean()) {
+ switch (node->child1().useKind()) {
+ case BooleanUse: {
SpeculateBooleanOperand value(this, node->child1());
GPRTemporary result(this, value);
m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
booleanResult(result.gpr(), node);
return;
}
- if (node->child1()->shouldSpeculateObjectOrOther()) {
- compileObjectOrOtherLogicalNot(node->child1(),
- !isObjectOrOtherSpeculation(m_state.forNode(node->child1()).m_type));
+
+ case ObjectOrOtherUse: {
+ compileObjectOrOtherLogicalNot(node->child1());
return;
}
- if (node->child1()->shouldSpeculateInteger()) {
+
+ case Int32Use: {
SpeculateIntegerOperand value(this, node->child1());
GPRTemporary resultPayload(this, value);
m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
booleanResult(resultPayload.gpr(), node);
return;
}
- if (node->child1()->shouldSpeculateNumber()) {
+
+ case NumberUse: {
SpeculateDoubleOperand value(this, node->child1());
FPRTemporary scratch(this);
GPRTemporary resultPayload(this);
@@ -1689,30 +1672,38 @@
return;
}
- JSValueOperand arg1(this, node->child1());
- GPRTemporary resultPayload(this, arg1, false);
- GPRReg arg1TagGPR = arg1.tagGPR();
- GPRReg arg1PayloadGPR = arg1.payloadGPR();
- GPRReg resultPayloadGPR = resultPayload.gpr();
+ case UntypedUse: {
+ JSValueOperand arg1(this, node->child1());
+ GPRTemporary resultPayload(this, arg1, false);
+ GPRReg arg1TagGPR = arg1.tagGPR();
+ GPRReg arg1PayloadGPR = arg1.payloadGPR();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
- arg1.use();
+ arg1.use();
- JITCompiler::Jump slowCase = m_jit.branch32(JITCompiler::NotEqual, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
+ JITCompiler::Jump slowCase = m_jit.branch32(JITCompiler::NotEqual, arg1TagGPR, TrustedImm32(JSValue::BooleanTag));
- m_jit.move(arg1PayloadGPR, resultPayloadGPR);
+ m_jit.move(arg1PayloadGPR, resultPayloadGPR);
- addSlowPathGenerator(
- slowPathCall(
- slowCase, this, dfgConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR,
- arg1PayloadGPR));
+ addSlowPathGenerator(
+ slowPathCall(
+ slowCase, this, dfgConvertJSValueToBoolean, resultPayloadGPR, arg1TagGPR,
+ arg1PayloadGPR));
- m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
- booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
+ m_jit.xor32(TrustedImm32(1), resultPayloadGPR);
+ booleanResult(resultPayloadGPR, node, UseChildrenCalledExplicitly);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
-void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, bool needSpeculationCheck)
+void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken)
{
- JSValueOperand value(this, nodeUse);
+ JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
GPRTemporary scratch(this);
GPRReg valueTagGPR = value.tagGPR();
GPRReg valuePayloadGPR = value.payloadGPR();
@@ -1722,23 +1713,21 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
m_jit.loadPtr(MacroAssembler::Address(valuePayloadGPR, JSCell::structureOffset()), scratchGPR);
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- scratchGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
+ m_jit.branchPtr(
+ MacroAssembler::Equal,
+ scratchGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::Zero, MacroAssembler::Address(scratchGPR, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
@@ -1755,10 +1744,12 @@
notCell.link(&m_jit);
COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
- if (needSpeculationCheck) {
+ if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
m_jit.move(valueTagGPR, scratchGPR);
m_jit.or32(TrustedImm32(1), scratchGPR);
- speculationCheck(BadType, JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
+ typeCheck(
+ JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, SpecCell | SpecOther,
+ m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
}
jump(notTaken);
@@ -1771,7 +1762,8 @@
BlockIndex taken = node->takenBlockIndex();
BlockIndex notTaken = node->notTakenBlockIndex();
- if (node->shouldSpeculateBoolean()) {
+ switch (node->child1().useKind()) {
+ case BooleanUse: {
SpeculateBooleanOperand value(this, node->child1());
MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
@@ -1789,14 +1781,14 @@
return;
}
- if (node->child1()->shouldSpeculateObjectOrOther()) {
- emitObjectOrOtherBranch(node->child1(), taken, notTaken,
- !isObjectOrOtherSpeculation(m_state.forNode(node->child1()).m_type));
+ case ObjectOrOtherUse: {
+ emitObjectOrOtherBranch(node->child1(), taken, notTaken);
return;
}
- if (node->child1()->shouldSpeculateNumber()) {
- if (node->child1()->shouldSpeculateInteger()) {
+ case NumberUse:
+ case Int32Use: {
+ if (node->child1().useKind() == Int32Use) {
bool invert = false;
if (taken == nextBlock()) {
@@ -1820,32 +1812,40 @@
return;
}
- JSValueOperand value(this, node->child1());
- value.fill();
- GPRReg valueTagGPR = value.tagGPR();
- GPRReg valuePayloadGPR = value.payloadGPR();
+ case UntypedUse: {
+ JSValueOperand value(this, node->child1());
+ value.fill();
+ GPRReg valueTagGPR = value.tagGPR();
+ GPRReg valuePayloadGPR = value.payloadGPR();
- GPRTemporary result(this);
- GPRReg resultGPR = result.gpr();
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
- use(node->child1());
+ use(node->child1());
- JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
- JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
+ JITCompiler::Jump fastPath = m_jit.branch32(JITCompiler::Equal, valueTagGPR, JITCompiler::TrustedImm32(JSValue::Int32Tag));
+ JITCompiler::Jump slowPath = m_jit.branch32(JITCompiler::NotEqual, valueTagGPR, JITCompiler::TrustedImm32(JSValue::BooleanTag));
- fastPath.link(&m_jit);
- branchTest32(JITCompiler::Zero, valuePayloadGPR, notTaken);
- jump(taken, ForceJump);
+ fastPath.link(&m_jit);
+ branchTest32(JITCompiler::Zero, valuePayloadGPR, notTaken);
+ jump(taken, ForceJump);
- slowPath.link(&m_jit);
- silentSpillAllRegisters(resultGPR);
- callOperation(dfgConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
- silentFillAllRegisters(resultGPR);
+ slowPath.link(&m_jit);
+ silentSpillAllRegisters(resultGPR);
+ callOperation(dfgConvertJSValueToBoolean, resultGPR, valueTagGPR, valuePayloadGPR);
+ silentFillAllRegisters(resultGPR);
- branchTest32(JITCompiler::NonZero, resultGPR, taken);
- jump(notTaken);
+ branchTest32(JITCompiler::NonZero, resultGPR, taken);
+ jump(notTaken);
- noResult(node, UseChildrenCalledExplicitly);
+ noResult(node, UseChildrenCalledExplicitly);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
@@ -1930,14 +1930,7 @@
break;
case Identity: {
- // This could be done a lot better. We take the cheap way out because Identity
- // is only going to stick around after CSE if we had prediction weirdness.
- JSValueOperand operand(this, node->child1());
- GPRTemporary resultTag(this);
- GPRTemporary resultPayload(this);
- m_jit.move(operand.tagGPR(), resultTag.gpr());
- m_jit.move(operand.payloadGPR(), resultPayload.gpr());
- jsValueResult(resultTag.gpr(), resultPayload.gpr(), node);
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
@@ -1955,6 +1948,8 @@
// If the CFA is tracking this variable and it found that the variable
// cannot have been assigned, then don't attempt to proceed.
if (value.isClear()) {
+ // FIXME: We should trap instead.
+ // https://bugs.webkit.org/show_bug.cgi?id=110383
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
break;
}
@@ -2055,7 +2050,7 @@
}
SpeculatedType predictedType = node->variableAccessData()->argumentAwarePrediction();
if (m_generationInfo[node->child1()->virtualRegister()].registerFormat() == DataFormatDouble) {
- SpeculateDoubleOperand value(this, Edge(node->child1().node(), DoubleUse));
+ SpeculateDoubleOperand value(this, node->child1(), BackwardSpeculation, ManualOperandSpeculation);
m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node->local()));
noResult(node);
recordSetLocal(node->local(), ValueSource(DoubleInJSStack));
@@ -2183,19 +2178,6 @@
break;
}
- case CheckNumber: {
- if (!isNumberSpeculation(m_state.forNode(node->child1()).m_type)) {
- JSValueOperand op1(this, node->child1());
- JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, op1.tagGPR(), TrustedImm32(JSValue::Int32Tag));
- speculationCheck(
- BadType, JSValueRegs(op1.tagGPR(), op1.payloadGPR()), node->child1(),
- m_jit.branch32(MacroAssembler::AboveOrEqual, op1.tagGPR(), TrustedImm32(JSValue::LowestTag)));
- isInteger.link(&m_jit);
- }
- noResult(node);
- break;
- }
-
case ValueAdd:
case ArithAdd:
compileAdd(node);
@@ -2214,8 +2196,8 @@
break;
case ArithDiv: {
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
#if CPU(X86)
compileIntegerArithDivForX86(node);
#elif CPU(APPLE_ARMV7S)
@@ -2225,16 +2207,24 @@
#endif
break;
}
-
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
- FPRTemporary result(this, op1);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.divDouble(reg1, reg2, result.fpr());
-
- doubleResult(result.fpr(), node);
+
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
+ FPRTemporary result(this, op1);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.divDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -2244,8 +2234,8 @@
}
case ArithAbs: {
- if (node->child1()->shouldSpeculateIntegerForArithmetic()
- && node->canSpeculateInteger()) {
+ switch (node->child1().useKind()) {
+ case Int32Use: {
SpeculateIntegerOperand op1(this, node->child1());
GPRTemporary result(this, op1);
GPRTemporary scratch(this);
@@ -2259,18 +2249,27 @@
break;
}
- SpeculateDoubleOperand op1(this, node->child1());
- FPRTemporary result(this);
-
- m_jit.absDouble(op1.fpr(), result.fpr());
- doubleResult(result.fpr(), node);
+
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ FPRTemporary result(this);
+
+ m_jit.absDouble(op1.fpr(), result.fpr());
+ doubleResult(result.fpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
case ArithMin:
case ArithMax: {
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
SpeculateStrictInt32Operand op1(this, node->child1());
SpeculateStrictInt32Operand op2(this, node->child2());
GPRTemporary result(this, op1);
@@ -2289,36 +2288,44 @@
break;
}
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
- FPRTemporary result(this, op1);
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
+ FPRTemporary result(this, op1);
- MacroAssembler::JumpList done;
+ MacroAssembler::JumpList done;
- MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());
+ MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());
- // op2 is eather the lesser one or one of then is NaN
- MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1.fpr(), op2.fpr());
+ // op2 is eather the lesser one or one of then is NaN
+ MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1.fpr(), op2.fpr());
- // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
- // op1 + op2 and putting it into result.
- m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());
- done.append(m_jit.jump());
-
- op2Less.link(&m_jit);
- m_jit.moveDouble(op2.fpr(), result.fpr());
-
- if (op1.fpr() != result.fpr()) {
+ // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
+ // op1 + op2 and putting it into result.
+ m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());
done.append(m_jit.jump());
+
+ op2Less.link(&m_jit);
+ m_jit.moveDouble(op2.fpr(), result.fpr());
+
+ if (op1.fpr() != result.fpr()) {
+ done.append(m_jit.jump());
- op1Less.link(&m_jit);
- m_jit.moveDouble(op1.fpr(), result.fpr());
- } else
- op1Less.link(&m_jit);
+ op1Less.link(&m_jit);
+ m_jit.moveDouble(op1.fpr(), result.fpr());
+ } else
+ op1Less.link(&m_jit);
- done.link(&m_jit);
+ done.link(&m_jit);
- doubleResult(result.fpr(), node);
+ doubleResult(result.fpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -2981,13 +2988,9 @@
SpeculateDoubleOperand value(this, node->child2());
FPRReg valueFPR = value.fpr();
- if (!isRealNumberSpeculation(m_state.forNode(node->child2()).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(), node->child2(), SpecRealNumber,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
@@ -3235,7 +3238,8 @@
}
case ToPrimitive: {
- if (node->child1()->shouldSpeculateInteger()) {
+ switch (node->child1().useKind()) {
+ case Int32Use: {
// It's really profitable to speculate integer, since it's really cheap,
// it means we don't have to do any real work, and we emit a lot less code.
@@ -3248,38 +3252,44 @@
integerResult(result.gpr(), node);
break;
}
+
+ case UntypedUse: {
+ JSValueOperand op1(this, node->child1());
+ GPRTemporary resultTag(this, op1);
+ GPRTemporary resultPayload(this, op1, false);
- // FIXME: Add string speculation here.
+ GPRReg op1TagGPR = op1.tagGPR();
+ GPRReg op1PayloadGPR = op1.payloadGPR();
+ GPRReg resultTagGPR = resultTag.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
- JSValueOperand op1(this, node->child1());
- GPRTemporary resultTag(this, op1);
- GPRTemporary resultPayload(this, op1, false);
+ op1.use();
- GPRReg op1TagGPR = op1.tagGPR();
- GPRReg op1PayloadGPR = op1.payloadGPR();
- GPRReg resultTagGPR = resultTag.gpr();
- GPRReg resultPayloadGPR = resultPayload.gpr();
-
- op1.use();
-
- if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
- m_jit.move(op1TagGPR, resultTagGPR);
- m_jit.move(op1PayloadGPR, resultPayloadGPR);
- } else {
- MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
- MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+ if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
+ m_jit.move(op1TagGPR, resultTagGPR);
+ m_jit.move(op1PayloadGPR, resultPayloadGPR);
+ } else {
+ MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
- alreadyPrimitive.link(&m_jit);
- m_jit.move(op1TagGPR, resultTagGPR);
- m_jit.move(op1PayloadGPR, resultPayloadGPR);
+ alreadyPrimitive.link(&m_jit);
+ m_jit.move(op1TagGPR, resultTagGPR);
+ m_jit.move(op1PayloadGPR, resultPayloadGPR);
- addSlowPathGenerator(
- slowPathCall(
- notPrimitive, this, operationToPrimitive,
- JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
+ addSlowPathGenerator(
+ slowPathCall(
+ notPrimitive, this, operationToPrimitive,
+ JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
+ }
+
+ jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
+ break;
}
-
- jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3363,13 +3373,9 @@
case ALL_DOUBLE_INDEXING_TYPES: {
SpeculateDoubleOperand operand(this, use);
FPRReg opFPR = operand.fpr();
- if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(), use, SpecRealNumber,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
break;
@@ -3432,13 +3438,9 @@
case ALL_DOUBLE_INDEXING_TYPES: {
SpeculateDoubleOperand operand(this, use);
FPRReg opFPR = operand.fpr();
- if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(), use, SpecRealNumber,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
m_jit.storeDouble(opFPR, reinterpret_cast<char*>(buffer + operandIdx));
break;
@@ -3639,39 +3641,41 @@
}
case ConvertThis: {
- if (isObjectSpeculation(m_state.forNode(node->child1()).m_type)) {
- SpeculateCellOperand thisValue(this, node->child1());
- GPRTemporary result(this, thisValue);
- m_jit.move(thisValue.gpr(), result.gpr());
- cellResult(result.gpr(), node);
- break;
- }
-
- if (isOtherSpeculation(node->child1()->prediction())) {
- JSValueOperand thisValue(this, node->child1());
+ switch (node->child1().useKind()) {
+ case OtherUse: {
+ JSValueOperand thisValue(this, node->child1(), ManualOperandSpeculation);
GPRTemporary scratch(this);
GPRReg thisValueTagGPR = thisValue.tagGPR();
GPRReg scratchGPR = scratch.gpr();
COMPILE_ASSERT((JSValue::UndefinedTag | 1) == JSValue::NullTag, UndefinedTag_OR_1_EQUALS_NullTag);
- m_jit.move(thisValueTagGPR, scratchGPR);
- m_jit.or32(TrustedImm32(1), scratchGPR);
- // This is hard. It would be better to save the value, but we can't quite do it,
- // since this operation does not otherwise get the payload.
- speculationCheck(BadType, JSValueRegs(), 0, m_jit.branch32(MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
+ if (needsTypeCheck(node->child1(), SpecOther)) {
+ m_jit.move(thisValueTagGPR, scratchGPR);
+ m_jit.or32(TrustedImm32(1), scratchGPR);
+ // This is hard. It would be better to save the value, but we can't quite do it,
+ // since this operation does not otherwise get the payload.
+ typeCheck(
+ JSValueRegs(), node->child1(), SpecOther,
+ m_jit.branch32(
+ MacroAssembler::NotEqual, scratchGPR, TrustedImm32(JSValue::NullTag)));
+ }
m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalThisObjectFor(node->codeOrigin)), scratchGPR);
cellResult(scratchGPR, node);
break;
}
- if (isObjectSpeculation(node->child1()->prediction())) {
+ case ObjectUse: {
SpeculateCellOperand thisValue(this, node->child1());
GPRReg thisValueGPR = thisValue.gpr();
- if (!isObjectSpeculation(m_state.forNode(node->child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(thisValueGPR), node->child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(thisValueGPR), node->child1(), SpecObject,
+ m_jit.branchPtr(
+ JITCompiler::Equal,
+ JITCompiler::Address(thisValueGPR, JSCell::structureOffset()),
+ JITCompiler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
GPRTemporary result(this, thisValue);
GPRReg resultGPR = result.gpr();
@@ -3680,17 +3684,25 @@
break;
}
- JSValueOperand thisValue(this, node->child1());
- GPRReg thisValueTagGPR = thisValue.tagGPR();
- GPRReg thisValuePayloadGPR = thisValue.payloadGPR();
-
- flushRegisters();
-
- GPRResult2 resultTag(this);
- GPRResult resultPayload(this);
- callOperation(operationConvertThis, resultTag.gpr(), resultPayload.gpr(), thisValueTagGPR, thisValuePayloadGPR);
-
- cellResult(resultPayload.gpr(), node);
+ case UntypedUse: {
+ JSValueOperand thisValue(this, node->child1());
+ GPRReg thisValueTagGPR = thisValue.tagGPR();
+ GPRReg thisValuePayloadGPR = thisValue.payloadGPR();
+
+ flushRegisters();
+
+ GPRResult2 resultTag(this);
+ GPRResult resultPayload(this);
+ callOperation(operationConvertThis, resultTag.gpr(), resultPayload.gpr(), thisValueTagGPR, thisValuePayloadGPR);
+
+ cellResult(resultPayload.gpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3906,7 +3918,8 @@
break;
}
- if (isCellSpeculation(node->child1()->prediction())) {
+ switch (node->child1().useKind()) {
+ case CellUse: {
SpeculateCellOperand base(this, node->child1());
GPRReg baseGPR = base.gpr();
@@ -3926,24 +3939,32 @@
break;
}
- JSValueOperand base(this, node->child1());
- GPRReg baseTagGPR = base.tagGPR();
- GPRReg basePayloadGPR = base.payloadGPR();
+ case UntypedUse: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseTagGPR = base.tagGPR();
+ GPRReg basePayloadGPR = base.payloadGPR();
- GPRResult resultTag(this);
- GPRResult2 resultPayload(this);
- GPRReg resultTagGPR = resultTag.gpr();
- GPRReg resultPayloadGPR = resultPayload.gpr();
+ GPRResult resultTag(this);
+ GPRResult2 resultPayload(this);
+ GPRReg resultTagGPR = resultTag.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
- base.use();
+ base.use();
- flushRegisters();
+ flushRegisters();
- JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
- cachedGetById(node->codeOrigin, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell, DontSpill);
+ cachedGetById(node->codeOrigin, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell, DontSpill);
- jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
+ jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3967,13 +3988,6 @@
case CheckStructure:
case ForwardCheckStructure: {
- AbstractValue& value = m_state.forNode(node->child1());
- if (value.m_currentKnownStructure.isSubsetOf(node->structureSet())
- && isCellSpeculation(value.m_type)) {
- noResult(node);
- break;
- }
-
SpeculationDirection direction = node->op() == ForwardCheckStructure ? ForwardSpeculation : BackwardSpeculation;
SpeculateCellOperand base(this, node->child1(), direction);
@@ -4032,6 +4046,8 @@
JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node->structure()));
m_jit.breakpoint();
isOK.link(&m_jit);
+#else
+ speculaceCell(node->child1());
#endif
noResult(node);
@@ -4039,6 +4055,7 @@
}
case PhantomPutStructure: {
+ ASSERT(isKnownCell(node->child1().node()));
ASSERT(node->structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated());
m_jit.addWeakReferenceTransition(
node->codeOrigin.codeOriginOwner(),
@@ -4390,18 +4407,20 @@
flushRegisters();
+ ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
+
JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, tagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
- if (node->child1()->shouldSpeculateCell())
+ if (node->child1().useKind() != UntypedUse)
speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node->child1(), isNotCell);
- if (!node->child1()->shouldSpeculateObject()) {
+ if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
m_jit.loadPtr(JITCompiler::Address(payloadGPR, JSCell::structureOffset()), tempGPR);
JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
- if (node->child1()->shouldSpeculateString())
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node->child1(), notString);
+ if (node->child1().useKind() == StringUse)
+ DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecString, notString);
m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString()), resultGPR);
doneJumps.append(m_jit.jump());
- if (!node->child1()->shouldSpeculateString()) {
+ if (node->child1().useKind() != StringUse) {
notString.link(&m_jit);
callOperation(operationTypeOf, resultGPR, payloadGPR);
doneJumps.append(m_jit.jump());
@@ -4411,7 +4430,7 @@
doneJumps.append(m_jit.jump());
}
- if (!node->child1()->shouldSpeculateCell()) {
+ if (node->child1().useKind() == UntypedUse) {
isNotCell.link(&m_jit);
m_jit.add32(TrustedImm32(1), tagGPR, tempGPR);
@@ -4928,6 +4947,10 @@
break;
case Phantom:
+ DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
+ noResult(node);
+ break;
+
case PhantomLocal:
// This is a no-op.
noResult(node);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index f8d3397..eae12cc 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -39,28 +39,30 @@
#if USE(JSVALUE64)
-GPRReg SpeculativeJIT::fillInteger(Node* node, DataFormat& returnFormat)
+GPRReg SpeculativeJIT::fillInteger(Edge edge, DataFormat& returnFormat)
{
- VirtualRegister virtualRegister = node->virtualRegister();
+ ASSERT(!needsTypeCheck(edge, SpecInt32));
+
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (info.registerFormat() == DataFormatNone) {
GPRReg gpr = allocate();
- if (node->hasConstant()) {
+ if (edge->hasConstant()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- if (isInt32Constant(node)) {
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(node)), gpr);
+ if (isInt32Constant(edge.node())) {
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
}
- if (isNumberConstant(node)) {
- JSValue jsValue = jsNumber(valueOfNumberConstant(node));
+ if (isNumberConstant(edge.node())) {
+ JSValue jsValue = jsNumber(valueOfNumberConstant(edge.node()));
m_jit.move(MacroAssembler::Imm64(JSValue::encode(jsValue)), gpr);
} else {
- ASSERT(isJSConstant(node));
- JSValue jsValue = valueOfJSConstant(node);
+ ASSERT(isJSConstant(edge.node()));
+ JSValue jsValue = valueOfJSConstant(edge.node());
m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
}
} else if (info.spillFormat() == DataFormatInteger) {
@@ -117,27 +119,27 @@
}
}
-GPRReg SpeculativeJIT::fillJSValue(Node* node)
+GPRReg SpeculativeJIT::fillJSValue(Edge edge)
{
- VirtualRegister virtualRegister = node->virtualRegister();
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
case DataFormatNone: {
GPRReg gpr = allocate();
- if (node->hasConstant()) {
- if (isInt32Constant(node)) {
+ if (edge->hasConstant()) {
+ if (isInt32Constant(edge.node())) {
info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
- JSValue jsValue = jsNumber(valueOfInt32Constant(node));
+ JSValue jsValue = jsNumber(valueOfInt32Constant(edge.node()));
m_jit.move(MacroAssembler::Imm64(JSValue::encode(jsValue)), gpr);
- } else if (isNumberConstant(node)) {
+ } else if (isNumberConstant(edge.node())) {
info.fillJSValue(*m_stream, gpr, DataFormatJSDouble);
- JSValue jsValue(JSValue::EncodeAsDouble, valueOfNumberConstant(node));
+ JSValue jsValue(JSValue::EncodeAsDouble, valueOfNumberConstant(edge.node()));
m_jit.move(MacroAssembler::Imm64(JSValue::encode(jsValue)), gpr);
} else {
- ASSERT(isJSConstant(node));
- JSValue jsValue = valueOfJSConstant(node);
+ ASSERT(isJSConstant(edge.node()));
+ JSValue jsValue = valueOfJSConstant(edge.node());
m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
info.fillJSValue(*m_stream, gpr, DataFormatJS);
}
@@ -802,18 +804,21 @@
}
template<bool strict>
-GPRReg SpeculativeJIT::fillSpeculateIntInternal(Node* node, DataFormat& returnFormat, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateIntInternal(Edge edge, DataFormat& returnFormat, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecInt@%d ", node->index());
+ dataLogF("SpecInt@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ ASSERT(edge.useKind() != KnownInt32Use || !(value.m_type & ~SpecInt32));
+ value.filter(SpecInt32);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
case DataFormatNone: {
- if ((node->hasConstant() && !isInt32Constant(node)) || info.spillFormat() == DataFormatDouble) {
+ if ((edge->hasConstant() && !isInt32Constant(edge.node())) || info.spillFormat() == DataFormatDouble) {
terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0, direction);
returnFormat = DataFormatInteger;
return allocate();
@@ -821,10 +826,10 @@
GPRReg gpr = allocate();
- if (node->hasConstant()) {
+ if (edge->hasConstant()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- ASSERT(isInt32Constant(node));
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(node)), gpr);
+ ASSERT(isInt32Constant(edge.node()));
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
info.fillInteger(*m_stream, gpr);
returnFormat = DataFormatInteger;
return gpr;
@@ -864,8 +869,8 @@
// Check the value is an integer.
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
- if (!isInt32Speculation(type))
- speculationCheck(BadType, JSValueRegs(gpr), node, m_jit.branch64(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister), direction);
+ if (type & ~SpecInt32)
+ speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branch64(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister), direction);
info.fillJSValue(*m_stream, gpr, DataFormatJSInteger);
// If !strict we're done, return.
if (!strict) {
@@ -910,10 +915,10 @@
case DataFormatDouble:
case DataFormatJSDouble: {
- if (node->hasConstant() && isInt32Constant(node)) {
+ if (edge->hasConstant() && isInt32Constant(edge.node())) {
GPRReg gpr = allocate();
- ASSERT(isInt32Constant(node));
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(node)), gpr);
+ ASSERT(isInt32Constant(edge.node()));
+ m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(edge.node())), gpr);
returnFormat = DataFormatInteger;
return gpr;
}
@@ -936,35 +941,38 @@
}
}
-GPRReg SpeculativeJIT::fillSpeculateInt(Node* node, DataFormat& returnFormat, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateInt(Edge edge, DataFormat& returnFormat, SpeculationDirection direction)
{
- return fillSpeculateIntInternal<false>(node, returnFormat, direction);
+ return fillSpeculateIntInternal<false>(edge, returnFormat, direction);
}
-GPRReg SpeculativeJIT::fillSpeculateIntStrict(Node* node)
+GPRReg SpeculativeJIT::fillSpeculateIntStrict(Edge edge)
{
DataFormat mustBeDataFormatInteger;
- GPRReg result = fillSpeculateIntInternal<true>(node, mustBeDataFormatInteger, BackwardSpeculation);
+ GPRReg result = fillSpeculateIntInternal<true>(edge, mustBeDataFormatInteger, BackwardSpeculation);
RELEASE_ASSERT(mustBeDataFormatInteger == DataFormatInteger);
return result;
}
-FPRReg SpeculativeJIT::fillSpeculateDouble(Node* node, SpeculationDirection direction)
+FPRReg SpeculativeJIT::fillSpeculateDouble(Edge edge, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecDouble@%d ", node->index());
+ dataLogF("SpecDouble@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ ASSERT(edge.useKind() != KnownNumberUse || !(value.m_type & ~SpecNumber));
+ value.filter(SpecNumber);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (info.registerFormat() == DataFormatNone) {
- if (node->hasConstant()) {
+ if (edge->hasConstant()) {
GPRReg gpr = allocate();
- if (isInt32Constant(node)) {
+ if (isInt32Constant(edge.node())) {
FPRReg fpr = fprAllocate();
- m_jit.move(MacroAssembler::Imm64(reinterpretDoubleToInt64(static_cast<double>(valueOfInt32Constant(node)))), gpr);
+ m_jit.move(MacroAssembler::Imm64(reinterpretDoubleToInt64(static_cast<double>(valueOfInt32Constant(edge.node())))), gpr);
m_jit.move64ToDouble(gpr, fpr);
unlock(gpr);
@@ -972,9 +980,9 @@
info.fillDouble(*m_stream, fpr);
return fpr;
}
- if (isNumberConstant(node)) {
+ if (isNumberConstant(edge.node())) {
FPRReg fpr = fprAllocate();
- m_jit.move(MacroAssembler::Imm64(reinterpretDoubleToInt64(valueOfNumberConstant(node))), gpr);
+ m_jit.move(MacroAssembler::Imm64(reinterpretDoubleToInt64(valueOfNumberConstant(edge.node()))), gpr);
m_jit.move64ToDouble(gpr, fpr);
unlock(gpr);
@@ -1038,8 +1046,8 @@
JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
- if (!isNumberSpeculation(type))
- speculationCheck(BadType, JSValueRegs(jsValueGpr), node, m_jit.branchTest64(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister), direction);
+ if (type & ~SpecNumber)
+ speculationCheck(BadType, JSValueRegs(jsValueGpr), edge, m_jit.branchTest64(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister), direction);
// First, if we get here we have a double encoded as a JSValue
m_jit.move(jsValueGpr, tempGpr);
@@ -1102,13 +1110,16 @@
}
}
-GPRReg SpeculativeJIT::fillSpeculateCell(Node* node, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecCell@%d ", node->index());
+ dataLogF("SpecCell@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ ASSERT(edge.useKind() != KnownCellUse || !(value.m_type & ~SpecCell));
+ value.filter(SpecCell);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
@@ -1120,8 +1131,8 @@
GPRReg gpr = allocate();
- if (node->hasConstant()) {
- JSValue jsValue = valueOfJSConstant(node);
+ if (edge->hasConstant()) {
+ JSValue jsValue = valueOfJSConstant(edge.node());
if (jsValue.isCell()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
@@ -1136,8 +1147,8 @@
m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
info.fillJSValue(*m_stream, gpr, DataFormatJS);
- if (!isCellSpeculation(type))
- speculationCheck(BadType, JSValueRegs(gpr), node, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), direction);
+ if (type & ~SpecCell)
+ speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), direction);
info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
@@ -1152,8 +1163,8 @@
case DataFormatJS: {
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
- if (!isCellSpeculation(type))
- speculationCheck(BadType, JSValueRegs(gpr), node, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), direction);
+ if (type & ~SpecCell)
+ speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister), direction);
info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
@@ -1177,13 +1188,15 @@
}
}
-GPRReg SpeculativeJIT::fillSpeculateBoolean(Node* node, SpeculationDirection direction)
+GPRReg SpeculativeJIT::fillSpeculateBoolean(Edge edge, SpeculationDirection direction)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
- dataLogF("SpecBool@%d ", node->index());
+ dataLogF("SpecBool@%d ", edge->index());
#endif
- SpeculatedType type = m_state.forNode(node).m_type;
- VirtualRegister virtualRegister = node->virtualRegister();
+ AbstractValue& value = m_state.forNode(edge);
+ SpeculatedType type = value.m_type;
+ value.filter(SpecBoolean);
+ VirtualRegister virtualRegister = edge->virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
switch (info.registerFormat()) {
@@ -1195,8 +1208,8 @@
GPRReg gpr = allocate();
- if (node->hasConstant()) {
- JSValue jsValue = valueOfJSConstant(node);
+ if (edge->hasConstant()) {
+ JSValue jsValue = valueOfJSConstant(edge.node());
if (jsValue.isBoolean()) {
m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
@@ -1211,9 +1224,9 @@
m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
info.fillJSValue(*m_stream, gpr, DataFormatJS);
- if (!isBooleanSpeculation(type)) {
+ if (type & ~SpecBoolean) {
m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
- speculationCheck(BadType, JSValueRegs(gpr), node, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg), direction);
+ speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg), direction);
m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
}
info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
@@ -1230,9 +1243,9 @@
case DataFormatJS: {
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
- if (!isBooleanSpeculation(type)) {
+ if (type & ~SpecBoolean) {
m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
- speculationCheck(BadType, JSValueRegs(gpr), node, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg), direction);
+ speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg), direction);
m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
}
info.fillJSValue(*m_stream, gpr, DataFormatJSBoolean);
@@ -1290,35 +1303,26 @@
if (m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(node->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
- if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(node->child1()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), node->child1(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node->child1(),
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1326,14 +1330,11 @@
MacroAssembler::TrustedImm32(MasqueradesAsUndefined)));
m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(node->child2()).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op2GPR), node->child2(), SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node->child2(),
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1354,7 +1355,7 @@
void SpeculativeJIT::compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild)
{
SpeculateCellOperand op1(this, leftChild);
- JSValueOperand op2(this, rightChild);
+ JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
GPRTemporary result(this);
GPRReg op1GPR = op1.gpr();
@@ -1363,27 +1364,21 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1399,27 +1394,21 @@
// We know that within this branch, rightChild must be a cell.
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueRegs(op2GPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1437,12 +1426,12 @@
// We know that within this branch, rightChild must not be a cell. Check if that is enough to
// prove that it is either null or undefined.
- if ((m_state.forNode(rightChild).m_type & ~SpecCell) & ~SpecOther) {
+ if (needsTypeCheck(rightChild, SpecCell | SpecOther)) {
m_jit.move(op2GPR, resultGPR);
m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild.node(),
+ typeCheck(
+ JSValueRegs(op2GPR), rightChild, SpecCell | SpecOther,
m_jit.branch64(
MacroAssembler::NotEqual, resultGPR,
MacroAssembler::TrustedImm64(ValueNull)));
@@ -1464,7 +1453,7 @@
BlockIndex notTaken = branchNode->notTakenBlockIndex();
SpeculateCellOperand op1(this, leftChild);
- JSValueOperand op2(this, rightChild);
+ JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
GPRTemporary result(this);
GPRReg op1GPR = op1.gpr();
@@ -1473,27 +1462,21 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op1GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op1GPR, JSCell::structureOffset()), structureGPR);
- if (m_state.forNode(leftChild).m_type & ~SpecObject) {
- speculationCheck(
- BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(op1GPR), leftChild, SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), leftChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1509,27 +1492,21 @@
// We know that within this branch, rightChild must be a cell.
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(op2GPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(op2GPR, JSCell::structureOffset()), structureGPR);
- if ((m_state.forNode(rightChild).m_type & SpecCell) & ~SpecObject) {
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(op2GPR), rightChild, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
speculationCheck(BadType, JSValueRegs(op2GPR), rightChild,
m_jit.branchTest8(
MacroAssembler::NonZero,
@@ -1544,7 +1521,7 @@
// We know that within this branch, rightChild must not be a cell. Check if that is enough to
// prove that it is either null or undefined.
- if ((m_state.forNode(rightChild).m_type & ~SpecCell) & ~SpecOther)
+ if (!needsTypeCheck(rightChild, SpecCell | SpecOther))
rightNotCell.link(&m_jit);
else {
jump(notTaken, ForceJump);
@@ -1553,9 +1530,8 @@
m_jit.move(op2GPR, resultGPR);
m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
- speculationCheck(
- BadType, JSValueRegs(op2GPR), rightChild,
- m_jit.branch64(
+ typeCheck(
+ JSValueRegs(op2GPR), rightChild, SpecCell | SpecOther, m_jit.branch64(
MacroAssembler::NotEqual, resultGPR,
MacroAssembler::TrustedImm64(ValueNull)));
}
@@ -1609,9 +1585,9 @@
jsValueResult(result.gpr(), node);
}
-void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse, bool needSpeculationCheck)
+void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
{
- JSValueOperand value(this, nodeUse);
+ JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
GPRTemporary result(this);
GPRReg valueGPR = value.gpr();
GPRReg resultGPR = result.gpr();
@@ -1619,27 +1595,22 @@
MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
-
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valueGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valueGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
GPRTemporary structure(this);
GPRReg structureGPR = structure.gpr();
m_jit.loadPtr(MacroAssembler::Address(valueGPR, JSCell::structureOffset()), structureGPR);
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- structureGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ structureGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
MacroAssembler::Jump isNotMasqueradesAsUndefined =
m_jit.branchTest8(
@@ -1660,11 +1631,11 @@
notCell.link(&m_jit);
- if (needSpeculationCheck) {
+ if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
m_jit.move(valueGPR, resultGPR);
m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), resultGPR);
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
- m_jit.branch64(
+ typeCheck(
+ JSValueRegs(valueGPR), nodeUse, SpecCell | SpecOther, m_jit.branch64(
MacroAssembler::NotEqual,
resultGPR,
MacroAssembler::TrustedImm64(ValueNull)));
@@ -1678,12 +1649,13 @@
void SpeculativeJIT::compileLogicalNot(Node* node)
{
- if (node->child1()->shouldSpeculateObjectOrOther()) {
- compileObjectOrOtherLogicalNot(node->child1(),
- !isObjectOrOtherSpeculation(m_state.forNode(node->child1()).m_type));
+ switch (node->child1().useKind()) {
+ case ObjectOrOtherUse: {
+ compileObjectOrOtherLogicalNot(node->child1());
return;
}
- if (node->child1()->shouldSpeculateInteger()) {
+
+ case Int32Use: {
SpeculateIntegerOperand value(this, node->child1());
GPRTemporary result(this, value);
m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), result.gpr());
@@ -1691,7 +1663,8 @@
jsValueResult(result.gpr(), node, DataFormatJSBoolean);
return;
}
- if (node->child1()->shouldSpeculateNumber()) {
+
+ case NumberUse: {
SpeculateDoubleOperand value(this, node->child1());
FPRTemporary scratch(this);
GPRTemporary result(this);
@@ -1703,9 +1676,8 @@
return;
}
- SpeculatedType prediction = node->child1()->prediction();
- if (isBooleanSpeculation(prediction)) {
- if (isBooleanSpeculation(m_state.forNode(node->child1()).m_type)) {
+ case BooleanUse: {
+ if (!needsTypeCheck(node->child1(), SpecBoolean)) {
SpeculateBooleanOperand value(this, node->child1());
GPRTemporary result(this, value);
@@ -1716,41 +1688,51 @@
return;
}
- JSValueOperand value(this, node->child1());
+ JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
m_jit.move(value.gpr(), result.gpr());
m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr());
- speculationCheck(BadType, JSValueRegs(value.gpr()), node->child1(), m_jit.branchTest64(JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
+ typeCheck(
+ JSValueRegs(value.gpr()), node->child1(), SpecBoolean, m_jit.branchTest64(
+ JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.gpr());
// If we add a DataFormatBool, we should use it here.
jsValueResult(result.gpr(), node, DataFormatJSBoolean);
return;
}
+
+ case UntypedUse: {
+ JSValueOperand arg1(this, node->child1());
+ GPRTemporary result(this);
- JSValueOperand arg1(this, node->child1());
- GPRTemporary result(this);
+ GPRReg arg1GPR = arg1.gpr();
+ GPRReg resultGPR = result.gpr();
- GPRReg arg1GPR = arg1.gpr();
- GPRReg resultGPR = result.gpr();
+ arg1.use();
- arg1.use();
+ m_jit.move(arg1GPR, resultGPR);
+ m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), resultGPR);
+ JITCompiler::Jump slowCase = m_jit.branchTest64(JITCompiler::NonZero, resultGPR, TrustedImm32(static_cast<int32_t>(~1)));
- m_jit.move(arg1GPR, resultGPR);
- m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), resultGPR);
- JITCompiler::Jump slowCase = m_jit.branchTest64(JITCompiler::NonZero, resultGPR, TrustedImm32(static_cast<int32_t>(~1)));
+ addSlowPathGenerator(
+ slowPathCall(slowCase, this, dfgConvertJSValueToBoolean, resultGPR, arg1GPR));
- addSlowPathGenerator(
- slowPathCall(slowCase, this, dfgConvertJSValueToBoolean, resultGPR, arg1GPR));
-
- m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueTrue)), resultGPR);
- jsValueResult(resultGPR, node, DataFormatJSBoolean, UseChildrenCalledExplicitly);
+ m_jit.xor64(TrustedImm32(static_cast<int32_t>(ValueTrue)), resultGPR);
+ jsValueResult(resultGPR, node, DataFormatJSBoolean, UseChildrenCalledExplicitly);
+ return;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
-void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken, bool needSpeculationCheck)
+void SpeculativeJIT::emitObjectOrOtherBranch(Edge nodeUse, BlockIndex taken, BlockIndex notTaken)
{
- JSValueOperand value(this, nodeUse);
+ JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
GPRTemporary scratch(this);
GPRReg valueGPR = value.gpr();
GPRReg scratchGPR = scratch.gpr();
@@ -1759,23 +1741,19 @@
if (m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(valueGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ MacroAssembler::Address(valueGPR, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
} else {
m_jit.loadPtr(MacroAssembler::Address(valueGPR, JSCell::structureOffset()), scratchGPR);
- if (needSpeculationCheck) {
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse,
- m_jit.branchPtr(
- MacroAssembler::Equal,
- scratchGPR,
- MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchPtr(
+ MacroAssembler::Equal,
+ scratchGPR,
+ MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
JITCompiler::Jump isNotMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::Zero, MacroAssembler::Address(scratchGPR, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
@@ -1791,10 +1769,12 @@
notCell.link(&m_jit);
- if (needSpeculationCheck) {
+ if (needsTypeCheck(nodeUse, SpecCell | SpecOther)) {
m_jit.move(valueGPR, scratchGPR);
m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), scratchGPR);
- speculationCheck(BadType, JSValueRegs(valueGPR), nodeUse, m_jit.branch64(MacroAssembler::NotEqual, scratchGPR, MacroAssembler::TrustedImm64(ValueNull)));
+ typeCheck(
+ JSValueRegs(valueGPR), nodeUse, SpecCell | SpecOther, m_jit.branch64(
+ MacroAssembler::NotEqual, scratchGPR, MacroAssembler::TrustedImm64(ValueNull)));
}
jump(notTaken);
@@ -1806,14 +1786,15 @@
BlockIndex taken = node->takenBlockIndex();
BlockIndex notTaken = node->notTakenBlockIndex();
- if (node->child1()->shouldSpeculateObjectOrOther()) {
- emitObjectOrOtherBranch(node->child1(), taken, notTaken,
- !isObjectOrOtherSpeculation(m_state.forNode(node->child1()).m_type));
+ switch (node->child1().useKind()) {
+ case ObjectOrOtherUse: {
+ emitObjectOrOtherBranch(node->child1(), taken, notTaken);
return;
}
-
- if (node->child1()->shouldSpeculateNumber()) {
- if (node->child1()->shouldSpeculateInteger()) {
+
+ case Int32Use:
+ case NumberUse: {
+ if (node->child1().useKind() == Int32Use) {
bool invert = false;
if (taken == nextBlock()) {
@@ -1837,56 +1818,62 @@
return;
}
- JSValueOperand value(this, node->child1());
- GPRReg valueGPR = value.gpr();
+ case UntypedUse:
+ case BooleanUse: {
+ JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
+ GPRReg valueGPR = value.gpr();
- bool predictBoolean = isBooleanSpeculation(node->child1()->prediction());
-
- if (predictBoolean) {
- if (isBooleanSpeculation(m_state.forNode(node->child1()).m_type)) {
- MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
+ if (node->child1().useKind() == BooleanUse) {
+ if (!needsTypeCheck(node->child1(), SpecBoolean)) {
+ MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
- if (taken == nextBlock()) {
- condition = MacroAssembler::Zero;
- BlockIndex tmp = taken;
- taken = notTaken;
- notTaken = tmp;
+ if (taken == nextBlock()) {
+ condition = MacroAssembler::Zero;
+ BlockIndex tmp = taken;
+ taken = notTaken;
+ notTaken = tmp;
+ }
+
+ branchTest32(condition, valueGPR, TrustedImm32(true), taken);
+ jump(notTaken);
+ } else {
+ branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), notTaken);
+ branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), taken);
+
+ typeCheck(JSValueRegs(valueGPR), node->child1(), SpecBoolean, m_jit.jump());
}
-
- branchTest32(condition, valueGPR, TrustedImm32(true), taken);
- jump(notTaken);
+ value.use();
} else {
- branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), notTaken);
- branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), taken);
-
- speculationCheck(BadType, JSValueRegs(valueGPR), node->child1(), m_jit.jump());
+ GPRTemporary result(this);
+ GPRReg resultGPR = result.gpr();
+
+ if (node->child1()->prediction() & SpecInt32) {
+ branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsNumber(0))), notTaken);
+ branch64(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister, taken);
+ }
+
+ if (node->child1()->prediction() & SpecBoolean) {
+ branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), notTaken);
+ branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), taken);
+ }
+
+ value.use();
+
+ silentSpillAllRegisters(resultGPR);
+ callOperation(dfgConvertJSValueToBoolean, resultGPR, valueGPR);
+ silentFillAllRegisters(resultGPR);
+
+ branchTest32(MacroAssembler::NonZero, resultGPR, taken);
+ jump(notTaken);
}
- value.use();
- } else {
- GPRTemporary result(this);
- GPRReg resultGPR = result.gpr();
- if (node->child1()->prediction() & SpecInt32) {
- branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsNumber(0))), notTaken);
- branch64(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister, taken);
- }
-
- if (node->child1()->prediction() & SpecBoolean) {
- branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), notTaken);
- branch64(MacroAssembler::Equal, valueGPR, MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(true))), taken);
- }
-
- value.use();
-
- silentSpillAllRegisters(resultGPR);
- callOperation(dfgConvertJSValueToBoolean, resultGPR, valueGPR);
- silentFillAllRegisters(resultGPR);
-
- branchTest32(MacroAssembler::NonZero, resultGPR, taken);
- jump(notTaken);
+ noResult(node, UseChildrenCalledExplicitly);
+ return;
}
- noResult(node, UseChildrenCalledExplicitly);
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
}
void SpeculativeJIT::compile(Node* node)
@@ -1908,12 +1895,8 @@
break;
case Identity: {
- // This could be done a lot better. We take the cheap way out because Identity
- // is only going to stick around after CSE if we had prediction weirdness.
- JSValueOperand operand(this, node->child1());
- GPRTemporary result(this, operand);
- m_jit.move(operand.gpr(), result.gpr());
- jsValueResult(result.gpr(), node);
+ // CSE should always eliminate this.
+ RELEASE_ASSERT_NOT_REACHED();
break;
}
@@ -1931,6 +1914,8 @@
// If the CFA is tracking this variable and it found that the variable
// cannot have been assigned, then don't attempt to proceed.
if (value.isClear()) {
+ // FIXME: We should trap instead.
+ // https://bugs.webkit.org/show_bug.cgi?id=110383
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
break;
}
@@ -2131,19 +2116,6 @@
break;
}
- case CheckNumber: {
- if (!isNumberSpeculation(m_state.forNode(node->child1()).m_type)) {
- JSValueOperand op1(this, node->child1());
- JITCompiler::Jump isInteger = m_jit.branch64(MacroAssembler::AboveOrEqual, op1.gpr(), GPRInfo::tagTypeNumberRegister);
- speculationCheck(
- BadType, JSValueRegs(op1.gpr()), node->child1().node(),
- m_jit.branchTest64(MacroAssembler::Zero, op1.gpr(), GPRInfo::tagTypeNumberRegister));
- isInteger.link(&m_jit);
- }
- noResult(node);
- break;
- }
-
case ValueAdd:
case ArithAdd:
compileAdd(node);
@@ -2162,21 +2134,29 @@
break;
case ArithDiv: {
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
compileIntegerArithDivForX86(node);
break;
}
-
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
- FPRTemporary result(this, op1);
-
- FPRReg reg1 = op1.fpr();
- FPRReg reg2 = op2.fpr();
- m_jit.divDouble(reg1, reg2, result.fpr());
-
- doubleResult(result.fpr(), node);
+
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
+ FPRTemporary result(this, op1);
+
+ FPRReg reg1 = op1.fpr();
+ FPRReg reg2 = op2.fpr();
+ m_jit.divDouble(reg1, reg2, result.fpr());
+
+ doubleResult(result.fpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -2186,8 +2166,8 @@
}
case ArithAbs: {
- if (node->child1()->shouldSpeculateIntegerForArithmetic()
- && node->canSpeculateInteger()) {
+ switch (node->child1().useKind()) {
+ case Int32Use: {
SpeculateIntegerOperand op1(this, node->child1());
GPRTemporary result(this);
GPRTemporary scratch(this);
@@ -2201,18 +2181,26 @@
break;
}
- SpeculateDoubleOperand op1(this, node->child1());
- FPRTemporary result(this);
-
- m_jit.absDouble(op1.fpr(), result.fpr());
- doubleResult(result.fpr(), node);
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ FPRTemporary result(this);
+
+ m_jit.absDouble(op1.fpr(), result.fpr());
+ doubleResult(result.fpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
case ArithMin:
case ArithMax: {
- if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInteger()) {
+ switch (node->binaryUseKind()) {
+ case Int32Use: {
SpeculateStrictInt32Operand op1(this, node->child1());
SpeculateStrictInt32Operand op2(this, node->child2());
GPRTemporary result(this, op1);
@@ -2231,36 +2219,44 @@
break;
}
- SpeculateDoubleOperand op1(this, node->child1());
- SpeculateDoubleOperand op2(this, node->child2());
- FPRTemporary result(this, op1);
+ case NumberUse: {
+ SpeculateDoubleOperand op1(this, node->child1());
+ SpeculateDoubleOperand op2(this, node->child2());
+ FPRTemporary result(this, op1);
- MacroAssembler::JumpList done;
+ MacroAssembler::JumpList done;
- MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());
+ MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());
- // op2 is eather the lesser one or one of then is NaN
- MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1.fpr(), op2.fpr());
+ // op2 is eather the lesser one or one of then is NaN
+ MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThanOrEqual : MacroAssembler::DoubleLessThanOrEqual, op1.fpr(), op2.fpr());
- // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
- // op1 + op2 and putting it into result.
- m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());
- done.append(m_jit.jump());
-
- op2Less.link(&m_jit);
- m_jit.moveDouble(op2.fpr(), result.fpr());
-
- if (op1.fpr() != result.fpr()) {
+ // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding
+ // op1 + op2 and putting it into result.
+ m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());
done.append(m_jit.jump());
+
+ op2Less.link(&m_jit);
+ m_jit.moveDouble(op2.fpr(), result.fpr());
+
+ if (op1.fpr() != result.fpr()) {
+ done.append(m_jit.jump());
- op1Less.link(&m_jit);
- m_jit.moveDouble(op1.fpr(), result.fpr());
- } else
- op1Less.link(&m_jit);
+ op1Less.link(&m_jit);
+ m_jit.moveDouble(op1.fpr(), result.fpr());
+ } else
+ op1Less.link(&m_jit);
- done.link(&m_jit);
+ done.link(&m_jit);
- doubleResult(result.fpr(), node);
+ doubleResult(result.fpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -2617,18 +2613,18 @@
switch (arrayMode.type()) {
case Array::Int32:
case Array::Contiguous: {
- JSValueOperand value(this, child3);
+ JSValueOperand value(this, child3, ManualOperandSpeculation);
GPRReg valueReg = value.gpr();
if (!m_compileOkay)
return;
- if (arrayMode.type() == Array::Int32
- && !isInt32Speculation(m_state.forNode(child3).m_type)) {
- speculationCheck(
- BadType, JSValueRegs(valueReg), child3,
- m_jit.branch64(MacroAssembler::Below, valueReg, GPRInfo::tagTypeNumberRegister));
+ if (arrayMode.type() == Array::Int32) {
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueReg), child3, SpecInt32,
+ m_jit.branch64(
+ MacroAssembler::Below, valueReg, GPRInfo::tagTypeNumberRegister));
}
if (arrayMode.type() == Array::Contiguous && Heap::isWriteBarrierEnabled()) {
@@ -2928,13 +2924,14 @@
switch (node->arrayMode().type()) {
case Array::Int32:
case Array::Contiguous: {
- JSValueOperand value(this, node->child2());
+ JSValueOperand value(this, node->child2(), ManualOperandSpeculation);
GPRReg valueGPR = value.gpr();
- if (node->arrayMode().type() == Array::Int32 && !isInt32Speculation(m_state.forNode(node->child2()).m_type)) {
- speculationCheck(
- BadType, JSValueRegs(valueGPR), node->child2(),
- m_jit.branch64(MacroAssembler::Below, valueGPR, GPRInfo::tagTypeNumberRegister));
+ if (node->arrayMode().type() == Array::Int32) {
+ DFG_TYPE_CHECK(
+ JSValueRegs(valueGPR), node->child2(), SpecInt32,
+ m_jit.branch64(
+ MacroAssembler::Below, valueGPR, GPRInfo::tagTypeNumberRegister));
}
if (node->arrayMode().type() != Array::Int32 && Heap::isWriteBarrierEnabled()) {
@@ -2962,13 +2959,9 @@
SpeculateDoubleOperand value(this, node->child2());
FPRReg valueFPR = value.fpr();
- if (!isRealNumberSpeculation(m_state.forNode(node->child2()).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
- }
+ DFG_TYPE_CHECK(
+ JSValueRegs(), node->child2(), SpecRealNumber,
+ m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, valueFPR, valueFPR));
m_jit.load32(MacroAssembler::Address(storageGPR, Butterfly::offsetOfPublicLength()), storageLengthGPR);
MacroAssembler::Jump slowPath = m_jit.branch32(MacroAssembler::AboveOrEqual, storageLengthGPR, MacroAssembler::Address(storageGPR, Butterfly::offsetOfVectorLength()));
@@ -3171,7 +3164,8 @@
}
case ToPrimitive: {
- if (node->child1()->shouldSpeculateInteger()) {
+ switch (node->child1().useKind()) {
+ case Int32Use: {
// It's really profitable to speculate integer, since it's really cheap,
// it means we don't have to do any real work, and we emit a lot less code.
@@ -3186,30 +3180,36 @@
break;
}
- // FIXME: Add string speculation here.
+ case UntypedUse: {
+ JSValueOperand op1(this, node->child1());
+ GPRTemporary result(this, op1);
- JSValueOperand op1(this, node->child1());
- GPRTemporary result(this, op1);
+ GPRReg op1GPR = op1.gpr();
+ GPRReg resultGPR = result.gpr();
- GPRReg op1GPR = op1.gpr();
- GPRReg resultGPR = result.gpr();
+ op1.use();
- op1.use();
-
- if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
- m_jit.move(op1GPR, resultGPR);
- else {
- MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
- MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+ if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
+ m_jit.move(op1GPR, resultGPR);
+ else {
+ MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
- alreadyPrimitive.link(&m_jit);
- m_jit.move(op1GPR, resultGPR);
+ alreadyPrimitive.link(&m_jit);
+ m_jit.move(op1GPR, resultGPR);
- addSlowPathGenerator(
- slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
+ addSlowPathGenerator(
+ slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
+ }
+
+ jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
+ break;
}
-
- jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3251,25 +3251,22 @@
case ALL_DOUBLE_INDEXING_TYPES: {
SpeculateDoubleOperand operand(this, use);
FPRReg opFPR = operand.fpr();
- if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
- }
-
+ DFG_TYPE_CHECK(
+ JSValueRegs(), use, SpecRealNumber,
+ m_jit.branchDouble(
+ MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
m_jit.storeDouble(opFPR, MacroAssembler::Address(storageGPR, sizeof(double) * operandIdx));
break;
}
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- JSValueOperand operand(this, use);
+ JSValueOperand operand(this, use, ManualOperandSpeculation);
GPRReg opGPR = operand.gpr();
- if (hasInt32(node->indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) {
- speculationCheck(
- BadType, JSValueRegs(opGPR), use,
- m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
+ if (hasInt32(node->indexingType())) {
+ DFG_TYPE_CHECK(
+ JSValueRegs(opGPR), use, SpecInt32,
+ m_jit.branch64(
+ MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
}
m_jit.store64(opGPR, MacroAssembler::Address(storageGPR, sizeof(JSValue) * operandIdx));
break;
@@ -3319,25 +3316,22 @@
GPRTemporary scratch(this);
FPRReg opFPR = operand.fpr();
GPRReg scratchGPR = scratch.gpr();
- if (!isRealNumberSpeculation(m_state.forNode(use).m_type)) {
- // FIXME: We need a way of profiling these, and we need to hoist them into
- // SpeculateDoubleOperand.
- speculationCheck(
- BadType, JSValueRegs(), 0,
- m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
- }
-
+ DFG_TYPE_CHECK(
+ JSValueRegs(), use, SpecRealNumber,
+ m_jit.branchDouble(
+ MacroAssembler::DoubleNotEqualOrUnordered, opFPR, opFPR));
m_jit.boxDouble(opFPR, scratchGPR);
m_jit.store64(scratchGPR, buffer + operandIdx);
break;
}
case ALL_INT32_INDEXING_TYPES: {
- JSValueOperand operand(this, use);
+ JSValueOperand operand(this, use, ManualOperandSpeculation);
GPRReg opGPR = operand.gpr();
- if (hasInt32(node->indexingType()) && !isInt32Speculation(m_state.forNode(use).m_type)) {
- speculationCheck(
- BadType, JSValueRegs(opGPR), use,
- m_jit.branch64(MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
+ if (hasInt32(node->indexingType())) {
+ DFG_TYPE_CHECK(
+ JSValueRegs(opGPR), use, SpecInt32,
+ m_jit.branch64(
+ MacroAssembler::Below, opGPR, GPRInfo::tagTypeNumberRegister));
}
m_jit.store64(opGPR, buffer + operandIdx);
break;
@@ -3559,24 +3553,21 @@
}
case ConvertThis: {
- if (isObjectSpeculation(m_state.forNode(node->child1()).m_type)) {
- SpeculateCellOperand thisValue(this, node->child1());
- GPRTemporary result(this, thisValue);
- m_jit.move(thisValue.gpr(), result.gpr());
- cellResult(result.gpr(), node);
- break;
- }
-
- if (isOtherSpeculation(node->child1()->prediction())) {
- JSValueOperand thisValue(this, node->child1());
+ switch (node->child1().useKind()) {
+ case OtherUse: {
+ JSValueOperand thisValue(this, node->child1(), ManualOperandSpeculation);
GPRTemporary scratch(this);
GPRReg thisValueGPR = thisValue.gpr();
GPRReg scratchGPR = scratch.gpr();
- if (!isOtherSpeculation(m_state.forNode(node->child1()).m_type)) {
+ if (needsTypeCheck(node->child1(), SpecOther)) {
m_jit.move(thisValueGPR, scratchGPR);
m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), scratchGPR);
- speculationCheck(BadType, JSValueRegs(thisValueGPR), node->child1(), m_jit.branch64(MacroAssembler::NotEqual, scratchGPR, MacroAssembler::TrustedImm64(ValueNull)));
+ typeCheck(
+ JSValueRegs(thisValueGPR), node->child1(), SpecOther,
+ m_jit.branch64(
+ MacroAssembler::NotEqual, scratchGPR,
+ MacroAssembler::TrustedImm64(ValueNull)));
}
m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalThisObjectFor(node->codeOrigin)), scratchGPR);
@@ -3584,30 +3575,42 @@
break;
}
- if (isObjectSpeculation(node->child1()->prediction())) {
+ case ObjectUse: {
SpeculateCellOperand thisValue(this, node->child1());
GPRTemporary result(this, thisValue);
GPRReg thisValueGPR = thisValue.gpr();
GPRReg resultGPR = result.gpr();
- if (!isObjectSpeculation(m_state.forNode(node->child1()).m_type))
- speculationCheck(BadType, JSValueSource::unboxedCell(thisValueGPR), node->child1(), m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValueGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(thisValueGPR), node->child1(), SpecObject,
+ m_jit.branchPtr(
+ JITCompiler::Equal,
+ JITCompiler::Address(thisValueGPR, JSCell::structureOffset()),
+ JITCompiler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
m_jit.move(thisValueGPR, resultGPR);
cellResult(resultGPR, node);
break;
}
-
- JSValueOperand thisValue(this, node->child1());
- GPRReg thisValueGPR = thisValue.gpr();
-
- flushRegisters();
-
- GPRResult result(this);
- callOperation(operationConvertThis, result.gpr(), thisValueGPR);
-
- cellResult(result.gpr(), node);
+
+ case UntypedUse: {
+ JSValueOperand thisValue(this, node->child1());
+ GPRReg thisValueGPR = thisValue.gpr();
+
+ flushRegisters();
+
+ GPRResult result(this);
+ callOperation(operationConvertThis, result.gpr(), thisValueGPR);
+
+ cellResult(result.gpr(), node);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3776,8 +3779,9 @@
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
break;
}
-
- if (isCellSpeculation(node->child1()->prediction())) {
+
+ switch (node->child1().useKind()) {
+ case CellUse: {
SpeculateCellOperand base(this, node->child1());
GPRTemporary result(this, base);
@@ -3792,20 +3796,27 @@
break;
}
- JSValueOperand base(this, node->child1());
- GPRTemporary result(this, base);
+ case UntypedUse: {
+ JSValueOperand base(this, node->child1());
+ GPRTemporary result(this, base);
- GPRReg baseGPR = base.gpr();
- GPRReg resultGPR = result.gpr();
+ GPRReg baseGPR = base.gpr();
+ GPRReg resultGPR = result.gpr();
- base.use();
+ base.use();
- JITCompiler::Jump notCell = m_jit.branchTest64(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
+ JITCompiler::Jump notCell = m_jit.branchTest64(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
- cachedGetById(node->codeOrigin, baseGPR, resultGPR, node->identifierNumber(), notCell);
+ cachedGetById(node->codeOrigin, baseGPR, resultGPR, node->identifierNumber(), notCell);
- jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
-
+ jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3814,8 +3825,9 @@
terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
break;
}
-
- if (isCellSpeculation(node->child1()->prediction())) {
+
+ switch (node->child1().useKind()) {
+ case CellUse: {
SpeculateCellOperand base(this, node->child1());
GPRReg baseGPR = base.gpr();
@@ -3833,21 +3845,28 @@
break;
}
- JSValueOperand base(this, node->child1());
- GPRReg baseGPR = base.gpr();
+ case UntypedUse: {
+ JSValueOperand base(this, node->child1());
+ GPRReg baseGPR = base.gpr();
- GPRResult result(this);
- GPRReg resultGPR = result.gpr();
+ GPRResult result(this);
+ GPRReg resultGPR = result.gpr();
- base.use();
- flushRegisters();
+ base.use();
+ flushRegisters();
- JITCompiler::Jump notCell = m_jit.branchTest64(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
+ JITCompiler::Jump notCell = m_jit.branchTest64(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
- cachedGetById(node->codeOrigin, baseGPR, resultGPR, node->identifierNumber(), notCell, DontSpill);
+ cachedGetById(node->codeOrigin, baseGPR, resultGPR, node->identifierNumber(), notCell, DontSpill);
- jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
-
+ jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
break;
}
@@ -3871,13 +3890,6 @@
case CheckStructure:
case ForwardCheckStructure: {
- AbstractValue& value = m_state.forNode(node->child1());
- if (value.m_currentKnownStructure.isSubsetOf(node->structureSet())
- && isCellSpeculation(value.m_type)) {
- noResult(node);
- break;
- }
-
SpeculationDirection direction = node->op() == ForwardCheckStructure ? ForwardSpeculation : BackwardSpeculation;
SpeculateCellOperand base(this, node->child1(), direction);
@@ -3942,6 +3954,8 @@
JITCompiler::Jump isOK = m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(op1.gpr(), JSCell::structureOffset()), TrustedImmPtr(node->structure()));
m_jit.breakpoint();
isOK.link(&m_jit);
+#else
+ speculateCell(node->child1());
#endif
noResult(node);
@@ -3949,6 +3963,8 @@
}
case PhantomPutStructure: {
+ ASSERT(isKnownCell(node->child1().node()));
+
ASSERT(node->structureTransitionData().previousStructure->transitionWatchpointSetHasBeenInvalidated());
m_jit.addWeakReferenceTransition(
node->codeOrigin.codeOriginOwner(),
@@ -4271,7 +4287,7 @@
}
case TypeOf: {
- JSValueOperand value(this, node->child1());
+ JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
GPRReg valueGPR = value.gpr();
GPRTemporary temp(this);
GPRReg tempGPR = temp.gpr();
@@ -4280,19 +4296,21 @@
JITCompiler::JumpList doneJumps;
flushRegisters();
+
+ ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
JITCompiler::Jump isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
- if (node->child1()->shouldSpeculateCell())
- speculationCheck(BadType, JSValueSource(valueGPR), node->child1(), isNotCell);
+ if (node->child1().useKind() != UntypedUse)
+ DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecCell, isNotCell);
- if (!node->child1()->shouldSpeculateObject()) {
+ if (!node->child1()->shouldSpeculateObject() || node->child1().useKind() == StringUse) {
m_jit.loadPtr(JITCompiler::Address(valueGPR, JSCell::structureOffset()), tempGPR);
JITCompiler::Jump notString = m_jit.branch8(JITCompiler::NotEqual, JITCompiler::Address(tempGPR, Structure::typeInfoTypeOffset()), TrustedImm32(StringType));
- if (node->child1()->shouldSpeculateString())
- speculationCheck(BadType, JSValueSource(valueGPR), node->child1(), notString);
+ if (node->child1().useKind() == StringUse)
+ DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecString, notString);
m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.stringString()), resultGPR);
doneJumps.append(m_jit.jump());
- if (!node->child1()->shouldSpeculateString()) {
+ if (node->child1().useKind() != StringUse) {
notString.link(&m_jit);
callOperation(operationTypeOf, resultGPR, valueGPR);
doneJumps.append(m_jit.jump());
@@ -4302,7 +4320,7 @@
doneJumps.append(m_jit.jump());
}
- if (!node->child1()->shouldSpeculateCell()) {
+ if (node->child1().useKind() == UntypedUse) {
isNotCell.link(&m_jit);
JITCompiler::Jump notNumber = m_jit.branchTest64(JITCompiler::Zero, valueGPR, GPRInfo::tagTypeNumberRegister);
m_jit.move(TrustedImmPtr(m_jit.globalData()->smallStrings.numberString()), resultGPR);
@@ -4771,6 +4789,10 @@
}
case Phantom:
+ DFG_NODE_DO_TO_CHILDREN(m_jit.graph(), node, speculate);
+ noResult(node);
+ break;
+
case PhantomLocal:
// This is a no-op.
noResult(node);
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index 9dc5dbc..8a2da48 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -289,11 +289,11 @@
Node* getLocal = insertionSet.insertNode(
indexInBlock + 1, DontRefChildren, DontRefNode, variable->prediction(),
- GetLocal, codeOrigin, OpInfo(variable), node);
+ GetLocal, codeOrigin, OpInfo(variable), Edge(node));
insertionSet.insertNode(
indexInBlock + 1, RefChildren, DontRefNode, SpecNone, CheckStructure,
codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
- getLocal);
+ Edge(getLocal, CellUse));
if (block->variablesAtTail.operand(variable->local()) == node)
block->variablesAtTail.operand(variable->local()) = getLocal;
@@ -317,7 +317,7 @@
// to exit.
CodeOrigin codeOrigin = node->codeOrigin;
- Node* child1 = node->child1().node();
+ Edge child1 = node->child1();
insertionSet.insertNode(
indexInBlock, DontRefChildren, DontRefNode, SpecNone, SetLocal, codeOrigin,
@@ -327,7 +327,7 @@
// next bytecode instruction rather than reexecuting the current one.
insertionSet.insertNode(
indexInBlock, RefChildren, DontRefNode, SpecNone, ForwardCheckStructure,
- codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), child1);
+ codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), Edge(child1.node(), CellUse));
changed = true;
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
new file mode 100644
index 0000000..bb81920
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 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
+ * 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 "DFGUseKind.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace WTF {
+
+using namespace JSC::DFG;
+
+void printInternal(PrintStream& out, UseKind useKind)
+{
+ switch (useKind) {
+ case UntypedUse:
+ out.print("Untyped");
+ break;
+ case Int32Use:
+ out.print("Int32");
+ break;
+ case KnownInt32Use:
+ out.print("KnownInt32");
+ break;
+ case RealNumberUse:
+ out.print("RealNumber");
+ break;
+ case NumberUse:
+ out.print("Number");
+ break;
+ case KnownNumberUse:
+ out.print("KnownNumber");
+ break;
+ case BooleanUse:
+ out.print("Boolean");
+ break;
+ case CellUse:
+ out.print("Cell");
+ break;
+ case KnownCellUse:
+ out.print("KnownCell");
+ break;
+ case ObjectUse:
+ out.print("Object");
+ break;
+ case ObjectOrOtherUse:
+ out.print("ObjectOrOther");
+ break;
+ case StringUse:
+ out.print("String");
+ break;
+ case NotCellUse:
+ out.print("NotCell");
+ break;
+ case OtherUse:
+ out.print("Other");
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
new file mode 100644
index 0000000..74b0ca2
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 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
+ * 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.
+ */
+
+#ifndef DFGUseKind_h
+#define DFGUseKind_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "SpeculatedType.h"
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace DFG {
+
+enum UseKind {
+ UntypedUse,
+ Int32Use,
+ KnownInt32Use,
+ RealNumberUse,
+ NumberUse,
+ KnownNumberUse,
+ BooleanUse,
+ CellUse,
+ KnownCellUse,
+ ObjectUse,
+ ObjectOrOtherUse,
+ StringUse,
+ NotCellUse,
+ OtherUse,
+ LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
+};
+
+ALWAYS_INLINE SpeculatedType typeFilterFor(UseKind useKind)
+{
+ switch (useKind) {
+ case UntypedUse:
+ return SpecEmptyOrTop; // TOP isn't good enough; untyped uses may use the normally unseen empty value, in the case of lazy registers.
+ case Int32Use:
+ case KnownInt32Use:
+ return SpecInt32;
+ case RealNumberUse:
+ return SpecRealNumber;
+ case NumberUse:
+ case KnownNumberUse:
+ return SpecNumber;
+ case BooleanUse:
+ return SpecBoolean;
+ case CellUse:
+ case KnownCellUse:
+ return SpecCell;
+ case ObjectUse:
+ return SpecObject;
+ case ObjectOrOtherUse:
+ return SpecObject | SpecOther;
+ case StringUse:
+ return SpecString;
+ case NotCellUse:
+ return ~SpecCell;
+ case OtherUse:
+ return SpecOther;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return SpecTop;
+ }
+}
+
+ALWAYS_INLINE bool isNumerical(UseKind kind)
+{
+ switch (kind) {
+ case Int32Use:
+ case KnownInt32Use:
+ case RealNumberUse:
+ case NumberUse:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::DFG::UseKind);
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGUseKind_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp
index 22b7b9c..a85c4e3 100644
--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp
+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp
@@ -354,7 +354,7 @@
void reportValidationContext(Node* node, Edge edge)
{
- dataLogF("@%u -> %s@%u", node->index(), useKindToString(edge.useKind()), edge->index());
+ dataLog(node, " -> ", edge);
}
void reportValidationContext(VirtualRegister local, BlockIndex blockIndex)
@@ -389,7 +389,7 @@
void reportValidationContext(
Node* node, BlockIndex blockIndex, Node* expectedNode, Edge incomingEdge)
{
- dataLogF("@%u in Block #%u, searching for @%u from @%u", node->index(), blockIndex, expectedNode->index(), incomingEdge->index());
+ dataLog(node, " in Block #", blockIndex, ", searching for ", expectedNode, " from ", incomingEdge);
}
void dumpGraphIfAppropriate()