All DFG nodes should have a mutable set of flags
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Mar 2012 09:50:38 +0000 (09:50 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 12 Mar 2012 09:50:38 +0000 (09:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=80779
<rdar://problem/11026218>

Reviewed by Gavin Barraclough.

Got rid of NodeId, and placed all of the flags that distinguished NodeId
from NodeType into a separate Node::flags field. Combined what was previously
ArithNodeFlags into Node::flags.

In the process of debugging, I found that the debug support in the virtual
register allocator was lacking, so I improved it. I also realized that the
virtual register allocator was assuming that the nodes in a basic block were
contiguous, which is no longer the case. So I fixed that. The fix also made
it natural to have more extreme assertions, so I added them. I suspect this
will make it easier to catch virtual register allocation bugs in the future.

This is mostly performance neutral; if anything it looks like a slight
speed-up.

This patch does leave some work for future refactorings; for example, Node::op
is unencapsulated. This was already the case, though now it feels even more
like it should be. I avoided doing that because this patch has already grown
way bigger than I wanted.

Finally, this patch creates a DFGNode.cpp file and makes a slight effort to
move some unnecessarily inline stuff out of DFGNode.h.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* dfg/DFGArithNodeFlagsInferencePhase.cpp:
(JSC::DFG::ArithNodeFlagsInferencePhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addToGraph):
(JSC::DFG::ByteCodeParser::makeSafe):
(JSC::DFG::ByteCodeParser::makeDivSafe):
(JSC::DFG::ByteCodeParser::handleMinMax):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCFAPhase.cpp:
(JSC::DFG::CFAPhase::performBlockCFA):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::endIndexForPureCSE):
(JSC::DFG::CSEPhase::pureCSE):
(JSC::DFG::CSEPhase::clobbersWorld):
(JSC::DFG::CSEPhase::impureCSE):
(JSC::DFG::CSEPhase::setReplacement):
(JSC::DFG::CSEPhase::eliminate):
(JSC::DFG::CSEPhase::performNodeCSE):
(JSC::DFG::CSEPhase::performBlockCSE):
(CSEPhase):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::opName):
(JSC::DFG::Graph::dump):
(DFG):
* dfg/DFGNode.cpp: Added.
(DFG):
(JSC::DFG::arithNodeFlagsAsString):
* dfg/DFGNode.h:
(DFG):
(JSC::DFG::nodeUsedAsNumber):
(JSC::DFG::nodeCanTruncateInteger):
(JSC::DFG::nodeCanIgnoreNegativeZero):
(JSC::DFG::nodeMayOverflow):
(JSC::DFG::nodeCanSpeculateInteger):
(JSC::DFG::defaultFlags):
(JSC::DFG::Node::Node):
(Node):
(JSC::DFG::Node::setOpAndDefaultFlags):
(JSC::DFG::Node::mustGenerate):
(JSC::DFG::Node::arithNodeFlags):
(JSC::DFG::Node::setArithNodeFlag):
(JSC::DFG::Node::mergeArithNodeFlags):
(JSC::DFG::Node::hasResult):
(JSC::DFG::Node::hasInt32Result):
(JSC::DFG::Node::hasNumberResult):
(JSC::DFG::Node::hasJSResult):
(JSC::DFG::Node::hasBooleanResult):
(JSC::DFG::Node::isJump):
(JSC::DFG::Node::isBranch):
(JSC::DFG::Node::isTerminal):
(JSC::DFG::Node::child1):
(JSC::DFG::Node::child2):
(JSC::DFG::Node::child3):
(JSC::DFG::Node::firstChild):
(JSC::DFG::Node::numChildren):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::vote):
(JSC::DFG::PredictionPropagationPhase::fixupNode):
* dfg/DFGScoreBoard.h:
(ScoreBoard):
(JSC::DFG::ScoreBoard::~ScoreBoard):
(JSC::DFG::ScoreBoard::assertClear):
(JSC::DFG::ScoreBoard::use):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::useChildren):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGVirtualRegisterAllocationPhase.cpp:
(JSC::DFG::VirtualRegisterAllocationPhase::run):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@110419 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/dfg/DFGArithNodeFlagsInferencePhase.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNode.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGScoreBoard.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp

