[DOMJIT] Add a way for DOMJIT::Patchpoint to express effects
https://bugs.webkit.org/show_bug.cgi?id=163657

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch introduces DOMJIT::Effect. It describes the side effects of
the DOMJIT::CallDOMPatchpoint. DOMJIT::CallDOMPatchpoint can use this
feature to teach the compilers about the effects. And the compilers
will perform CSE based on the reported effects.

As the same to B3's HeapRange, the effects are represented as a pair of
integers. [begin, end) pair will represents the range of the abstract
heap. We encode the abstract heap hierarchy into these pairs. Like,

                        Root: [0, 32)
         Child1: [0, 20)             Child2: [20, 32)
Child11: [0, 4) Child12: [4, 20)

This simplifies the representation of the abstract heap. And WebCore
just tells pairs of integers and it does not tell any detailed hierarchy.
So, DFG and FTL can optimize DOM operations without deep knowledge of
the DOM abstract heap hierarchy. For example, WebCore will tell that
firstChild will read Node_firstChild abstract heap. But this information
is encoded to the pair and DFG does not know the details. But still
DFG can understand the abstract heap hierarchy and can query whether the
given abstract heap overlaps with some abstract heap.

The heap range told by the WebCore is represented as DOMJIT::HeapRange.
DFG will handle this under the DOMState abstract heap. DOMJIT::HeapRange
is stored in DFG::AbstractHeap's Payload. We maintain the hierarchy by
DOMJIT::HeapRange in the DOMState abstract heap. We add a necessary
handling in DFG's AbstractHeap and ClobberSet.

And we also introduce DOMStateLoc for HeapLocation. It is combined with
DOMState AbstractHeap with DOMJIT::HeapRange. For example, we can
represent Node.firstChild as `read(DOMState:Node_firstChild)` and
`def(HeapLocation(node, DOMState:Node_firstChild))` thingy. This allows us
to perform CSE onto DOM getters that will read some of DOM heap!

For simplicity, we convert CallDOM from NodeVarArgs to the normal one.
CallDOM is now just used for DOMJIT getter. So its children is at most 2.
It may have either 1 or 2 children. If the global object is required
by CallDOMPatchpoint, it has 2 children. And we changed the order of
the children to further simplify the code. Before this change, the order
is 1: globalObject 2: base. After this patch, the order becomes 1: base,
and 2: globalObject. And the child2 may not exists if the global object
is not required. We changed all the existing DOMJIT patchpoint to this
form.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/PolymorphicAccess.cpp:
(JSC::AccessCase::emitDOMJITGetter):
* dfg/DFGAbstractHeap.cpp:
(JSC::DFG::AbstractHeap::dump):
* dfg/DFGAbstractHeap.h:
(JSC::DFG::AbstractHeap::isStrictSubtypeOf):
(JSC::DFG::AbstractHeap::overlaps):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::blessCallDOM):
(JSC::DFG::ByteCodeParser::handleDOMJITGetter):
* dfg/DFGClobberSet.cpp:
(JSC::DFG::ClobberSet::overlaps):
* dfg/DFGClobberSet.h:
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.h:
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasCallDOMData):
(JSC::DFG::Node::callDOMData):
(JSC::DFG::Node::hasCallDOMPatchpoint): Deleted.
(JSC::DFG::Node::callDOMPatchpoint): Deleted.
* dfg/DFGNodeType.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCallDOM):
* domjit/DOMJITAbstractHeap.cpp: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
(JSC::DOMJIT::AbstractHeap::compute):
(JSC::DOMJIT::AbstractHeap::dump):
(JSC::DOMJIT::AbstractHeap::shallowDump):
(JSC::DOMJIT::AbstractHeap::deepDump):
* domjit/DOMJITAbstractHeap.h: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
(JSC::DOMJIT::AbstractHeap::AbstractHeap):
(JSC::DOMJIT::AbstractHeap::setParent):
(JSC::DOMJIT::AbstractHeap::isRoot):
(JSC::DOMJIT::AbstractHeap::isComputed):
(JSC::DOMJIT::AbstractHeap::range):
* domjit/DOMJITCallDOMPatchpoint.h:
* domjit/DOMJITEffect.h: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
(JSC::DOMJIT::Effect::forReadWrite):
(JSC::DOMJIT::Effect::forPure):
(JSC::DOMJIT::Effect::forDef):
(JSC::DOMJIT::Effect::mustGenerate):
* domjit/DOMJITHeapRange.cpp: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
(JSC::DOMJIT::HeapRange::dump):
* domjit/DOMJITHeapRange.h: Added.
(JSC::DOMJIT::HeapRange::HeapRange):
(JSC::DOMJIT::HeapRange::fromRaw):
(JSC::DOMJIT::HeapRange::begin):
(JSC::DOMJIT::HeapRange::end):
(JSC::DOMJIT::HeapRange::rawRepresentation):
(JSC::DOMJIT::HeapRange::operator bool):
(JSC::DOMJIT::HeapRange::operator==):
(JSC::DOMJIT::HeapRange::top):
(JSC::DOMJIT::HeapRange::none):
(JSC::DOMJIT::HeapRange::isStrictSubtypeOf):
(JSC::DOMJIT::HeapRange::isSubtypeOf):
(JSC::DOMJIT::HeapRange::overlaps):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
* jsc.cpp:

