Inserting a node into the DFG graph should not require five lines of code
https://bugs.webkit.org/show_bug.cgi?id=107381

Reviewed by Sam Weinig.
        
This adds fairly comprehensive support for inserting a node into a DFG graph in one
method call. A common example of this is:
        
m_insertionSet.insertNode(indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit, codeOrigin);
        
The arguments to insert() specify what reference counting you need to have happen
(RefChildren => recursively refs all children, RefNode => non-recursively refs the node
that was created), the prediction to set (SpecNone is a common default), followed by
the arguments to the Node() constructor. InsertionSet::insertNode() and similar methods
(Graph::addNode() and BasicBlock::appendNode()) all use a common variadic template
function macro from DFGVariadicFunction.h. Also, all of these methods will automatically
non-recursively ref() the node being created if the flags say NodeMustGenerate.
        
In all, this new mechanism retains the flexibility of the old approach (you get to
manage ref counts yourself, albeit in less code) while ensuring that most code that adds
nodes to the graph now needs less code to do it.
        
In the future, we should revisit the reference counting methodology in the DFG: we could
do like most compilers and get rid of it entirely, or we could make it automatic. This
patch doesn't attempt to make any such major changes, and only seeks to simplify the
technique we were already using (manual ref counting).

* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/Operands.h:
(JSC::dumpOperands):
* dfg/DFGAdjacencyList.h:
(AdjacencyList):
(JSC::DFG::AdjacencyList::kind):
* dfg/DFGArgumentsSimplificationPhase.cpp:
(JSC::DFG::ArgumentsSimplificationPhase::run):
* dfg/DFGBasicBlock.h:
(DFG):
(BasicBlock):
* dfg/DFGBasicBlockInlines.h: Added.
(DFG):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
(JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
* dfg/DFGCommon.h:
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::ConstantFoldingPhase):
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
(JSC::DFG::ConstantFoldingPhase::paintUnreachableCode):
(ConstantFoldingPhase):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::FixupPhase):
(JSC::DFG::FixupPhase::fixupBlock):
(JSC::DFG::FixupPhase::fixupNode):
(FixupPhase):
(JSC::DFG::FixupPhase::checkArray):
(JSC::DFG::FixupPhase::blessArrayOperation):
(JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::ref):
(Graph):
* dfg/DFGInsertionSet.h:
(DFG):
(JSC::DFG::Insertion::Insertion):
(JSC::DFG::Insertion::element):
(Insertion):
(JSC::DFG::InsertionSet::InsertionSet):
(JSC::DFG::InsertionSet::insert):
(InsertionSet):
(JSC::DFG::InsertionSet::execute):
* dfg/DFGNode.h:
(JSC::DFG::Node::Node):
(Node):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):
* dfg/DFGVariadicFunction.h: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@140275 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index a22f402..7bb4344 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,83 @@
+2013-01-20  Filip Pizlo  <fpizlo@apple.com>
+
+        Inserting a node into the DFG graph should not require five lines of code
+        https://bugs.webkit.org/show_bug.cgi?id=107381
+
+        Reviewed by Sam Weinig.
+        
+        This adds fairly comprehensive support for inserting a node into a DFG graph in one
+        method call. A common example of this is:
+        
+        m_insertionSet.insertNode(indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit, codeOrigin);
+        
+        The arguments to insert() specify what reference counting you need to have happen
+        (RefChildren => recursively refs all children, RefNode => non-recursively refs the node
+        that was created), the prediction to set (SpecNone is a common default), followed by
+        the arguments to the Node() constructor. InsertionSet::insertNode() and similar methods
+        (Graph::addNode() and BasicBlock::appendNode()) all use a common variadic template
+        function macro from DFGVariadicFunction.h. Also, all of these methods will automatically
+        non-recursively ref() the node being created if the flags say NodeMustGenerate.
+        
+        In all, this new mechanism retains the flexibility of the old approach (you get to
+        manage ref counts yourself, albeit in less code) while ensuring that most code that adds
+        nodes to the graph now needs less code to do it.
+        
+        In the future, we should revisit the reference counting methodology in the DFG: we could
+        do like most compilers and get rid of it entirely, or we could make it automatic. This
+        patch doesn't attempt to make any such major changes, and only seeks to simplify the
+        technique we were already using (manual ref counting).
+
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/Operands.h:
+        (JSC::dumpOperands):
+        * dfg/DFGAdjacencyList.h:
+        (AdjacencyList):
+        (JSC::DFG::AdjacencyList::kind):
+        * dfg/DFGArgumentsSimplificationPhase.cpp:
+        (JSC::DFG::ArgumentsSimplificationPhase::run):
+        * dfg/DFGBasicBlock.h:
+        (DFG):
+        (BasicBlock):
+        * dfg/DFGBasicBlockInlines.h: Added.
+        (DFG):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::run):
+        (JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
+        * dfg/DFGCommon.h:
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::ConstantFoldingPhase):
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
+        (JSC::DFG::ConstantFoldingPhase::paintUnreachableCode):
+        (ConstantFoldingPhase):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::FixupPhase):
+        (JSC::DFG::FixupPhase::fixupBlock):
+        (JSC::DFG::FixupPhase::fixupNode):
+        (FixupPhase):
+        (JSC::DFG::FixupPhase::checkArray):
+        (JSC::DFG::FixupPhase::blessArrayOperation):
+        (JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::ref):
+        (Graph):
+        * dfg/DFGInsertionSet.h:
+        (DFG):
+        (JSC::DFG::Insertion::Insertion):
+        (JSC::DFG::Insertion::element):
+        (Insertion):
+        (JSC::DFG::InsertionSet::InsertionSet):
+        (JSC::DFG::InsertionSet::insert):
+        (InsertionSet):
+        (JSC::DFG::InsertionSet::execute):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::Node):
+        (Node):
+        * dfg/DFGStructureCheckHoistingPhase.cpp:
+        (JSC::DFG::StructureCheckHoistingPhase::run):
+        * dfg/DFGVariadicFunction.h: Added.
+
 2013-01-19  Geoffrey Garen  <ggaren@apple.com>
 
         Track inheritance structures in a side table, instead of using a private
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 4cf237d..fc507f3 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -176,6 +176,7 @@
 	Source/JavaScriptCore/dfg/DFGAssemblyHelpers.cpp \
 	Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h \
 	Source/JavaScriptCore/dfg/DFGBasicBlock.h \