index 5bed329..d4a51d2 100644 (file)
@@ -68,6 +68,7 @@ SET(JavaScriptCore_SOURCES
     dfg/DFGDriver.cpp
     dfg/DFGGraph.cpp
     dfg/DFGJITCompiler.cpp
+    dfg/DFGNode.cpp
     dfg/DFGOSREntry.cpp
     dfg/DFGOSRExit.cpp
     dfg/DFGOSRExitCompiler.cpp
index ef70c46..0092392 100644 (file)
@@ -1,3 +1,111 @@
+2012-03-12  Filip Pizlo  <fpizlo@apple.com>
+
+        All DFG nodes should have a mutable set of flags
+        https://bugs.webkit.org/show_bug.cgi?id=80779
+        <rdar://problem/11026218>
+
+        Reviewed by Gavin Barraclough.
+        
+        Got rid of NodeId, and placed all of the flags that distinguished NodeId
+        from NodeType into a separate Node::flags field. Combined what was previously
+        ArithNodeFlags into Node::flags.
+        
+        In the process of debugging, I found that the debug support in the virtual
+        register allocator was lacking, so I improved it. I also realized that the
+        virtual register allocator was assuming that the nodes in a basic block were
+        contiguous, which is no longer the case. So I fixed that. The fix also made
+        it natural to have more extreme assertions, so I added them. I suspect this
+        will make it easier to catch virtual register allocation bugs in the future.
+        
+        This is mostly performance neutral; if anything it looks like a slight
+        speed-up.
+        
+        This patch does leave some work for future refactorings; for example, Node::op
+        is unencapsulated. This was already the case, though now it feels even more
+        like it should be. I avoided doing that because this patch has already grown
+        way bigger than I wanted.
+        
+        Finally, this patch creates a DFGNode.cpp file and makes a slight effort to
+        move some unnecessarily inline stuff out of DFGNode.h.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * dfg/DFGArithNodeFlagsInferencePhase.cpp:
+        (JSC::DFG::ArithNodeFlagsInferencePhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addToGraph):
+        (JSC::DFG::ByteCodeParser::makeSafe):
+        (JSC::DFG::ByteCodeParser::makeDivSafe):
+        (JSC::DFG::ByteCodeParser::handleMinMax):
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCFAPhase.cpp:
+        (JSC::DFG::CFAPhase::performBlockCFA):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::endIndexForPureCSE):
+        (JSC::DFG::CSEPhase::pureCSE):
+        (JSC::DFG::CSEPhase::clobbersWorld):
+        (JSC::DFG::CSEPhase::impureCSE):
+        (JSC::DFG::CSEPhase::setReplacement):
+        (JSC::DFG::CSEPhase::eliminate):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        (JSC::DFG::CSEPhase::performBlockCSE):
+        (CSEPhase):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::opName):
+        (JSC::DFG::Graph::dump):
+        (DFG):
+        * dfg/DFGNode.cpp: Added.
+        (DFG):
+        (JSC::DFG::arithNodeFlagsAsString):
+        * dfg/DFGNode.h:
+        (DFG):
+        (JSC::DFG::nodeUsedAsNumber):
+        (JSC::DFG::nodeCanTruncateInteger):
+        (JSC::DFG::nodeCanIgnoreNegativeZero):
+        (JSC::DFG::nodeMayOverflow):
+        (JSC::DFG::nodeCanSpeculateInteger):
+        (JSC::DFG::defaultFlags):
+        (JSC::DFG::Node::Node):
+        (Node):
+        (JSC::DFG::Node::setOpAndDefaultFlags):
+        (JSC::DFG::Node::mustGenerate):
+        (JSC::DFG::Node::arithNodeFlags):
+        (JSC::DFG::Node::setArithNodeFlag):
+        (JSC::DFG::Node::mergeArithNodeFlags):
+        (JSC::DFG::Node::hasResult):
+        (JSC::DFG::Node::hasInt32Result):
+        (JSC::DFG::Node::hasNumberResult):
+        (JSC::DFG::Node::hasJSResult):
+        (JSC::DFG::Node::hasBooleanResult):
+        (JSC::DFG::Node::isJump):
+        (JSC::DFG::Node::isBranch):
+        (JSC::DFG::Node::isTerminal):
+        (JSC::DFG::Node::child1):
+        (JSC::DFG::Node::child2):
+        (JSC::DFG::Node::child3):
+        (JSC::DFG::Node::firstChild):
+        (JSC::DFG::Node::numChildren):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::vote):
+        (JSC::DFG::PredictionPropagationPhase::fixupNode):
+        * dfg/DFGScoreBoard.h:
+        (ScoreBoard):
+        (JSC::DFG::ScoreBoard::~ScoreBoard):
+        (JSC::DFG::ScoreBoard::assertClear):
+        (JSC::DFG::ScoreBoard::use):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::useChildren):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGVirtualRegisterAllocationPhase.cpp:
+        (JSC::DFG::VirtualRegisterAllocationPhase::run):
+
 2012-03-10  Filip Pizlo  <fpizlo@apple.com>
 
         LLInt should support JSVALUE64
index b50f114..430b564 100644 (file)
@@ -169,6 +169,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGGraph.h \
        Source/JavaScriptCore/dfg/DFGJITCompiler.cpp \
        Source/JavaScriptCore/dfg/DFGJITCompiler.h \
+       Source/JavaScriptCore/dfg/DFGNode.cpp \
        Source/JavaScriptCore/dfg/DFGNode.h \
        Source/JavaScriptCore/dfg/DFGNodeReferenceBlob.h \
        Source/JavaScriptCore/dfg/DFGNodeUse.h \
index 8f40b7f..a72046e 100644 (file)
@@ -73,6 +73,7 @@
                0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F16D726142C39C000CF784A /* BitVector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F16D724142C39A200CF784A /* BitVector.cpp */; };