Source/WebCore:

CallDOMPatchpoint now has the way to tell its effects to DFG and FTL compilers.
WebCore DOMJIT::AbstractHeapRepository will construct the hierarchy of the abstract
heap. And then it encodes these information into the pairs of the integers.

And this patch also changes the DOMJIT::PatchpointParams' parameter order.
So we change them in all the DOMJIT::CallDOMPatchpoint sites.

* CMakeLists.txt:
* ForwardingHeaders/domjit/DOMJITAbstractHeap.h: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
* ForwardingHeaders/domjit/DOMJITEffect.h: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
* ForwardingHeaders/domjit/DOMJITHeapRange.h: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
* WebCore.xcodeproj/project.pbxproj:
* domjit/DOMJITAbstractHeapRepository.cpp: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
(WebCore::DOMJIT::AbstractHeapRepository::AbstractHeapRepository):
(WebCore::DOMJIT::AbstractHeapRepository::instance):
* domjit/DOMJITAbstractHeapRepository.h: Copied from Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h.
* domjit/DOMJITHelpers.h:
(WebCore::DOMJITHelpers::branchIfNotWorldIsNormal): Deleted.
(WebCore::DOMJITHelpers::branchIfNotWeakIsLive): Deleted.
(WebCore::DOMJITHelpers::tryLookUpWrapperCache): Deleted.
(WebCore::DOMJITHelpers::toWrapper): Deleted.
(WebCore::DOMJITHelpers::branchIfDOMWrapper): Deleted.
(WebCore::DOMJITHelpers::branchIfNotDOMWrapper): Deleted.
(WebCore::DOMJITHelpers::branchIfNode): Deleted.
(WebCore::DOMJITHelpers::branchIfNotNode): Deleted.
(WebCore::DOMJITHelpers::branchIfElement): Deleted.
(WebCore::DOMJITHelpers::branchIfNotElement): Deleted.
(WebCore::DOMJITHelpers::branchIfDocumentWrapper): Deleted.
(WebCore::DOMJITHelpers::branchIfNotDocumentWrapper): Deleted.
* domjit/JSNodeDOMJIT.cpp:
(WebCore::createCallDOMForOffsetAccess):
(WebCore::checkNode):
(WebCore::NodeFirstChildDOMJIT::checkDOM):
(WebCore::NodeFirstChildDOMJIT::callDOM):
(WebCore::NodeLastChildDOMJIT::checkDOM):
(WebCore::NodeLastChildDOMJIT::callDOM):
(WebCore::NodeNextSiblingDOMJIT::checkDOM):
(WebCore::NodeNextSiblingDOMJIT::callDOM):
(WebCore::NodePreviousSiblingDOMJIT::checkDOM):
(WebCore::NodePreviousSiblingDOMJIT::callDOM):
(WebCore::NodeParentNodeDOMJIT::checkDOM):
(WebCore::NodeParentNodeDOMJIT::callDOM):
(WebCore::NodeNodeTypeDOMJIT::checkDOM):
(WebCore::NodeNodeTypeDOMJIT::callDOM):

Source/WTF:

Simplify nonEmptyRangesOverlap.

* wtf/MathExtras.h:
(WTF::nonEmptyRangesOverlap):

LayoutTests:

* js/dom/domjit-accessor-different-effect-expected.txt: Added.
* js/dom/domjit-accessor-different-effect.html: Added.
* js/dom/domjit-accessor-effect-expected.txt: Added.
* js/dom/domjit-accessor-effect-should-overlap-with-call-expected.txt: Added.
* js/dom/domjit-accessor-effect-should-overlap-with-call.html: Added.
* js/dom/domjit-accessor-effect.html: Added.
* js/dom/domjit-accessor-licm-expected.txt: Added.
* js/dom/domjit-accessor-licm.html: Added.
* js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure-expected.txt: Added.
* js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@207787 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractHeap.cpp b/Source/JavaScriptCore/dfg/DFGAbstractHeap.cpp
index 1e11019..cd694bb 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractHeap.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractHeap.cpp
@@ -45,6 +45,10 @@
     out.print(kind());
     if (kind() == InvalidAbstractHeap || kind() == World || kind() == Heap || payload().isTop())
         return;