+	Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h \
 	Source/JavaScriptCore/dfg/DFGBranchDirection.h \
 	Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp \
 	Source/JavaScriptCore/dfg/DFGByteCodeParser.h \
@@ -264,6 +265,7 @@
 	Source/JavaScriptCore/dfg/DFGVariableAccessData.h \
 	Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp \
 	Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h \
+	Source/JavaScriptCore/dfg/DFGVariadicFunction.h \
 	Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp \
 	Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.h \
 	Source/JavaScriptCore/disassembler/Disassembler.cpp \
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 567df16..0464505 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -1037,6 +1037,7 @@
 		0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayAllocationProfile.cpp; sourceTree = "<group>"; };
 		0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; };
 		0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = "<group>"; };
+		0F85A31E16AB76AE0077571E /* DFGVariadicFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariadicFunction.h; path = dfg/DFGVariadicFunction.h; sourceTree = "<group>"; };
 		0F8F943A1667631100D61971 /* CodeSpecializationKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSpecializationKind.cpp; sourceTree = "<group>"; };
 		0F8F943D1667632D00D61971 /* CodeBlockHash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeBlockHash.cpp; sourceTree = "<group>"; };
 		0F8F943E1667632D00D61971 /* CodeBlockHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockHash.h; sourceTree = "<group>"; };
@@ -1110,6 +1111,7 @@
 		0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlotVisitorInlines.h; sourceTree = "<group>"; };
 		0FD3C82014115CF800FD81CB /* DFGDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDriver.cpp; path = dfg/DFGDriver.cpp; sourceTree = "<group>"; };
 		0FD3C82214115D0E00FD81CB /* DFGDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDriver.h; path = dfg/DFGDriver.h; sourceTree = "<group>"; };
+		0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBasicBlockInlines.h; path = dfg/DFGBasicBlockInlines.h; sourceTree = "<group>"; };
 		0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDominators.cpp; path = dfg/DFGDominators.cpp; sourceTree = "<group>"; };
 		0FD81AD0154FB4EB00983E72 /* DFGDominators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDominators.h; path = dfg/DFGDominators.h; sourceTree = "<group>"; };
 		0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCapabilities.cpp; path = dfg/DFGCapabilities.cpp; sourceTree = "<group>"; };
@@ -2549,6 +2551,7 @@
 				0FC0976B1468AB4A00CF2442 /* DFGAssemblyHelpers.cpp */,
 				0FC0976C1468AB4A00CF2442 /* DFGAssemblyHelpers.h */,
 				0F620170143FCD2F0068B77C /* DFGBasicBlock.h */,
+				0FD5652216AB780A00197653 /* DFGBasicBlockInlines.h */,
 				0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */,
 				86EC9DB41328DF82002B2AD7 /* DFGByteCodeParser.cpp */,
 				86EC9DB51328DF82002B2AD7 /* DFGByteCodeParser.h */,
@@ -2636,6 +2639,7 @@
 				0F2BDC411522801700CD8910 /* DFGVariableEvent.h */,
 				0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */,
 				0F2BDC431522801700CD8910 /* DFGVariableEventStream.h */,
+				0F85A31E16AB76AE0077571E /* DFGVariadicFunction.h */,
 				0FFFC95314EF909500C72532 /* DFGVirtualRegisterAllocationPhase.cpp */,
 				0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */,
 			);
diff --git a/Source/JavaScriptCore/bytecode/Operands.h b/Source/JavaScriptCore/bytecode/Operands.h
index 6b44e51..e7cb1f2 100644
--- a/Source/JavaScriptCore/bytecode/Operands.h
+++ b/Source/JavaScriptCore/bytecode/Operands.h
@@ -193,7 +193,7 @@
 void dumpOperands(const Operands<T, Traits>& operands, PrintStream& out)
 {
     for (size_t argument = operands.numberOfArguments(); argument--;) {
-        if (argument)
+        if (argument != operands.numberOfArguments() - 1)
             out.printf(" ");
         out.print("arg", argument, ":");
         Traits::dump(operands.argument(argument), out);
diff --git a/Source/JavaScriptCore/dfg/DFGAdjacencyList.h b/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
index 921a67a..2bf762f 100644
--- a/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
+++ b/Source/JavaScriptCore/dfg/DFGAdjacencyList.h
@@ -162,6 +162,9 @@
         m_words[1].m_encodedWord = numChildren;
     }
     
+#if !ASSERT_DISABLED
+    Kind kind() const { return m_kind; }
+#endif
 private:
     Edge m_words[Size];
 #if !ASSERT_DISABLED
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 7d635ac..4a88ffb 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -407,7 +407,7 @@
         }
 #endif
         
-        InsertionSet<NodeIndex> insertionSet;
+        InsertionSet insertionSet(m_graph);
         
         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
@@ -532,11 +532,9 @@
                     
                     // We know exactly what this will return. But only after we have checked
                     // that nobody has escaped our arguments.
-                    Node check(CheckArgumentsNotCreated, codeOrigin);
-                    check.ref();
-                    NodeIndex checkIndex = m_graph.size();
-                    m_graph.append(check);
-                    insertionSet.append(indexInBlock, checkIndex);
+                    insertionSet.insertNode(
+                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, 
+                        CheckArgumentsNotCreated, codeOrigin);
                     
                     m_graph.convertToConstant(
                         nodeIndex, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
@@ -576,24 +574,20 @@
                     // has run - therefore it makes little sense to link the GetLocal operation
                     // into the VariableAccessData and Phi graphs.
 
-                    Node check(CheckArgumentsNotCreated, node.codeOrigin);
-                    check.ref();
-                    
-                    Node phantom(Phantom, node.codeOrigin);
-                    phantom.ref();
-                    phantom.children = node.children;
+                    CodeOrigin codeOrigin = node.codeOrigin;
+                    AdjacencyList children = node.children;
                     
                     node.convertToGetLocalUnlinked(
                         static_cast<VirtualRegister>(
                             node.codeOrigin.inlineCallFrame->stackOffset +
                             m_graph.baselineCodeBlockFor(node.codeOrigin)->argumentIndexAfterCapture(index)));
 
-                    NodeIndex checkNodeIndex = m_graph.size();
-                    m_graph.append(check);
-                    insertionSet.append(indexInBlock, checkNodeIndex);
-                    NodeIndex phantomNodeIndex = m_graph.size();
-                    m_graph.append(phantom);
-                    insertionSet.append(indexInBlock, phantomNodeIndex);
+                    insertionSet.insertNode(
+                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, CheckArgumentsNotCreated,
+                        codeOrigin);
+                    insertionSet.insertNode(
+                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, Phantom, codeOrigin,
+                        children);
                     
                     changed = true;
                     break;
@@ -614,7 +608,7 @@
                     break;
                 }
             }