+               0F1D0861150C5A860074D109 /* DFGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1D085F150C5A800074D109 /* DFGNode.cpp */; };
                0F21C26814BE5F6800ADC64B /* JITDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C26614BE5F5E00ADC64B /* JITDriver.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F21C27C14BE727600ADC64B /* ExecutionHarness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27A14BE727300ADC64B /* ExecutionHarness.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F21C27D14BE727A00ADC64B /* CodeSpecializationKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F0FC45814BD15F100B81154 /* LLIntCallLinkInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLIntCallLinkInfo.h; sourceTree = "<group>"; };
                0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPaths.h; sourceTree = "<group>"; };
                0F16D724142C39A200CF784A /* BitVector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BitVector.cpp; sourceTree = "<group>"; };
+               0F1D085F150C5A800074D109 /* DFGNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNode.cpp; path = dfg/DFGNode.cpp; sourceTree = "<group>"; };
                0F21C26614BE5F5E00ADC64B /* JITDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITDriver.h; sourceTree = "<group>"; };
                0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeSpecializationKind.h; sourceTree = "<group>"; };
                0F21C27A14BE727300ADC64B /* ExecutionHarness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutionHarness.h; sourceTree = "<group>"; };
                86EC9DB31328DF44002B2AD7 /* dfg */ = {
                        isa = PBXGroup;
                        children = (
+                               0F1D085F150C5A800074D109 /* DFGNode.cpp */,
                                0FFFC94914EF909500C72532 /* DFGArithNodeFlagsInferencePhase.cpp */,
                                0FFFC94A14EF909500C72532 /* DFGArithNodeFlagsInferencePhase.h */,
                                0F62016D143FCD2F0068B77C /* DFGAbstractState.cpp */,
                                0FB5467D14F5CFD6002C2989 /* MethodOfGettingAValueProfile.cpp in Sources */,
                                0F56A1D515001CF4002992B1 /* ExecutionCounter.cpp in Sources */,
                                0A4337BB1506218800991C95 /* DFGRedundantPhiEliminationPhase.cpp in Sources */,
+                               0F1D0861150C5A860074D109 /* DFGNode.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 0c6808d..1480ae7 100644 (file)
@@ -95,6 +95,7 @@ SOURCES += \
     dfg/DFGDriver.cpp \
     dfg/DFGGraph.cpp \
     dfg/DFGJITCompiler.cpp \
+    dfg/DFGNode.cpp \
     dfg/DFGOperations.cpp \
     dfg/DFGOSREntry.cpp \
     dfg/DFGOSRExit.cpp \
index 0b6ece1..9a49364 100644 (file)
@@ -80,11 +80,8 @@ private:
         if (!node.shouldGenerate())
             return;
         
-        NodeType op = node.op;
-        ArithNodeFlags flags = 0;
-        
-        if (node.hasArithNodeFlags())
-            flags = node.rawArithNodeFlags();
+        NodeType op = static_cast<NodeType>(node.op);
+        NodeFlags flags = node.flags;
         
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         dataLog("   %s @%u: %s ", Graph::opName(op), m_compileIndex, arithNodeFlagsAsString(flags));
@@ -178,7 +175,7 @@ private:
             
         default:
             flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            if (op & NodeHasVarArgs) {
+            if (node.flags & NodeHasVarArgs) {
                 for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
                     changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeArithNodeFlags(flags);
             } else {
index 699c619..3a3678d 100644 (file)
@@ -572,7 +572,7 @@ private:
         ASSERT(op != Phi);
         m_currentBlock->append(resultIndex);
 
-        if (op & NodeMustGenerate)
+        if (defaultFlags(op) & NodeMustGenerate)
             m_graph.ref(resultIndex);
         return resultIndex;
     }
@@ -585,7 +585,7 @@ private:
         else
             m_currentBlock->append(resultIndex);
 
-        if (op & NodeMustGenerate)
+        if (defaultFlags(op) & NodeMustGenerate)
             m_graph.ref(resultIndex);
         return resultIndex;
     }
@@ -596,7 +596,7 @@ private:
         ASSERT(op != Phi);
         m_currentBlock->append(resultIndex);
 
-        if (op & NodeMustGenerate)
+        if (defaultFlags(op) & NodeMustGenerate)
             m_graph.ref(resultIndex);
         return resultIndex;
     }
@@ -610,7 +610,7 @@ private:
         
         m_numPassedVarArgs = 0;
         
-        if (op & NodeMustGenerate)
+        if (defaultFlags(op) & NodeMustGenerate)
             m_graph.ref(resultIndex);
         return resultIndex;
     }
@@ -699,7 +699,7 @@ private:
             return nodeIndex;
         
 #if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLog("Making %s @%u safe at bc#%u because slow-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(m_graph[nodeIndex].op), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
+        dataLog("Making %s @%u safe at bc#%u because slow-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(static_cast<NodeType>(m_graph[nodeIndex].op)), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
 #endif
         
         switch (m_graph[nodeIndex].op) {
@@ -752,7 +752,7 @@ private:
             return nodeIndex;
         
 #if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLog("Making %s @%u safe at bc#%u because special fast-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(m_graph[nodeIndex].op), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->specialFastCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
+        dataLog("Making %s @%u safe at bc#%u because special fast-case counter is at %u and exit profiles say %d, %d\n", Graph::opName(static_cast<NodeType>(m_graph[nodeIndex].op)), nodeIndex, m_currentIndex, m_inlineStackTop->m_profiledBlock->specialFastCaseProfileForBytecodeOffset(m_currentIndex)->m_counter, m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow), m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero));
 #endif
         
         // FIXME: It might be possible to make this more granular. The DFG certainly can
@@ -1267,7 +1267,7 @@ bool ByteCodeParser::handleMinMax(bool usesResult, int resultOperand, NodeType o
     }
     
     if (argumentCountIncludingThis == 3) { // Math.min(x, y)
-        set(resultOperand, addToGraph(op, OpInfo(NodeUseBottom), get(registerOffset + argumentToOperand(1)), get(registerOffset + argumentToOperand(2))));
+        set(resultOperand, addToGraph(op, get(registerOffset + argumentToOperand(1)), get(registerOffset + argumentToOperand(2))));
         return true;
     }
     
@@ -1295,7 +1295,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
         if (!MacroAssembler::supportsFloatingPointAbs())
             return false;
 
-        NodeIndex nodeIndex = addToGraph(ArithAbs, OpInfo(NodeUseBottom), get(registerOffset + argumentToOperand(1)));
+        NodeIndex nodeIndex = addToGraph(ArithAbs, get(registerOffset + argumentToOperand(1)));
         if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
             m_graph[nodeIndex].mergeArithNodeFlags(NodeMayOverflow);
         set(resultOperand, nodeIndex);
@@ -1562,11 +1562,11 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                 if (valueOfInt32Constant(op2) & 0x1f)
                     result = addToGraph(BitURShift, op1, op2);
                 else
-                    result = makeSafe(addToGraph(UInt32ToNumber, OpInfo(NodeUseBottom), op1));
+                    result = makeSafe(addToGraph(UInt32ToNumber, op1));
             }  else {
                 // Cannot optimize at this stage; shift & potentially rebox as a double.
                 result = addToGraph(BitURShift, op1, op2);
-                result = makeSafe(addToGraph(UInt32ToNumber, OpInfo(NodeUseBottom), result));
+                result = makeSafe(addToGraph(UInt32ToNumber, result));
             }
             set(currentInstruction[1].u.operand, result);
             NEXT_OPCODE(op_urshift);
@@ -1577,7 +1577,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         case op_pre_inc: {
             unsigned srcDst = currentInstruction[1].u.operand;
             NodeIndex op = get(srcDst);
-            set(srcDst, makeSafe(addToGraph(ArithAdd, OpInfo(NodeUseBottom), op, one())));
+            set(srcDst, makeSafe(addToGraph(ArithAdd, op, one())));
             NEXT_OPCODE(op_pre_inc);
         }
 
@@ -1587,14 +1587,14 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             ASSERT(result != srcDst); // Required for assumptions we make during OSR.
             NodeIndex op = get(srcDst);
             set(result, op);
-            set(srcDst, makeSafe(addToGraph(ArithAdd, OpInfo(NodeUseBottom), op, one())));
+            set(srcDst, makeSafe(addToGraph(ArithAdd, op, one())));
             NEXT_OPCODE(op_post_inc);
         }
 
         case op_pre_dec: {
             unsigned srcDst = currentInstruction[1].u.operand;
             NodeIndex op = get(srcDst);
-            set(srcDst, makeSafe(addToGraph(ArithSub, OpInfo(NodeUseBottom), op, one())));
+            set(srcDst, makeSafe(addToGraph(ArithSub, op, one())));
             NEXT_OPCODE(op_pre_dec);
         }
 
@@ -1603,7 +1603,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             unsigned srcDst = currentInstruction[2].u.operand;
             NodeIndex op = get(srcDst);
             set(result, op);
-            set(srcDst, makeSafe(addToGraph(ArithSub, OpInfo(NodeUseBottom), op, one())));
+            set(srcDst, makeSafe(addToGraph(ArithSub, op, one())));
             NEXT_OPCODE(op_post_dec);
         }
 
@@ -1613,22 +1613,22 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NodeIndex op1 = get(currentInstruction[2].u.operand);
             NodeIndex op2 = get(currentInstruction[3].u.operand);
             if (m_graph[op1].hasNumberResult() && m_graph[op2].hasNumberResult())
-                set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithAdd, OpInfo(NodeUseBottom), op1, op2)));
+                set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithAdd, op1, op2)));
             else
-                set(currentInstruction[1].u.operand, makeSafe(addToGraph(ValueAdd, OpInfo(NodeUseBottom), op1, op2)));
+                set(currentInstruction[1].u.operand, makeSafe(addToGraph(ValueAdd, op1, op2)));
             NEXT_OPCODE(op_add);
         }
 
         case op_sub: {
             NodeIndex op1 = get(currentInstruction[2].u.operand);
             NodeIndex op2 = get(currentInstruction[3].u.operand);
-            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithSub, OpInfo(NodeUseBottom), op1, op2)));
+            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithSub, op1, op2)));
             NEXT_OPCODE(op_sub);
         }
 
         case op_negate: {
             NodeIndex op1 = get(currentInstruction[2].u.operand);
-            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithNegate, OpInfo(NodeUseBottom), op1)));
+            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithNegate, op1)));
             NEXT_OPCODE(op_negate);
         }
 
@@ -1636,21 +1636,21 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             // Multiply requires that the inputs are not truncated, unfortunately.
             NodeIndex op1 = get(currentInstruction[2].u.operand);
             NodeIndex op2 = get(currentInstruction[3].u.operand);
-            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMul, OpInfo(NodeUseBottom), op1, op2)));
+            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMul, op1, op2)));
             NEXT_OPCODE(op_mul);
         }
 
         case op_mod: {
             NodeIndex op1 = get(currentInstruction[2].u.operand);
             NodeIndex op2 = get(currentInstruction[3].u.operand);
-            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMod, OpInfo(NodeUseBottom), op1, op2)));
+            set(currentInstruction[1].u.operand, makeSafe(addToGraph(ArithMod, op1, op2)));
             NEXT_OPCODE(op_mod);
         }
 
         case op_div: {
             NodeIndex op1 = get(currentInstruction[2].u.operand);
             NodeIndex op2 = get(currentInstruction[3].u.operand);
-            set(currentInstruction[1].u.operand, makeDivSafe(addToGraph(ArithDiv, OpInfo(NodeUseBottom), op1, op2)));
+            set(currentInstruction[1].u.operand, makeDivSafe(addToGraph(ArithDiv, op1, op2)));
             NEXT_OPCODE(op_div);
         }
 
index 0bb6759..b4e75f8 100644 (file)
@@ -87,7 +87,7 @@ private:
             if (!m_graph[nodeIndex].shouldGenerate())
                 continue;
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-            dataLog("      %s @%u: ", Graph::opName(m_graph[nodeIndex].op), nodeIndex);
+            dataLog("      %s @%u: ", Graph::opName(static_cast<NodeType>(m_graph[nodeIndex].op)), nodeIndex);
             m_state.dump(WTF::dataFile());
             dataLog("\n");
 #endif
index 4a91efb..82e1b46 100644 (file)
@@ -70,7 +70,7 @@ private:
     
     unsigned endIndexForPureCSE()
     {
-        unsigned result = m_lastSeen[m_graph[m_compileIndex].op & NodeIdMask];
+        unsigned result = m_lastSeen[m_graph[m_compileIndex].op];
         if (result == UINT_MAX)
             result = 0;
         else
@@ -97,7 +97,7 @@ private:
             if (node.op != otherNode.op)
                 continue;
             
-            if (node.arithNodeFlagsForCompare() != otherNode.arithNodeFlagsForCompare())
+            if (node.arithNodeFlags() != otherNode.arithNodeFlags())
                 continue;
             
             NodeIndex otherChild = canonicalize(otherNode.child1());
@@ -147,9 +147,9 @@ private:
     bool clobbersWorld(NodeIndex nodeIndex)
     {
         Node& node = m_graph[nodeIndex];
-        if (node.op & NodeClobbersWorld)
+        if (node.flags & NodeClobbersWorld)
             return true;
-        if (!(node.op & NodeMightClobber))
+        if (!(node.flags & NodeMightClobber))
             return false;
         switch (node.op) {
         case ValueAdd:
@@ -182,7 +182,7 @@ private:
 
             Node& otherNode = m_graph[index];
             if (node.op == otherNode.op
-                && node.arithNodeFlagsForCompare() == otherNode.arithNodeFlagsForCompare()) {
+                && node.arithNodeFlags() == otherNode.arithNodeFlags()) {
                 NodeIndex otherChild = canonicalize(otherNode.child1());
                 if (otherChild == NoNode)
                     return index;
@@ -506,7 +506,7 @@ private:
 #endif
         
         Node& node = m_graph[m_compileIndex];
-        node.op = Phantom;
+        node.setOpAndDefaultFlags(Phantom);
         node.setRefCount(1);
         
         // At this point we will eliminate all references to this node.
@@ -522,14 +522,14 @@ private:
         Node& node = m_graph[m_compileIndex];
         ASSERT(node.refCount() == 1);
         ASSERT(node.mustGenerate());
-        node.op = Phantom;
+        node.setOpAndDefaultFlags(Phantom);
     }
     
     void performNodeCSE(Node& node)
     {
         bool shouldGenerate = node.shouldGenerate();
 
-        if (node.op & NodeHasVarArgs) {
+        if (node.flags & NodeHasVarArgs) {
             for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
                 performSubstitution(m_graph.m_varArgChildren[childIdx], shouldGenerate);
         } else {
@@ -542,7 +542,7 @@ private:
             return;
         
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("   %s @%u: ", Graph::opName(m_graph[m_compileIndex].op), m_compileIndex);
+        dataLog("   %s @%u: ", Graph::opName(static_cast<NodeType>(m_graph[m_compileIndex].op)), m_compileIndex);
 #endif
         
         // NOTE: there are some nodes that we deliberately don't CSE even though we
@@ -669,7 +669,7 @@ private:
             break;
         }
         
-        m_lastSeen[node.op & NodeIdMask] = m_indexInBlock;
+        m_lastSeen[node.op] = m_indexInBlock;
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         dataLog("\n");
 #endif
@@ -678,7 +678,7 @@ private:
     void performBlockCSE(BasicBlock& block)
     {
         m_currentBlock = &block;
-        for (unsigned i = 0; i < LastNodeId; ++i)
+        for (unsigned i = 0; i < LastNodeType; ++i)
             m_lastSeen[i] = UINT_MAX;
 
         for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
@@ -691,7 +691,7 @@ private:
     NodeIndex m_compileIndex;
     unsigned m_indexInBlock;
     Vector<NodeIndex, 16> m_replacements;
-    FixedArray<unsigned, LastNodeId> m_lastSeen;
+    FixedArray<unsigned, LastNodeType> m_lastSeen;
 };
 
 void performCSE(Graph& graph)
index 11c0f52..900251e 100644 (file)
@@ -41,7 +41,7 @@ static const char* dfgOpNames[] = {
 
 const char *Graph::opName(NodeType op)
 {
-    return dfgOpNames[op & NodeIdMask];
+    return dfgOpNames[op];
 }
 
 const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessData)
@@ -120,7 +120,7 @@ void Graph::dumpCodeOrigin(NodeIndex nodeIndex)
 void Graph::dump(NodeIndex nodeIndex)
 {
     Node& node = at(nodeIndex);
-    NodeType op = node.op;
+    NodeType op = static_cast<NodeType>(node.op);
 
     unsigned refCount = node.refCount();
     bool skipped = !refCount;
@@ -157,7 +157,7 @@ void Graph::dump(NodeIndex nodeIndex)
         dataLog("-");
     dataLog(">\t%s(", opName(op));
     bool hasPrinted = false;
-    if (op & NodeHasVarArgs) {
+    if (node.flags & NodeHasVarArgs) {
         for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
             if (hasPrinted)
                 dataLog(", ");
@@ -175,8 +175,8 @@ void Graph::dump(NodeIndex nodeIndex)
         hasPrinted = !!node.child1();
     }
 
-    if (node.hasArithNodeFlags()) {
-        dataLog("%s%s", hasPrinted ? ", " : "", arithNodeFlagsAsString(node.rawArithNodeFlags()));
+    if (node.arithNodeFlags()) {
+        dataLog("%s%s", hasPrinted ? ", " : "", arithNodeFlagsAsString(node.arithNodeFlags()));
         hasPrinted = true;
     }
     if (node.hasVarNumber()) {
@@ -294,7 +294,7 @@ void Graph::dump()
 // FIXME: Convert this to be iterative, not recursive.
 #define DO_TO_CHILDREN(node, thingToDo) do {                            \
         Node& _node = (node);                                           \
-        if (_node.op & NodeHasVarArgs) {                                \
+        if (_node.flags & NodeHasVarArgs) {                             \
             for (unsigned _childIdx = _node.firstChild();               \
                  _childIdx < _node.firstChild() + _node.numChildren();  \
                  _childIdx++)                                           \
diff --git a/Source/JavaScriptCore/dfg/DFGNode.cpp b/Source/JavaScriptCore/dfg/DFGNode.cpp
new file mode 100644 (file)
index 0000000..c53817b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 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 "DFGNode.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+const char* arithNodeFlagsAsString(NodeFlags flags)
+{
+    flags &= NodeArithMask;
+    
+    if (!flags)
+        return "<empty>";
+
+    static const int size = 64;
+    static char description[size];
+    BoundsCheckedPointer<char> ptr(description, size);
+    
+    bool hasPrinted = false;
+    
+    if (flags & NodeUsedAsNumber) {
+        ptr.strcat("UsedAsNum");
+        hasPrinted = true;
+    }
+    
+    if (flags & NodeNeedsNegZero) {
+        if (hasPrinted)
+            ptr.strcat("|");
+        ptr.strcat("NeedsNegZero");
+        hasPrinted = true;
+    }
+    
+    if (flags & NodeMayOverflow) {
+        if (hasPrinted)
+            ptr.strcat("|");
+        ptr.strcat("MayOverflow");
+        hasPrinted = true;
+    }
+    
+    if (flags & NodeMayNegZero) {
+        if (hasPrinted)
+            ptr.strcat("|");
+        ptr.strcat("MayNegZero");
+        hasPrinted = true;
+    }
+    
+    *ptr++ = 0;
+    
+    return description;
+}
+
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
index e1c77bf..b672b67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -57,36 +57,50 @@ struct StructureTransitionData {
     }
 };
 
-typedef unsigned ArithNodeFlags;
-#define NodeUseBottom      0x00
-#define NodeUsedAsNumber   0x01
-#define NodeNeedsNegZero   0x02
-#define NodeUsedAsMask     0x03
-#define NodeMayOverflow    0x04
-#define NodeMayNegZero     0x08
-#define NodeBehaviorMask   0x0c
+// Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
+// and some additional informative flags (must generate, is constant, etc).
+#define NodeResultMask       0xF
+#define NodeResultJS         0x1
+#define NodeResultNumber     0x2
+#define NodeResultInt32      0x3
+#define NodeResultBoolean    0x4
+#define NodeResultStorage    0x5
+#define NodeMustGenerate    0x10 // set on nodes that have side effects, and may not trivially be removed by DCE.
+#define NodeHasVarArgs      0x20
+#define NodeClobbersWorld   0x40
+#define NodeMightClobber    0x80
+#define NodeArithMask      0xF00
+#define NodeUseBottom      0x000
+#define NodeUsedAsNumber   0x100
+#define NodeNeedsNegZero   0x200
+#define NodeUsedAsMask     0x300
+#define NodeMayOverflow    0x400
+#define NodeMayNegZero     0x800
+#define NodeBehaviorMask   0xc00
+
+typedef uint16_t NodeFlags;
 
-static inline bool nodeUsedAsNumber(ArithNodeFlags flags)
+static inline bool nodeUsedAsNumber(NodeFlags flags)
 {
     return !!(flags & NodeUsedAsNumber);
 }
 
-static inline bool nodeCanTruncateInteger(ArithNodeFlags flags)
+static inline bool nodeCanTruncateInteger(NodeFlags flags)
 {
     return !nodeUsedAsNumber(flags);
 }
 
-static inline bool nodeCanIgnoreNegativeZero(ArithNodeFlags flags)
+static inline bool nodeCanIgnoreNegativeZero(NodeFlags flags)
 {
     return !(flags & NodeNeedsNegZero);
 }
 
-static inline bool nodeMayOverflow(ArithNodeFlags flags)
+static inline bool nodeMayOverflow(NodeFlags flags)
 {
     return !!(flags & NodeMayOverflow);
 }
 
-static inline bool nodeCanSpeculateInteger(ArithNodeFlags flags)
+static inline bool nodeCanSpeculateInteger(NodeFlags flags)
 {
     if (flags & NodeMayOverflow)
         return !nodeUsedAsNumber(flags);
@@ -97,67 +111,7 @@ static inline bool nodeCanSpeculateInteger(ArithNodeFlags flags)
     return true;
 }
 
-static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
-{
-    if (!flags)
-        return "<empty>";
-
-    static const int size = 64;
-    static char description[size];
-    BoundsCheckedPointer<char> ptr(description, size);
-    
-    bool hasPrinted = false;
-    
-    if (flags & NodeUsedAsNumber) {
-        ptr.strcat("UsedAsNum");
-        hasPrinted = true;
-    }
-    
-    if (flags & NodeNeedsNegZero) {
-        if (hasPrinted)
-            ptr.strcat("|");
-        ptr.strcat("NeedsNegZero");
-        hasPrinted = true;
-    }
-    
-    if (flags & NodeMayOverflow) {
-        if (hasPrinted)
-            ptr.strcat("|");
-        ptr.strcat("MayOverflow");
-        hasPrinted = true;
-    }
-    
-    if (flags & NodeMayNegZero) {
-        if (hasPrinted)
-            ptr.strcat("|");
-        ptr.strcat("MayNegZero");
-        hasPrinted = true;
-    }
-    
-    *ptr++ = 0;
-    
-    return description;
-}
-
-// Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
-// and some additional informative flags (must generate, is constant, etc).
-#define NodeIdMask           0xFFF
-#define NodeResultMask      0xF000
-#define NodeMustGenerate   0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE.
-#define NodeIsConstant     0x20000
-#define NodeIsJump         0x40000
-#define NodeIsBranch       0x80000
-#define NodeIsTerminal    0x100000
-#define NodeHasVarArgs    0x200000
-#define NodeClobbersWorld 0x400000
-#define NodeMightClobber  0x800000
-
-// These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result.
-#define NodeResultJS        0x1000
-#define NodeResultNumber    0x2000
-#define NodeResultInt32     0x3000
-#define NodeResultBoolean   0x4000
-#define NodeResultStorage   0x5000
+const char* arithNodeFlagsAsString(NodeFlags);
 
 // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
 #define FOR_EACH_DFG_OP(macro) \
@@ -304,11 +258,11 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
     macro(NewFunctionExpression, NodeResultJS) \
     \
     /* Block terminals. */\
-    macro(Jump, NodeMustGenerate | NodeIsTerminal | NodeIsJump) \
-    macro(Branch, NodeMustGenerate | NodeIsTerminal | NodeIsBranch) \
-    macro(Return, NodeMustGenerate | NodeIsTerminal) \
-    macro(Throw, NodeMustGenerate | NodeIsTerminal) \
-    macro(ThrowReferenceError, NodeMustGenerate | NodeIsTerminal) \
+    macro(Jump, NodeMustGenerate) \
+    macro(Branch, NodeMustGenerate) \
+    macro(Return, NodeMustGenerate) \
+    macro(Throw, NodeMustGenerate) \
+    macro(ThrowReferenceError, NodeMustGenerate) \
     \
     /* This is a pseudo-terminal. It means that execution should fall out of DFG at */\
     /* this point, but execution does continue in the basic block - just in a */\
@@ -317,20 +271,25 @@ static inline const char* arithNodeFlagsAsString(ArithNodeFlags flags)
 
 // This enum generates a monotonically increasing id for all Node types,
 // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
-enum NodeId {
-#define DFG_OP_ENUM(opcode, flags) opcode##_id,
+enum NodeType {
+#define DFG_OP_ENUM(opcode, flags) opcode,
     FOR_EACH_DFG_OP(DFG_OP_ENUM)
 #undef DFG_OP_ENUM
-    LastNodeId
+    LastNodeType
 };
 
-// Entries in this enum describe all Node types.
-// The enum value contains a monotonically increasing id, a result type, and additional flags.
-enum NodeType {
-#define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags),
+// Specifies the default flags for each node.
+inline NodeFlags defaultFlags(NodeType op)
+{
+    switch (op) {
+#define DFG_OP_ENUM(opcode, flags) case opcode: return flags;
     FOR_EACH_DFG_OP(DFG_OP_ENUM)
 #undef DFG_OP_ENUM
-};
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
 
 // This type used in passing an immediate argument to Node constructor;
 // distinguishes an immediate value (typically an index into a CodeBlock data structure - 
@@ -353,34 +312,32 @@ struct Node {
 
     // Construct a node with up to 3 children, no immediate value.
     Node(NodeType op, CodeOrigin codeOrigin, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
-        : op(op)
-        , codeOrigin(codeOrigin)
+        : codeOrigin(codeOrigin)
         , children(NodeReferenceBlob::Fixed, child1, child2, child3)
         , m_virtualRegister(InvalidVirtualRegister)
         , m_refCount(0)
         , m_prediction(PredictNone)
     {
-        ASSERT(!(op & NodeHasVarArgs));
-        ASSERT(!hasArithNodeFlags());
+        setOpAndDefaultFlags(op);
+        ASSERT(!(flags & NodeHasVarArgs));
     }
 
     // Construct a node with up to 3 children and an immediate value.
     Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
-        : op(op)
-        , codeOrigin(codeOrigin)
+        : codeOrigin(codeOrigin)
         , children(NodeReferenceBlob::Fixed, child1, child2, child3)
         , m_virtualRegister(InvalidVirtualRegister)
         , m_refCount(0)
         , m_opInfo(imm.m_value)
         , m_prediction(PredictNone)
     {
-        ASSERT(!(op & NodeHasVarArgs));
+        setOpAndDefaultFlags(op);
+        ASSERT(!(flags & NodeHasVarArgs));
     }
 
     // Construct a node with up to 3 children and two immediate values.
     Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
-        : op(op)
-        , codeOrigin(codeOrigin)
+        : codeOrigin(codeOrigin)
         , children(NodeReferenceBlob::Fixed, child1, child2, child3)
         , m_virtualRegister(InvalidVirtualRegister)
         , m_refCount(0)
@@ -388,13 +345,13 @@ struct Node {
         , m_opInfo2(safeCast<unsigned>(imm2.m_value))
         , m_prediction(PredictNone)
     {
-        ASSERT(!(op & NodeHasVarArgs));
+        setOpAndDefaultFlags(op);
+        ASSERT(!(flags & NodeHasVarArgs));
     }
     
     // Construct a node with a variable number of children and two immediate values.
     Node(VarArgTag, NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
-        : op(op)
-        , codeOrigin(codeOrigin)
+        : codeOrigin(codeOrigin)
         , children(NodeReferenceBlob::Variable, firstChild, numChildren)
         , m_virtualRegister(InvalidVirtualRegister)
         , m_refCount(0)
@@ -402,12 +359,19 @@ struct Node {
         , m_opInfo2(safeCast<unsigned>(imm2.m_value))
         , m_prediction(PredictNone)
     {
-        ASSERT(op & NodeHasVarArgs);
+        setOpAndDefaultFlags(op);
+        ASSERT(flags & NodeHasVarArgs);
+    }
+    
+    void setOpAndDefaultFlags(NodeType op)
+    {
+        this->op = op;
+        flags = defaultFlags(op);
     }
 
     bool mustGenerate()
     {
-        return op & NodeMustGenerate;
+        return flags & NodeMustGenerate;
     }
 
     bool isConstant()
@@ -546,44 +510,32 @@ struct Node {
         }
     }
     
-    ArithNodeFlags rawArithNodeFlags()
-    {
-        ASSERT(hasArithNodeFlags());
-        return m_opInfo;
-    }
-    
     // This corrects the arithmetic node flags, so that irrelevant bits are
     // ignored. In particular, anything other than ArithMul does not need
     // to know if it can speculate on negative zero.
-    ArithNodeFlags arithNodeFlags()
+    NodeFlags arithNodeFlags()
     {
-        ArithNodeFlags result = rawArithNodeFlags();
+        NodeFlags result = flags & NodeArithMask;
         if (op == ArithMul)
             return result;
         return result & ~NodeNeedsNegZero;
     }
     
-    ArithNodeFlags arithNodeFlagsForCompare()
+    void setArithNodeFlag(NodeFlags newFlags)
     {
-        if (hasArithNodeFlags())
-            return arithNodeFlags();
-        return 0;
-    }
-    
-    void setArithNodeFlag(ArithNodeFlags flags)
-    {
-        ASSERT(hasArithNodeFlags());
-        m_opInfo = flags;
+        ASSERT(!(newFlags & ~NodeArithMask));
+        
+        flags &= ~NodeArithMask;
+        flags |= newFlags;
     }
     
-    bool mergeArithNodeFlags(ArithNodeFlags flags)
+    bool mergeArithNodeFlags(NodeFlags newFlags)
     {
-        if (!hasArithNodeFlags())
-            return false;
-        ArithNodeFlags newFlags = m_opInfo | flags;
-        if (newFlags == m_opInfo)
+        ASSERT(!(newFlags & ~NodeArithMask));
+        newFlags = flags | newFlags;
+        if (newFlags == flags)
             return false;
-        m_opInfo = newFlags;
+        flags = newFlags;
         return true;
     }
     
@@ -639,42 +591,51 @@ struct Node {
 
     bool hasResult()
     {
-        return op & NodeResultMask;
+        return flags & NodeResultMask;
     }
 
     bool hasInt32Result()
     {
-        return (op & NodeResultMask) == NodeResultInt32;
+        return (flags & NodeResultMask) == NodeResultInt32;
     }
     
     bool hasNumberResult()
     {
-        return (op & NodeResultMask) == NodeResultNumber;
+        return (flags & NodeResultMask) == NodeResultNumber;
     }
     
     bool hasJSResult()
     {
-        return (op & NodeResultMask) == NodeResultJS;
+        return (flags & NodeResultMask) == NodeResultJS;
     }
     
     bool hasBooleanResult()
     {
-        return (op & NodeResultMask) == NodeResultBoolean;
+        return (flags & NodeResultMask) == NodeResultBoolean;
     }
 
     bool isJump()
     {
-        return op & NodeIsJump;
+        return op == Jump;
     }
 
     bool isBranch()
     {
-        return op & NodeIsBranch;
+        return op == Branch;
     }
 
     bool isTerminal()
     {
-        return op & NodeIsTerminal;
+        switch (op) {
+        case Jump:
+        case Branch:
+        case Return:
+        case Throw:
+        case ThrowReferenceError:
+            return true;
+        default:
+            return false;
+        }
     }
 
     unsigned takenBytecodeOffsetDuringParsing()
@@ -871,7 +832,7 @@ struct Node {
     
     NodeUse child1()
     {
-        ASSERT(!(op & NodeHasVarArgs));
+        ASSERT(!(flags & NodeHasVarArgs));
         return children.child1();
     }
     
@@ -885,25 +846,25 @@ struct Node {
 
     NodeUse child2()
     {
-        ASSERT(!(op & NodeHasVarArgs));
+        ASSERT(!(flags & NodeHasVarArgs));
         return children.child2();
     }
 
     NodeUse child3()
     {
-        ASSERT(!(op & NodeHasVarArgs));
+        ASSERT(!(flags & NodeHasVarArgs));
         return children.child3();
     }
     
     unsigned firstChild()
     {
-        ASSERT(op & NodeHasVarArgs);
+        ASSERT(flags & NodeHasVarArgs);
         return children.firstChild();
     }
     
     unsigned numChildren()
     {
-        ASSERT(op & NodeHasVarArgs);
+        ASSERT(flags & NodeHasVarArgs);
         return children.numChildren();
     }
     
@@ -1069,8 +1030,8 @@ struct Node {
         fprintf(out, ", @%u", child3().index());
     }
     
-    // This enum value describes the type of the node.
-    NodeType op;
+    uint16_t op; // real type is NodeType
+    NodeFlags flags;
     // Used to look up exception handling information (currently implemented as a bytecode index).
     CodeOrigin codeOrigin;
     // References to up to 3 children, or links to a variable length set of children.
index 74f04cf..98bdaac 100644 (file)
@@ -105,7 +105,7 @@ private:
         if (!node.shouldGenerate())
             return;
         
-        NodeType op = node.op;
+        NodeType op = static_cast<NodeType>(node.op);
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         dataLog("   %s @%u: ", Graph::opName(op), m_compileIndex);
@@ -468,6 +468,10 @@ private:
         case InlineStart:
         case Nop:
             break;
+            
+        case LastNodeType:
+            ASSERT_NOT_REACHED();
+            break;
 #else
         default:
             break;
@@ -516,7 +520,7 @@ private:
     
     void vote(Node& node, VariableAccessData::Ballot ballot)
     {
-        if (node.op & NodeHasVarArgs) {
+        if (node.flags & NodeHasVarArgs) {
             for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
                 vote(m_graph.m_varArgChildren[childIdx], ballot);
             return;
@@ -624,7 +628,7 @@ private:
         if (!node.shouldGenerate())
             return;
         
-        NodeType op = node.op;
+        NodeType op = static_cast<NodeType>(node.op);
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         dataLog("   %s @%u: ", Graph::opName(op), m_compileIndex);
@@ -680,13 +684,16 @@ private:
                 node.op = GetFloat64ArrayLength;
             else
                 ASSERT_NOT_REACHED();
-            m_graph.deref(m_compileIndex); // No longer MustGenerate
+            // No longer MustGenerate
+            ASSERT(node.flags & NodeMustGenerate);
+            node.flags &= ~NodeMustGenerate;
+            m_graph.deref(m_compileIndex);
             break;
         }
         case GetIndexedPropertyStorage: {
             PredictedType basePrediction = m_graph[node.child2()].prediction();
             if (!(basePrediction & PredictInt32) && basePrediction) {
-                node.op = Nop;
+                node.setOpAndDefaultFlags(Nop);
                 m_graph.clearAndDerefChild1(node);
                 m_graph.clearAndDerefChild2(node);
                 m_graph.clearAndDerefChild3(node);
index 912b3e8..140de18 100644 (file)
@@ -58,14 +58,27 @@ public:
         }
     }
 
-#if DFG_ENABLE(CONSISTENCY_CHECK)
     ~ScoreBoard()
     {
-        // For every entry in the used list the use count of the virtual register should be zero.
-        for (size_t i = 0; i < m_free.size(); ++i)
-            ASSERT(!m_used[i] || m_used[i] == max());
+        assertClear();
     }
+    
+    void assertClear()
+    {
+#if !ASSERT_DISABLED
+        // For every entry in the used list the use count of the virtual register should be zero, or max, due to it being a preserved local.
+        for (size_t i = 0; i < m_used.size(); ++i)
+            ASSERT(!m_used[i] || m_used[i] == max());
+        // For every entry in the free list, the use count should be zero.
+        for (size_t i = 0; i < m_free.size(); ++i)
+            ASSERT(!m_used[m_free[i]]);
+        // There must not be duplicates in the free list.
+        for (size_t i = 0; i < m_free.size(); ++i) {
+            for (size_t j = i + 1; j < m_free.size(); ++j)
+                ASSERT(m_free[i] != m_free[j]);
+        }
 #endif
+    }
 
     VirtualRegister allocate()
     {
@@ -99,6 +112,9 @@ public:
         uint32_t index = node.virtualRegister();
         ASSERT(m_used[index] != max());
         if (node.refCount() == ++m_used[index]) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLog(" Freeing virtual register %u.", index);
+#endif
             // If the use count in the scoreboard reaches the use count for the node,
             // then this was its last use; the virtual register is now free.
             // Clear the use count & add to the free list.
index 22a6355..7bcb445 100644 (file)
@@ -83,7 +83,7 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
 
 void SpeculativeJIT::useChildren(Node& node)
 {
-    if (node.op & NodeHasVarArgs) {
+    if (node.flags & NodeHasVarArgs) {
         for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
             use(m_jit.graph().m_varArgChildren[childIdx]);
     } else {
index ad42938..b681422 100644 (file)
@@ -1640,7 +1640,7 @@ void SpeculativeJIT::emitBranch(Node& node)
 
 void SpeculativeJIT::compile(Node& node)
 {
-    NodeType op = node.op;
+    NodeType op = static_cast<NodeType>(node.op);
 
     switch (op) {
     case JSConstant:
@@ -3578,6 +3578,7 @@ void SpeculativeJIT::compile(Node& node)
 
     case InlineStart:
     case Nop:
+    case LastNodeType:
         ASSERT_NOT_REACHED();
         break;
     }
index a9b7fca..1597b16 100644 (file)
@@ -1744,7 +1744,7 @@ void SpeculativeJIT::emitBranch(Node& node)
 
 void SpeculativeJIT::compile(Node& node)
 {
-    NodeType op = node.op;
+    NodeType op = static_cast<NodeType>(node.op);
 
     switch (op) {
     case JSConstant:
@@ -3552,6 +3552,10 @@ void SpeculativeJIT::compile(Node& node)
     case Nop:
         ASSERT_NOT_REACHED();
         break;
+        
+    case LastNodeType:
+        ASSERT_NOT_REACHED();
+        break;
     }
 
     if (!m_compileOkay)
index bc7e3f4..2550036 100644 (file)
@@ -48,38 +48,62 @@ public:
         dataLog("\n");
 #endif
         ScoreBoard scoreBoard(m_graph, m_graph.m_preservedVars);
-        for (size_t i = 0; i < m_graph.size(); ++i) {
-            Node& node = m_graph[i];
+        scoreBoard.assertClear();
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        bool needsNewLine = false;
+#endif
+        for (size_t blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            for (size_t indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+                NodeIndex nodeIndex = block->at(indexInBlock);
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+                if (needsNewLine)
+                    dataLog("\n");
+                dataLog("   @%u:", nodeIndex);
+                needsNewLine = true;
+#endif
+                Node& node = m_graph[nodeIndex];
         
-            if (!node.shouldGenerate() || node.op == Phi || node.op == Flush)
-                continue;
+                if (!node.shouldGenerate() || node.op == Phi || node.op == Flush)
+                    continue;
             
-            // GetLocal nodes are effectively phi nodes in the graph, referencing
-            // results from prior blocks.
-            if (node.op != GetLocal) {
-                // First, call use on all of the current node's children, then
-                // allocate a VirtualRegister for this node. We do so in this
-                // order so that if a child is on its last use, and a
-                // VirtualRegister is freed, then it may be reused for node.
-                if (node.op & NodeHasVarArgs) {
-                    for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
-                        scoreBoard.use(m_graph.m_varArgChildren[childIdx]);
-                } else {
-                    scoreBoard.use(node.child1());
-                    scoreBoard.use(node.child2());
-                    scoreBoard.use(node.child3());
+                // GetLocal nodes are effectively phi nodes in the graph, referencing
+                // results from prior blocks.
+                if (node.op != GetLocal) {
+                    // First, call use on all of the current node's children, then
+                    // allocate a VirtualRegister for this node. We do so in this
+                    // order so that if a child is on its last use, and a
+                    // VirtualRegister is freed, then it may be reused for node.
+                    if (node.flags & NodeHasVarArgs) {
+                        for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
+                            scoreBoard.use(m_graph.m_varArgChildren[childIdx]);
+                    } else {
+                        scoreBoard.use(node.child1());
+                        scoreBoard.use(node.child2());
+                        scoreBoard.use(node.child3());
+                    }
                 }
-            }
 
-            if (!node.hasResult())
-                continue;
+                if (!node.hasResult())
+                    continue;
 
-            node.setVirtualRegister(scoreBoard.allocate());
-            // 'mustGenerate' nodes have their useCount artificially elevated,
-            // call use now to account for this.
-            if (node.mustGenerate())
-                scoreBoard.use(i);
+                VirtualRegister virtualRegister = scoreBoard.allocate();
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+                dataLog(" Assigning virtual register %u to node %u.",
+                        virtualRegister, nodeIndex);
+#endif
+                node.setVirtualRegister(virtualRegister);
+                // 'mustGenerate' nodes have their useCount artificially elevated,
+                // call use now to account for this.
+                if (node.mustGenerate())
+                    scoreBoard.use(nodeIndex);
+            }
+            scoreBoard.assertClear();
         }
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        if (needsNewLine)
+            dataLog("\n");
+#endif
 
         // 'm_numCalleeRegisters' is the number of locals and temporaries allocated
         // for the function (and checked for on entry). Since we perform a new and