+    if (kind() == DOMState) {
+        out.print("(", DOMJIT::HeapRange::fromRaw(payload().value32()), ")");
+        return;
+    }
     out.print("(", payload(), ")");
 }
 
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
index 0abd502..97c3a34 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractHeap.h
@@ -27,6 +27,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "DOMJITHeapRange.h"
 #include "VirtualRegister.h"
 #include <wtf/HashMap.h>
 #include <wtf/PrintStream.h>
@@ -73,6 +74,8 @@
     macro(MathDotRandomState) \
     macro(InternalState) \
     macro(Absolute) \
+    /* DOMJIT tells the heap range with the pair of integers. */\
+    macro(DOMState) \
     /* Use this for writes only, to indicate that this may fire watchpoints. Usually this is never directly written but instead we test to see if a node clobbers this; it just so happens that you have to write world to clobber it. */\
     macro(Watchpoint_fire) \
     /* Use these for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
@@ -233,6 +236,15 @@
     bool isStrictSubtypeOf(const AbstractHeap& other) const
     {
         AbstractHeap current = *this;
+        if (current.kind() == DOMState && other.kind() == DOMState) {
+            Payload currentPayload = current.payload();
+            Payload otherPayload = other.payload();
+            if (currentPayload.isTop())
+                return false;
+            if (otherPayload.isTop())
+                return true;
+            return DOMJIT::HeapRange::fromRaw(currentPayload.value32()).isStrictSubtypeOf(DOMJIT::HeapRange::fromRaw(otherPayload.value32()));
+        }
         while (current.kind() != World) {
             current = current.supertype();
             if (current == other)
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index a12f09c..f09d41b 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -2289,10 +2289,13 @@
         filterClassInfo(value, node->classInfo());
         break;
     }
-    case CallDOM:
-        clobberWorld(node->origin.semantic, clobberLimit);
+    case CallDOM: {
+        DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMData()->patchpoint;
+        if (patchpoint->effect.writes)
+            clobberWorld(node->origin.semantic, clobberLimit);
         forNode(node).makeBytecodeTop();
         break;
+    }
     case CheckArray: {
         if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
             m_state.setFoundConstants(true);
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 4884206..0603168 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2673,6 +2673,13 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+static void blessCallDOM(Node* node)
+{
+    DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMData()->patchpoint;
+    if (!patchpoint->effect.mustGenerate())
+        node->clearFlags(NodeMustGenerate);
+}
+
 bool ByteCodeParser::handleDOMJITGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, SpeculatedType prediction)
 {
     if (!variant.domJIT())
@@ -2691,14 +2698,22 @@
     // We do not need to emit CheckCell thingy here. When the custom accessor is replaced to different one, Structure transition occurs.
     addToGraph(CheckDOM, OpInfo(checkDOMPatchpoint.ptr()), OpInfo(domJIT->thisClassInfo()), thisNode);
 
+    CallDOMData* callDOMData = m_graph.m_callDOMData.add();
     Ref<DOMJIT::CallDOMPatchpoint> callDOMPatchpoint = domJIT->callDOM();
     m_graph.m_domJITPatchpoints.append(callDOMPatchpoint.ptr());
+
+    callDOMData->domJIT = domJIT;
+    callDOMData->patchpoint = callDOMPatchpoint.ptr();
+
+    Node* callDOMNode = nullptr;
+    // GlobalObject of thisNode is always used to create a DOMWrapper.
     if (callDOMPatchpoint->requireGlobalObject) {
         Node* globalObject = addToGraph(GetGlobalObject, thisNode);
-        addVarArgChild(globalObject); // GlobalObject of thisNode is always used to create a DOMWrapper.
-    }
-    addVarArgChild(thisNode);
-    set(VirtualRegister(resultOperand), addToGraph(Node::VarArg, CallDOM, OpInfo(callDOMPatchpoint.ptr()), OpInfo(prediction)));
+        callDOMNode = addToGraph(CallDOM, OpInfo(callDOMData), OpInfo(prediction), thisNode, globalObject);
+    } else
+        callDOMNode = addToGraph(CallDOM, OpInfo(callDOMData), OpInfo(prediction), thisNode);
+    blessCallDOM(callDOMNode);
+    set(VirtualRegister(resultOperand), callDOMNode);
     return true;
 }
 
diff --git a/Source/JavaScriptCore/dfg/DFGClobberSet.cpp b/Source/JavaScriptCore/dfg/DFGClobberSet.cpp
index d4630e3..ce3398e 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberSet.cpp
+++ b/Source/JavaScriptCore/dfg/DFGClobberSet.cpp
@@ -81,6 +81,23 @@
 {
     if (m_clobbers.find(heap) != m_clobbers.end())
         return true;
+    if (heap.kind() == DOMState && !heap.payload().isTop()) {
+        // DOMState heap has its own hierarchy. For direct heap clobbers that payload is not Top,
+        // we should query whether the clobber overlaps with the given heap.
+        DOMJIT::HeapRange range = DOMJIT::HeapRange::fromRaw(heap.payload().value32());
+        for (auto pair : m_clobbers) {
+            bool direct = pair.value;
+            if (!direct)
+                continue;
+            AbstractHeap clobber = pair.key;
+            if (clobber.kind() != DOMState)
+                continue;
+            if (clobber.payload().isTop())
+                return true;
+            if (DOMJIT::HeapRange::fromRaw(clobber.payload().value32()).overlaps(range))
+                return true;
+        }
+    }
     while (heap.kind() != World) {
         heap = heap.supertype();
         if (contains(heap))
diff --git a/Source/JavaScriptCore/dfg/DFGClobberSet.h b/Source/JavaScriptCore/dfg/DFGClobberSet.h
index 729f39b..f93e27f 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberSet.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberSet.h
@@ -52,11 +52,11 @@
     
     void add(AbstractHeap);
     void addAll(const ClobberSet&);
-    bool contains(AbstractHeap) const;
     bool overlaps(AbstractHeap) const;
     void clear();
     
     // Calls useful for debugging the ClobberSet.
+    // Do not call for non debugging purpose. Otherwise, you must handle DOMState hierarchy carefully.
     
     HashSet<AbstractHeap> direct() const;
     HashSet<AbstractHeap> super() const;
@@ -64,6 +64,8 @@
     void dump(PrintStream&) const;
     
 private:
+    bool contains(AbstractHeap) const;
+
     HashSet<AbstractHeap> setOf(bool direct) const;
     
     // Maps heap to:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index f929337..f2625be 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -33,6 +33,7 @@
 #include "DFGHeapLocation.h"
 #include "DFGLazyNode.h"
 #include "DFGPureValue.h"
+#include "DOMJITCallDOMPatchpoint.h"
 
 namespace JSC { namespace DFG {
 
@@ -907,10 +908,34 @@
         def(PureValue(node, node->classInfo()));
         return;
 
-    case CallDOM:
-        read(World);
-        write(Heap);
+    case CallDOM: {
+        DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMData()->patchpoint;
+        DOMJIT::Effect effect = patchpoint->effect;
+        if (effect.reads) {
+            if (effect.reads == DOMJIT::HeapRange::top())
+                read(World);
+            else
+                read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
+        }
+        if (effect.writes) {
+            if (effect.writes == DOMJIT::HeapRange::top())
+                write(World);
+            else
+                write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
+        }
+        if (effect.def) {
+            DOMJIT::HeapRange range = effect.def.value();
+            if (range == DOMJIT::HeapRange::none())
+                def(PureValue(node, node->callDOMData()->domJIT));
+            else {
+                // Def with heap location. We do not include "GlobalObject" for that since this information is included in the base node.
+                // FIXME: When supporting the other nodes like getElementById("string"), we should include the base and the id string.
+                // Currently, we only see the DOMJIT getter here. So just including "base" is ok.
+                def(HeapLocation(DOMStateLoc, AbstractHeap(DOMState, range.rawRepresentation()), node->child1()), LazyNode(node));
+            }
+        }
         return;
+    }
 
     case Arrayify:
     case ArrayifyToStructure:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 3f13842..f35b66c 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -118,7 +118,6 @@
     case CheckStructure:
     case GetExecutable:
     case GetButterfly:
-    case CallDOM:
     case CheckDOM:
     case CheckArray:
     case GetScope:
@@ -299,6 +298,7 @@
     case StringReplaceRegExp:
     case CreateRest:
     case ToLowerCase:
+    case CallDOM:
         return true;
         
     case MultiPutByOffset:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 33c0cf1..dbc1017 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -1711,11 +1711,10 @@
             break;
 
         case CallDOM: {
-            int childIndex = 0;
-            DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMPatchpoint();
+            DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMData()->patchpoint;
+            fixEdge<CellUse>(node->child1()); // DOM.
             if (patchpoint->requireGlobalObject)
-                fixEdge<KnownCellUse>(m_graph.varArgChild(node, childIndex++)); // GlobalObject.
-            fixEdge<CellUse>(m_graph.varArgChild(node, childIndex++)); // DOM.
+                fixEdge<KnownCellUse>(node->child2()); // GlobalObject.
             break;
         }
 
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 76b2bae..f957f5c 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -901,6 +901,7 @@
     Bag<LoadVarargsData> m_loadVarargsData;
     Bag<StackAccessData> m_stackAccessData;
     Bag<LazyJSValue> m_lazyJSValues;
+    Bag<CallDOMData> m_callDOMData;
     Vector<InlineVariableData, 4> m_inlineVariableData;
     HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness;
     HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>> m_bytecodeKills;
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
index 8470637..9b2292d 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
@@ -152,6 +152,9 @@
     case MapHasLoc:
         out.print("MapHasLoc");
         return;
+    case DOMStateLoc:
+        out.print("DOMStateLoc");
+        return;
     }
     
     RELEASE_ASSERT_NOT_REACHED();
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.h b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
index 704d191..6357be1 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.h
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
@@ -60,7 +60,8 @@
     StackPayloadLoc,
     MapBucketLoc,
     JSMapGetLoc,
-    MapHasLoc
+    MapHasLoc,
+    DOMStateLoc,
 };
 
 class HeapLocation {
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index c9411d5..0d1a4b5 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -59,6 +59,7 @@
 namespace JSC {
 
 namespace DOMJIT {
+class GetterSetter;
 class Patchpoint;
 class CallDOMPatchpoint;
 }
@@ -231,6 +232,11 @@
     FlushedAt flushedAt() { return FlushedAt(format, machineLocal); }
 };
 
+struct CallDOMData {
+    DOMJIT::GetterSetter* domJIT { nullptr };
+    DOMJIT::CallDOMPatchpoint* patchpoint { nullptr };
+};
+
 // === Node ===
 //
 // Node represents a single operation in the data flow graph.
@@ -2336,15 +2342,15 @@
         return m_opInfo.as<DOMJIT::Patchpoint*>();
     }
 
-    bool hasCallDOMPatchpoint() const
+    bool hasCallDOMData() const
     {
         return op() == CallDOM;
     }
 
-    DOMJIT::CallDOMPatchpoint* callDOMPatchpoint()
+    CallDOMData* callDOMData()
     {
-        ASSERT(hasCallDOMPatchpoint());
-        return m_opInfo.as<DOMJIT::CallDOMPatchpoint*>();
+        ASSERT(hasCallDOMData());
+        return m_opInfo.as<CallDOMData*>();
     }
 
     bool hasClassInfo() const
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 19b2825f..75aa62e 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -404,7 +404,7 @@
     macro(ToLowerCase, NodeResultJS) \
     /* Nodes for DOM JIT */\
     macro(CheckDOM, NodeMustGenerate) \