-            insertionSet.execute(*block);
+            insertionSet.execute(block);
         }
         
         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
@@ -634,19 +628,16 @@
                 if (m_createsArguments.contains(nodePtr->codeOrigin.inlineCallFrame))
                     continue;
                 if (nodePtr->shouldGenerate()) {
-                    Node phantom(Phantom, nodePtr->codeOrigin);
-                    phantom.children = nodePtr->children;
-                    phantom.ref();
-                    NodeIndex phantomNodeIndex = m_graph.size();
-                    m_graph.append(phantom);
-                    insertionSet.append(indexInBlock, phantomNodeIndex);
+                    insertionSet.insertNode(
+                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, Phantom,
+                        nodePtr->codeOrigin, nodePtr->children);
                     nodePtr = &m_graph[nodeIndex];
                 }
                 nodePtr->setOpAndDefaultFlags(PhantomArguments);
                 nodePtr->children.reset();
                 changed = true;
             }
-            insertionSet.execute(*block);
+            insertionSet.execute(block);
         }
         
         if (changed)
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
index 6f348f2e..e1e7c2e 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -31,12 +31,15 @@
 #include "DFGAbstractValue.h"
 #include "DFGBranchDirection.h"
 #include "DFGNode.h"
+#include "DFGVariadicFunction.h"
 #include "Operands.h"
 #include <wtf/OwnPtr.h>
 #include <wtf/Vector.h>
 
 namespace JSC { namespace DFG {
 
+class Graph;
+
 typedef Vector <BlockIndex, 2> PredecessorList;
 
 struct BasicBlock : Vector<NodeIndex, 8> {
@@ -97,7 +100,12 @@
         }
         return false;
     }
-
+    
+#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
+    templatePre typeParams templatePost NodeIndex appendNode(Graph&, RefChildrenMode, RefNodeMode, SpeculatedType valueParamsComma valueParams);
+    DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
+#undef DFG_DEFINE_APPEND_NODE
+    
     // This value is used internally for block linking and OSR entry. It is mostly meaningless
     // for other purposes due to inlining.
     unsigned bytecodeBegin;
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h b/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h
new file mode 100644
index 0000000..d37ea01
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h
@@ -0,0 +1,51 @@
+/*
+ * 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 DFGBasicBlockInlines_h
+#define DFGBasicBlockInlines_h
+
+#include "DFGBasicBlock.h"
+#include "DFGGraph.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+#define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
+    templatePre typeParams templatePost NodeIndex BasicBlock::appendNode(Graph& graph, RefChildrenMode refChildrenMode, RefNodeMode refNodeMode, SpeculatedType type valueParamsComma valueParams) \
+    { \
+        NodeIndex result = graph.addNode(refChildrenMode, refNodeMode, type valueParamsComma valueArgs); \
+        append(result); \
+        return result; \
+    }
+    DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
+#undef DFG_DEFINE_APPEND_NODE
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGBasicBlockInlines_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index 1a52ce4..177fb22 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -29,7 +29,7 @@
 #if ENABLE(DFG_JIT)
 
 #include "DFGAbstractState.h"
-#include "DFGBasicBlock.h"
+#include "DFGBasicBlockInlines.h"
 #include "DFGGraph.h"
 #include "DFGInsertionSet.h"
 #include "DFGPhase.h"
@@ -136,11 +136,9 @@
                         
                             jettisonBlock(blockIndex, notTakenBlockIndex, boundaryCodeOrigin);
                         
-                            NodeIndex jumpNodeIndex = m_graph.size();
-                            Node jump(Jump, boundaryCodeOrigin, OpInfo(takenBlockIndex));
-                            jump.ref();
-                            m_graph.append(jump);
-                            block->append(jumpNodeIndex);
+                            block->appendNode(
+                                m_graph, DontRefChildren, DontRefNode, SpecNone, Jump,
+                                boundaryCodeOrigin, OpInfo(takenBlockIndex));
                         }
                         innerChanged = outerChanged = true;
                         break;
@@ -169,11 +167,9 @@
                             branch.setOpAndDefaultFlags(Phantom);
                             ASSERT(branch.refCount() == 1);
                             
-                            Node jump(Jump, branch.codeOrigin, OpInfo(targetBlockIndex));
-                            jump.ref();
-                            NodeIndex jumpNodeIndex = m_graph.size();
-                            m_graph.append(jump);
-                            block->append(jumpNodeIndex);
+                            block->appendNode(
+                                m_graph, DontRefChildren, DontRefNode, SpecNone, Jump,
+                                branch.codeOrigin, OpInfo(targetBlockIndex));
                         }
                         innerChanged = outerChanged = true;
                         break;
@@ -275,11 +271,8 @@
         if (!node.shouldGenerate())
             return;
         ASSERT(m_graph[nodeIndex].op() != SetLocal);
-        NodeIndex phantomNodeIndex = m_graph.size();
-        Node phantom(Phantom, codeOrigin, nodeIndex);
-        m_graph.append(phantom);
-        m_graph.ref(phantomNodeIndex);
-        block->append(phantomNodeIndex);
+        block->appendNode(
+            m_graph, RefChildren, DontRefNode, SpecNone, Phantom, codeOrigin, nodeIndex);
     }
     
     void fixPossibleGetLocal(BasicBlock* block, Edge& edge, bool changeRef)
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index ee4d470..f8bc2c5 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -105,6 +105,23 @@
     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.
+// - The place where you're inserting a reference to the node you're creating
+//   will not also do RefChildren.
+enum RefChildrenMode {
+    RefChildren,
+    DontRefChildren
+};
+
+// Use RefNode if you know that the node will be used from another node, and you
+// will not already be ref'ing the node to account for that use.
+enum RefNodeMode {
+    RefNode,
+    DontRefNode
+};
+
 inline const char* useKindToString(UseKind useKind)
 {
     switch (useKind) {
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index baeaafd..940643e 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -44,6 +44,7 @@
     ConstantFoldingPhase(Graph& graph)
         : Phase(graph, "constant folding")
         , m_state(graph)
+        , m_insertionSet(graph)
     {
     }
     
@@ -179,12 +180,9 @@
                 
                 if (needsWatchpoint) {
                     ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
-                    m_graph[child].ref();
-                    Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
-                    watchpoint.ref();
-                    NodeIndex watchpointIndex = m_graph.size();
-                    m_graph.append(watchpoint);
-                    m_insertionSet.append(indexInBlock, watchpointIndex);
+                    m_insertionSet.insertNode(
+                        indexInBlock, RefChildren, DontRefNode, SpecNone,
+                        StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
                 }
                 
                 NodeIndex propertyStorageIndex;
@@ -193,11 +191,9 @@
                 if (isInlineOffset(status.offset()))
                     propertyStorageIndex = child;
                 else {
-                    Node getButterfly(GetButterfly, codeOrigin, child);
-                    getButterfly.ref();
-                    propertyStorageIndex = m_graph.size();
-                    m_graph.append(getButterfly);
-                    m_insertionSet.append(indexInBlock, propertyStorageIndex);
+                    propertyStorageIndex = m_insertionSet.insertNode(
+                        indexInBlock, DontRefChildren, RefNode, SpecNone, GetButterfly, codeOrigin,
+                        child);
                 }
                 
                 m_graph[nodeIndex].convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex);
@@ -241,12 +237,9 @@
                 
                 if (needsWatchpoint) {
                     ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
-                    m_graph[child].ref();
-                    Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
-                    watchpoint.ref();
-                    NodeIndex watchpointIndex = m_graph.size();
-                    m_graph.append(watchpoint);
-                    m_insertionSet.append(indexInBlock, watchpointIndex);
+                    m_insertionSet.insertNode(
+                        indexInBlock, RefChildren, DontRefNode, SpecNone,
+                        StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), child);
                 }
                 
                 StructureTransitionData* transitionData = 0;
@@ -274,51 +267,36 @@
 
                 NodeIndex propertyStorageIndex;
                 
-                m_graph[child].ref();
-                if (isInlineOffset(status.offset()))
+                if (isInlineOffset(status.offset())) {
+                    m_graph[child].ref(); // The child will be used as the property index, so ref it to reflect the double use.
                     propertyStorageIndex = child;
-                else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
-                    Node getButterfly(GetButterfly, codeOrigin, child);
-                    getButterfly.ref();
-                    propertyStorageIndex = m_graph.size();
-                    m_graph.append(getButterfly);
-                    m_insertionSet.append(indexInBlock, propertyStorageIndex);
+                } else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
+                    propertyStorageIndex = m_insertionSet.insertNode(
+                        indexInBlock, RefChildren, RefNode, SpecNone, GetButterfly, codeOrigin, child);
                 } else if (!structure->outOfLineCapacity()) {
                     ASSERT(status.newStructure()->outOfLineCapacity());
                     ASSERT(!isInlineOffset(status.offset()));
-                    Node allocateStorage(AllocatePropertyStorage, codeOrigin, OpInfo(transitionData), child);
-                    allocateStorage.ref(); // Once for the use.
-                    allocateStorage.ref(); // Twice because it's must-generate.
-                    propertyStorageIndex = m_graph.size();
-                    m_graph.append(allocateStorage);
-                    m_insertionSet.append(indexInBlock, propertyStorageIndex);
+                    propertyStorageIndex = m_insertionSet.insertNode(
+                        indexInBlock, RefChildren, RefNode, SpecNone, AllocatePropertyStorage,
+                        codeOrigin, OpInfo(transitionData), child);
                 } else {
                     ASSERT(structure->outOfLineCapacity());
                     ASSERT(status.newStructure()->outOfLineCapacity() > structure->outOfLineCapacity());
                     ASSERT(!isInlineOffset(status.offset()));
                     
-                    Node getButterfly(GetButterfly, codeOrigin, child);
-                    getButterfly.ref();
-                    NodeIndex getButterflyIndex = m_graph.size();
-                    m_graph.append(getButterfly);
-                    m_insertionSet.append(indexInBlock, getButterflyIndex);
-                    
-                    m_graph[child].ref();
-                    Node reallocateStorage(ReallocatePropertyStorage, codeOrigin, OpInfo(transitionData), child, getButterflyIndex);
-                    reallocateStorage.ref(); // Once for the use.
-                    reallocateStorage.ref(); // Twice because it's must-generate.
-                    propertyStorageIndex = m_graph.size();
-                    m_graph.append(reallocateStorage);
-                    m_insertionSet.append(indexInBlock, propertyStorageIndex);
+                    propertyStorageIndex = m_insertionSet.insertNode(
+                        indexInBlock, RefChildren, RefNode, SpecNone, ReallocatePropertyStorage,
+                        codeOrigin, OpInfo(transitionData),
+                        child,
+                        m_insertionSet.insertNode(
+                            indexInBlock, DontRefChildren, DontRefNode, SpecNone, GetButterfly,
+                            codeOrigin, child));
                 }
                 
                 if (status.isSimpleTransition()) {
-                    m_graph[child].ref();
-                    Node putStructure(PutStructure, codeOrigin, OpInfo(transitionData), child);
-                    putStructure.ref();
-                    NodeIndex putStructureIndex = m_graph.size();
-                    m_graph.append(putStructure);
-                    m_insertionSet.append(indexInBlock, putStructureIndex);
+                    m_insertionSet.insertNode(
+                        indexInBlock, RefChildren, DontRefNode, SpecNone, PutStructure, codeOrigin,
+                        OpInfo(transitionData), child);
                 }
                 
                 m_graph[nodeIndex].convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorageIndex);
@@ -346,8 +324,6 @@
             if (!value)
                 continue;
                 
-            Node phantom(Phantom, node.codeOrigin);
-                
             if (node.op() == GetLocal) {
                 NodeIndex previousLocalAccess = NoNode;
                 if (block->variablesAtHead.operand(node.local()) == nodeIndex
@@ -402,46 +378,38 @@
                         || node.variableAccessData()->isCaptured());
                 }
             }
-                
-            phantom.children = node.children;
-            phantom.ref();
             
+            CodeOrigin codeOrigin = node.codeOrigin;
+            AdjacencyList children = node.children;
+                
             m_graph.convertToConstant(nodeIndex, value);
-            NodeIndex phantomNodeIndex = m_graph.size();
-            m_graph.append(phantom);
-            m_insertionSet.append(indexInBlock, phantomNodeIndex);
+            m_insertionSet.insertNode(
+                indexInBlock, DontRefChildren, DontRefNode, SpecNone, Phantom, codeOrigin, children);
                 
             changed = true;
         }
         m_state.reset();
-        m_insertionSet.execute(*block);
+        m_insertionSet.execute(block);
         
         return changed;
     }
     
     void addStructureTransitionCheck(CodeOrigin codeOrigin, unsigned indexInBlock, JSCell* cell)
     {
-        Node weakConstant(WeakJSConstant, codeOrigin, OpInfo(cell));
-        weakConstant.ref();
-        weakConstant.predict(speculationFromValue(cell));
-        NodeIndex weakConstantIndex = m_graph.size();
-        m_graph.append(weakConstant);
-        m_insertionSet.append(indexInBlock, weakConstantIndex);
+        NodeIndex weakConstantIndex = m_insertionSet.insertNode(
+            indexInBlock, DontRefChildren, DontRefNode, speculationFromValue(cell),
+            WeakJSConstant, codeOrigin, OpInfo(cell));
         
         if (cell->structure()->transitionWatchpointSetIsStillValid()) {
-            Node watchpoint(StructureTransitionWatchpoint, codeOrigin, OpInfo(cell->structure()), weakConstantIndex);
-            watchpoint.ref();
-            NodeIndex watchpointIndex = m_graph.size();
-            m_graph.append(watchpoint);
-            m_insertionSet.append(indexInBlock, watchpointIndex);
+            m_insertionSet.insertNode(
+                indexInBlock, RefChildren, DontRefNode, SpecNone, StructureTransitionWatchpoint,
+                codeOrigin, OpInfo(cell->structure()), weakConstantIndex);
             return;
         }
-        
-        Node check(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(cell->structure())), weakConstantIndex);
-        check.ref();
-        NodeIndex checkIndex = m_graph.size();
-        m_graph.append(check);
-        m_insertionSet.append(indexInBlock, checkIndex);
+
+        m_insertionSet.insertNode(
+            indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure, codeOrigin,
+            OpInfo(m_graph.addStructureSet(cell->structure())), weakConstantIndex);
     }
     
     // This is necessary because the CFA may reach conclusions about constants based on its
@@ -477,24 +445,22 @@
                 break;
                 
             default:
-                Node forceOSRExit(ForceOSRExit, node.codeOrigin);
-                forceOSRExit.ref();
-                NodeIndex forceOSRExitIndex = m_graph.size();
-                m_graph.append(forceOSRExit);
-                m_insertionSet.append(indexInBlock, forceOSRExitIndex);
+                m_insertionSet.insertNode(
+                    indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit,
+                    node.codeOrigin);
                 changed = true;
                 break;
             }
             break;
         }
         m_state.reset();
-        m_insertionSet.execute(*block);
+        m_insertionSet.execute(block);
         
         return changed;
     }
 
     AbstractState m_state;
-    InsertionSet<NodeIndex> m_insertionSet;
+    InsertionSet m_insertionSet;
 };
 
 bool performConstantFolding(Graph& graph)
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 448ef18..bbff1b6 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -39,6 +39,7 @@
 public:
     FixupPhase(Graph& graph)
         : Phase(graph, "fixup")
+        , m_insertionSet(graph)
     {
     }
     
@@ -60,7 +61,7 @@
             m_compileIndex = block->at(m_indexInBlock);
             fixupNode(m_graph[m_compileIndex]);
         }
-        m_insertionSet.execute(*block);
+        m_insertionSet.execute(block);
     }
     
     void fixupNode(Node& node)
@@ -96,12 +97,10 @@
                     m_graph[node.child1()].prediction(),
                     m_graph[m_compileIndex].prediction());
                 if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
-                    m_graph.ref(nodePtr->child1());
-                    Node checkStructure(CheckStructure, nodePtr->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), nodePtr->child1().index());
-                    checkStructure.ref();
-                    NodeIndex checkStructureIndex = m_graph.size();
-                    m_graph.append(checkStructure);
-                    m_insertionSet.append(m_indexInBlock, checkStructureIndex);
+                    m_insertionSet.insertNode(
+                        m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure,
+                        nodePtr->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
+                        nodePtr->child1().index());
                     nodePtr = &m_graph[m_compileIndex];
                 }
             } else {
@@ -322,19 +321,14 @@
                     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.
+                NodeIndex newDivisionIndex = m_insertionSet.insertNode(
+                    m_indexInBlock, DontRefChildren, RefNode, SpecDouble, m_graph[m_compileIndex]);
                 
-                Node& oldDivision = m_graph[m_compileIndex];
-                
-                Node newDivision = oldDivision;
-                newDivision.setRefCount(2);
-                newDivision.predict(SpecDouble);
-                NodeIndex newDivisionIndex = m_graph.size();
-                
-                oldDivision.setOp(DoubleAsInt32);
-                oldDivision.children.initialize(Edge(newDivisionIndex, DoubleUse), Edge(), Edge());
-                
-                m_graph.append(newDivision);
-                m_insertionSet.append(m_indexInBlock, newDivisionIndex);
+                m_graph[m_compileIndex].setOp(DoubleAsInt32);
+                m_graph[m_compileIndex].children.initialize(Edge(newDivisionIndex, DoubleUse), Edge(), Edge());
                 
                 break;
             }
@@ -423,28 +417,13 @@
 #endif
     }
     
-    NodeIndex addNode(const Node& node, bool shouldGenerate)
-    {
-        NodeIndex nodeIndex = m_graph.size();
-        m_graph.append(node);
-        m_insertionSet.append(m_indexInBlock, nodeIndex);
-        if (shouldGenerate)
-            m_graph[nodeIndex].ref();
-        return nodeIndex;
-    }
-    
     NodeIndex checkArray(ArrayMode arrayMode, CodeOrigin codeOrigin, NodeIndex array, NodeIndex index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage, bool shouldGenerate = true)
     {
         ASSERT(arrayMode.isSpecific());
         
-        m_graph.ref(array);
-
         Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
         
         if (arrayMode.doesConversion()) {
-            if (index != NoNode)
-                m_graph.ref(index);
-            
             if (structure) {
                 if (m_indexInBlock > 0) {
                     // If the previous node was a CheckStructure inserted because of stuff
@@ -456,44 +435,42 @@
                         previousNode.setOpAndDefaultFlags(Phantom);
                 }
                 
-                Node arrayify(ArrayifyToStructure, codeOrigin, OpInfo(structure), OpInfo(arrayMode.asWord()), array, index);
-                arrayify.ref();
-                NodeIndex arrayifyIndex = m_graph.size();
-                m_graph.append(arrayify);
-                m_insertionSet.append(m_indexInBlock, arrayifyIndex);
+                m_insertionSet.insertNode(
+                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, ArrayifyToStructure, codeOrigin,
+                    OpInfo(structure), OpInfo(arrayMode.asWord()), array, index);
             } else {
-                Node arrayify(Arrayify, codeOrigin, OpInfo(arrayMode.asWord()), array, index);
-                arrayify.ref();
-                NodeIndex arrayifyIndex = m_graph.size();
-                m_graph.append(arrayify);
-                m_insertionSet.append(m_indexInBlock, arrayifyIndex);
+                m_insertionSet.insertNode(
+                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, Arrayify, codeOrigin,
+                    OpInfo(arrayMode.asWord()), array, index);
             }
         } else {
             if (structure) {
-                Node checkStructure(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(structure)), array);
-                checkStructure.ref();
-                NodeIndex checkStructureIndex = m_graph.size();
-                m_graph.append(checkStructure);
-                m_insertionSet.append(m_indexInBlock, checkStructureIndex);
+                m_insertionSet.insertNode(
+                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure, codeOrigin,
+                    OpInfo(m_graph.addStructureSet(structure)), array);
             } else {
-                Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode.asWord()), array);
-                checkArray.ref();
-                NodeIndex checkArrayIndex = m_graph.size();
-                m_graph.append(checkArray);
-                m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+                m_insertionSet.insertNode(
+                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckArray, codeOrigin,
+                    OpInfo(arrayMode.asWord()), array);
             }
         }
         
         if (!storageCheck(arrayMode))
             return NoNode;
         
-        if (shouldGenerate)
-            m_graph.ref(array);
+        if (arrayMode.usesButterfly()) {
+            return m_insertionSet.insertNode(
+                m_indexInBlock,
+                shouldGenerate ? RefChildren : DontRefChildren,
+                shouldGenerate ? RefNode : DontRefNode,
+                SpecNone, GetButterfly, codeOrigin, array);
+        }
         
-        if (arrayMode.usesButterfly())
-            return addNode(Node(GetButterfly, codeOrigin, array), shouldGenerate);
-        
-        return addNode(Node(GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode.asWord()), array), shouldGenerate);
+        return m_insertionSet.insertNode(
+            m_indexInBlock,
+            shouldGenerate ? RefChildren : DontRefChildren,
+            shouldGenerate ? RefNode : DontRefNode,
+            SpecNone, GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode.asWord()), array);
     }
     
     void blessArrayOperation(Edge base, Edge index, unsigned storageChildIdx)
@@ -505,11 +482,9 @@
         
         switch (nodePtr->arrayMode().type()) {
         case Array::ForceExit: {
-            Node forceExit(ForceOSRExit, nodePtr->codeOrigin);
-            forceExit.ref();
-            NodeIndex forceExitIndex = m_graph.size();
-            m_graph.append(forceExit);
-            m_insertionSet.append(m_indexInBlock, forceExitIndex);
+            m_insertionSet.insertNode(
+                m_indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit,
+                nodePtr->codeOrigin);
             return;
         }
             
@@ -564,33 +539,24 @@
 
     void injectInt32ToDoubleNode(unsigned childIndex)
     {
-        Node& source = m_graph[m_compileIndex];
-        Edge& edge = m_graph.child(source, childIndex);
-        
-        NodeIndex resultIndex = (NodeIndex)m_graph.size();
+        NodeIndex resultIndex = m_insertionSet.insertNode(
+            m_indexInBlock, DontRefChildren, RefNode, SpecDouble, Int32ToDouble,
+            m_graph[m_compileIndex].codeOrigin,
+            m_graph.child(m_graph[m_compileIndex], childIndex).index());
         
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLogF("(replacing @%u->@%u with @%u->@%u) ",
-                m_compileIndex, edge.index(), m_compileIndex, resultIndex);
+        dataLogF(
+            "(replacing @%u->@%u with @%u->@%u) ",
+            m_compileIndex, m_graph.child(m_graph[m_compileIndex], childIndex).index(), m_compileIndex, resultIndex);
 #endif
-        
-        // Fix the edge up here because it's a reference that will be clobbered by
-        // the append() below.
-        NodeIndex oldIndex = edge.index();
-        edge = Edge(resultIndex, DoubleUse);
 
-        m_graph.append(Node(Int32ToDouble, source.codeOrigin, oldIndex));
-        m_insertionSet.append(m_indexInBlock, resultIndex);
-        
-        Node& int32ToDouble = m_graph[resultIndex];
-        int32ToDouble.predict(SpecDouble);
-        int32ToDouble.ref();
+        m_graph.child(m_graph[m_compileIndex], childIndex) = Edge(resultIndex, DoubleUse);
     }
 
     BasicBlock* m_block;
     unsigned m_indexInBlock;
     NodeIndex m_compileIndex;
-    InsertionSet<NodeIndex> m_insertionSet;
+    InsertionSet m_insertionSet;
 };
     
 bool performFixup(Graph& graph)
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index c09d8e9..ee89fb1 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -36,6 +36,7 @@
 #include "DFGBasicBlock.h"
 #include "DFGDominators.h"
 #include "DFGNode.h"
+#include "DFGVariadicFunction.h"
 #include "JSStack.h"
 #include "MethodOfGettingAValueProfile.h"
 #include <wtf/BitVector.h>
@@ -99,16 +100,18 @@
     const Node& at(Edge nodeUse) const { return at(nodeUse.index()); }
     
     // Mark a node as being referenced.
-    void ref(NodeIndex nodeIndex)
+    NodeIndex ref(NodeIndex nodeIndex)
     {
         Node& node = at(nodeIndex);
         // If the value (before incrementing) was at refCount zero then we need to ref its children.
         if (!node.postfixRef())
             refChildren(nodeIndex);
+        return nodeIndex;
     }
-    void ref(Edge nodeUse)
+    Edge ref(Edge nodeUse)
     {
         ref(nodeUse.index());
+        return nodeUse;
     }
     
     void deref(NodeIndex nodeIndex)
@@ -177,6 +180,24 @@
         node.children.child3() = Edge();
     }
     
+#define DFG_DEFINE_ADD_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
+    templatePre typeParams templatePost NodeIndex addNode(RefChildrenMode refChildrenMode, RefNodeMode refNodeMode, SpeculatedType type valueParamsComma valueParams) \
+    { \
+        Node node = Node(valueArgs); \
+        node.predict(type); \
+        if (node.flags() & NodeMustGenerate) \
+            node.ref(); \
+        if (refNodeMode == RefNode) \
+            node.ref(); \
+        NodeIndex result = size(); \
+        append(node); \
+        if (refChildrenMode == RefChildren) \
+            refChildren(result); \
+        return result; \
+    }
+    DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_ADD_NODE)
+#undef DFG_DEFINE_ADD_NODE
+
     // Call this if you've modified the reference counts of nodes that deal with
     // local variables. This is necessary because local variable references can form
     // cycles, and hence reference counting is not enough. This will reset the
diff --git a/Source/JavaScriptCore/dfg/DFGInsertionSet.h b/Source/JavaScriptCore/dfg/DFGInsertionSet.h
index 26ab1f2..bece656 100644
--- a/Source/JavaScriptCore/dfg/DFGInsertionSet.h
+++ b/Source/JavaScriptCore/dfg/DFGInsertionSet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,64 +30,75 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "DFGGraph.h"
 #include <wtf/Vector.h>
 
 namespace JSC { namespace DFG {
 
-template<typename ElementType>
 class Insertion {
 public:
     Insertion() { }
     
-    Insertion(size_t index, const ElementType& element)
+    Insertion(size_t index, NodeIndex element)
         : m_index(index)
         , m_element(element)
     {
     }
     
     size_t index() const { return m_index; }
-    const ElementType& element() const { return m_element; }
+    NodeIndex element() const { return m_element; }
 private:
     size_t m_index;
-    ElementType m_element;
+    NodeIndex m_element;
 };
 
-template<typename ElementType>
 class InsertionSet {
 public:
-    InsertionSet() { }
+    InsertionSet(Graph& graph)
+        : m_graph(graph)
+    {
+    }
     
-    void append(const Insertion<ElementType>& insertion)
+    NodeIndex insert(const Insertion& insertion)
     {
         ASSERT(!m_insertions.size() || m_insertions.last().index() <= insertion.index());
         m_insertions.append(insertion);
+        return insertion.element();
     }
     
-    void append(size_t index, const ElementType& element)
+    NodeIndex insert(size_t index, NodeIndex element)
     {
-        append(Insertion<ElementType>(index, element));
+        return insert(Insertion(index, element));
     }
+
+#define DFG_DEFINE_INSERT_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
+    templatePre typeParams templatePost NodeIndex insertNode(size_t index, RefChildrenMode refChildrenMode, RefNodeMode refNodeMode, SpeculatedType type valueParamsComma valueParams) \
+    { \
+        return insert(index, m_graph.addNode(refChildrenMode, refNodeMode, type valueParamsComma valueArgs)); \
+    }
+    DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_INSERT_NODE)
+#undef DFG_DEFINE_INSERT_NODE
     
-    template<typename CollectionType>
-    void execute(CollectionType& collection)
+    void execute(BasicBlock* block)
     {
         if (!m_insertions.size())
             return;
-        collection.grow(collection.size() + m_insertions.size());
-        size_t lastIndex = collection.size();
+        block->grow(block->size() + m_insertions.size());
+        size_t lastIndex = block->size();
         for (size_t indexInInsertions = m_insertions.size(); indexInInsertions--;) {
-            Insertion<ElementType>& insertion = m_insertions[indexInInsertions];
+            Insertion& insertion = m_insertions[indexInInsertions];
             size_t firstIndex = insertion.index() + indexInInsertions;
             size_t indexOffset = indexInInsertions + 1;
             for (size_t i = lastIndex; --i > firstIndex;)
-                collection[i] = collection[i - indexOffset];
-            collection[firstIndex] = insertion.element();
+                block->at(i) = block->at(i - indexOffset);
+            block->at(firstIndex) = insertion.element();
             lastIndex = firstIndex;
         }
         m_insertions.resize(0);
     }
 private:
-    Vector<Insertion<ElementType>, 8> m_insertions;
+    Graph& m_graph;
+    Vector<Insertion, 8> m_insertions;
 };
 
 } } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 72a2081..7f43d6b 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -87,6 +87,17 @@
     
     Node() { }
     
+    Node(NodeType op, CodeOrigin codeOrigin, const AdjacencyList& children)
+        : codeOrigin(codeOrigin)
+        , children(children)
+        , m_virtualRegister(InvalidVirtualRegister)
+        , m_refCount(0)
+        , 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, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
         : codeOrigin(codeOrigin)
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index a70f56a..09b732b 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -259,7 +259,7 @@
         
         // Place CheckStructure's at SetLocal sites.
         
-        InsertionSet<NodeIndex> insertionSet;
+        InsertionSet insertionSet(m_graph);
         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
             if (!block)
@@ -286,23 +286,16 @@
                     if (!iter->value.m_structure)
                         break;
                     
-                    node.ref();
-
                     CodeOrigin codeOrigin = node.codeOrigin;
                     
-                    Node getLocal(GetLocal, codeOrigin, OpInfo(variable), nodeIndex);
-                    getLocal.predict(variable->prediction());
-                    getLocal.ref();
-                    NodeIndex getLocalIndex = m_graph.size();
-                    m_graph.append(getLocal);
-                    insertionSet.append(indexInBlock + 1, getLocalIndex);
-                    
-                    Node checkStructure(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), getLocalIndex);
-                    checkStructure.ref();
-                    NodeIndex checkStructureIndex = m_graph.size();
-                    m_graph.append(checkStructure);
-                    insertionSet.append(indexInBlock + 1, checkStructureIndex);
-                    
+                    NodeIndex getLocalIndex = insertionSet.insertNode(
+                        indexInBlock + 1, DontRefChildren, DontRefNode, variable->prediction(),
+                        GetLocal, codeOrigin, OpInfo(variable), nodeIndex);
+                    insertionSet.insertNode(
+                        indexInBlock + 1, RefChildren, DontRefNode, SpecNone, CheckStructure,
+                        codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
+                        getLocalIndex);
+
                     if (block->variablesAtTail.operand(variable->local()) == nodeIndex)
                         block->variablesAtTail.operand(variable->local()) = getLocalIndex;
                     
@@ -327,18 +320,15 @@
                     CodeOrigin codeOrigin = node.codeOrigin;
                     NodeIndex child1 = node.child1().index();
                     
-                    Node setLocal(SetLocal, codeOrigin, OpInfo(variable), child1);
-                    NodeIndex setLocalIndex = m_graph.size();
-                    m_graph.append(setLocal);
-                    insertionSet.append(indexInBlock, setLocalIndex);
-                    m_graph[child1].ref();
+                    insertionSet.insertNode(
+                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, SetLocal, codeOrigin,
+                        OpInfo(variable), child1);
+
                     // Use a ForwardCheckStructure to indicate that we should exit to the
                     // next bytecode instruction rather than reexecuting the current one.
-                    Node checkStructure(ForwardCheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), child1);
-                    checkStructure.ref();
-                    NodeIndex checkStructureIndex = m_graph.size();
-                    m_graph.append(checkStructure);
-                    insertionSet.append(indexInBlock, checkStructureIndex);
+                    insertionSet.insertNode(
+                        indexInBlock, RefChildren, DontRefNode, SpecNone, ForwardCheckStructure,
+                        codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), child1);
                     changed = true;
                     break;
                 }
@@ -347,7 +337,7 @@
                     break;
                 }
             }
-            insertionSet.execute(*block);
+            insertionSet.execute(block);
         }
         
         return changed;
diff --git a/Source/JavaScriptCore/dfg/DFGVariadicFunction.h b/Source/JavaScriptCore/dfg/DFGVariadicFunction.h
new file mode 100644
index 0000000..f5523af
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGVariadicFunction.h
@@ -0,0 +1,57 @@
+/*
+ * 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 DFGVariadicFunction_h
+#define DFGVariadicFunction_h
+
+#define DFG_COMMA ,
+
+// The signature of v is (templatePre, templatePost, typeParams, valueParams, valueArgs)
+//
+// You would use it like:
+// #define DEFINE_FUNCTION(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs)
+//     templatePre typeParams templatePost void f(valueParams) { g(valueArgs); }
+// DFG_VARIADIC_TEMPLATE_FUNCTION(DEFINE_FUNCTION)
+// #undef DEFINE_FUNCTION
+//
+// Or if you wanted the defined function to take an additional template arg, you would do:
+// #define DEFINE_FUNCTION(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs)
+//     template<typename T valueParamsComma typeParams> void f(T value valueParamsComma valueParams) { g(value, valueArgs); }
+// DFG_VARIADIC_TEMPLATE_FUNCTION(DEFINE_FUNCTION)
+// #undef DEFINE_FUNCTION
+
+#define DFG_VARIADIC_TEMPLATE_FUNCTION(v) \
+    v(, , , , , ) \
+    v(template<, >, typename _DFG_T1, DFG_COMMA, const _DFG_T1& _DFG_value1, _DFG_value1) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2, _DFG_value1 DFG_COMMA _DFG_value2) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2 DFG_COMMA typename _DFG_T3, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2 DFG_COMMA const _DFG_T3& _DFG_value3, _DFG_value1 DFG_COMMA _DFG_value2 DFG_COMMA _DFG_value3) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2 DFG_COMMA typename _DFG_T3 DFG_COMMA typename _DFG_T4, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2 DFG_COMMA const _DFG_T3& _DFG_value3 DFG_COMMA const _DFG_T4& _DFG_value4, _DFG_value1 DFG_COMMA _DFG_value2 DFG_COMMA _DFG_value3 DFG_COMMA _DFG_value4) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2 DFG_COMMA typename _DFG_T3 DFG_COMMA typename _DFG_T4 DFG_COMMA typename _DFG_T5, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2 DFG_COMMA const _DFG_T3& _DFG_value3 DFG_COMMA const _DFG_T4& _DFG_value4 DFG_COMMA const _DFG_T5& _DFG_value5, _DFG_value1 DFG_COMMA _DFG_value2 DFG_COMMA _DFG_value3 DFG_COMMA _DFG_value4 DFG_COMMA _DFG_value5) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2 DFG_COMMA typename _DFG_T3 DFG_COMMA typename _DFG_T4 DFG_COMMA typename _DFG_T5 DFG_COMMA typename _DFG_T6, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2 DFG_COMMA const _DFG_T3& _DFG_value3 DFG_COMMA const _DFG_T4& _DFG_value4 DFG_COMMA const _DFG_T5& _DFG_value5 DFG_COMMA const _DFG_T6& _DFG_value6, _DFG_value1 DFG_COMMA _DFG_value2 DFG_COMMA _DFG_value3 DFG_COMMA _DFG_value4 DFG_COMMA _DFG_value5 DFG_COMMA _DFG_value6) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2 DFG_COMMA typename _DFG_T3 DFG_COMMA typename _DFG_T4 DFG_COMMA typename _DFG_T5 DFG_COMMA typename _DFG_T6 DFG_COMMA typename _DFG_T7, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2 DFG_COMMA const _DFG_T3& _DFG_value3 DFG_COMMA const _DFG_T4& _DFG_value4 DFG_COMMA const _DFG_T5& _DFG_value5 DFG_COMMA const _DFG_T6& _DFG_value6 DFG_COMMA const _DFG_T7& _DFG_value7, _DFG_value1 DFG_COMMA _DFG_value2 DFG_COMMA _DFG_value3 DFG_COMMA _DFG_value4 DFG_COMMA _DFG_value5 DFG_COMMA _DFG_value6 DFG_COMMA _DFG_value7) \
+    v(template<, >, typename _DFG_T1 DFG_COMMA typename _DFG_T2 DFG_COMMA typename _DFG_T3 DFG_COMMA typename _DFG_T4 DFG_COMMA typename _DFG_T5 DFG_COMMA typename _DFG_T6 DFG_COMMA typename _DFG_T7 DFG_COMMA typename _DFG_T8, DFG_COMMA, const _DFG_T1& _DFG_value1 DFG_COMMA const _DFG_T2& _DFG_value2 DFG_COMMA const _DFG_T3& _DFG_value3 DFG_COMMA const _DFG_T4& _DFG_value4 DFG_COMMA const _DFG_T5& _DFG_value5 DFG_COMMA const _DFG_T6& _DFG_value6 DFG_COMMA const _DFG_T7& _DFG_value7 DFG_COMMA _DFG_T8& _DFG_value8, _DFG_value1 DFG_COMMA _DFG_value2 DFG_COMMA _DFG_value3 DFG_COMMA _DFG_value4 DFG_COMMA _DFG_value5 DFG_COMMA _DFG_value6 DFG_COMMA _DFG_value7 DFG_COMMA _DFG_value8)
+
+#endif // DFGVariadicFunction_h
+