-    macro(CallDOM, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
+    macro(CallDOM, NodeResultJS | NodeMustGenerate) \
 
 // 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).
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 5e64baf..6ccffb5 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -7225,7 +7225,7 @@
 
 void SpeculativeJIT::compileCallDOM(Node* node)
 {
-    DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMPatchpoint();
+    DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMData()->patchpoint;
 
     Vector<GPRReg> gpScratch;
     Vector<FPRReg> fpScratch;
@@ -7234,19 +7234,17 @@
     JSValueRegsTemporary result(this);
     regs.append(result.regs());
 
-    int childIndex = 0;
+    Edge& baseEdge = node->child1();
+    SpeculateCellOperand base(this, baseEdge);
+    regs.append(DOMJIT::Value(base.gpr(), m_state.forNode(baseEdge).value()));
 
     Optional<SpeculateCellOperand> globalObject;
     if (patchpoint->requireGlobalObject) {
-        Edge& globalObjectEdge = m_jit.graph().varArgChild(node, childIndex++);
+        Edge& globalObjectEdge = node->child2();
         globalObject = SpeculateCellOperand(this, globalObjectEdge);
         regs.append(DOMJIT::Value(globalObject->gpr(), m_state.forNode(globalObjectEdge).value()));
     }
 
-    Edge& baseEdge = m_jit.graph().varArgChild(node, childIndex++);
-    SpeculateCellOperand base(this, baseEdge);
-    regs.append(DOMJIT::Value(base.gpr(), m_state.forNode(baseEdge).value()));
-
     Vector<GPRTemporary> gpTempraries;
     Vector<FPRTemporary> fpTempraries;
     allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, *patchpoint);