[DOMJIT] Add a way for DOMJIT::Patchpoint to express effects
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Oct 2016 23:34:32 +0000 (23:34 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Oct 2016 23:34:32 +0000 (23:34 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@207787 268f45cc-cd09-0410-ab3c-d52691b4dbfc

50 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/domjit-accessor-different-effect-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-different-effect.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-effect-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-effect-should-overlap-with-call-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-effect-should-overlap-with-call.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-effect.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-licm-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-licm.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure.html [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp
Source/JavaScriptCore/dfg/DFGAbstractHeap.cpp
Source/JavaScriptCore/dfg/DFGAbstractHeap.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberSet.cpp
Source/JavaScriptCore/dfg/DFGClobberSet.h
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
Source/JavaScriptCore/dfg/DFGHeapLocation.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/domjit/DOMJITAbstractHeap.cpp [new file with mode: 0644]
Source/JavaScriptCore/domjit/DOMJITAbstractHeap.h [new file with mode: 0644]
Source/JavaScriptCore/domjit/DOMJITCallDOMPatchpoint.h
Source/JavaScriptCore/domjit/DOMJITEffect.h [new file with mode: 0644]
Source/JavaScriptCore/domjit/DOMJITHeapRange.cpp [new file with mode: 0644]
Source/JavaScriptCore/domjit/DOMJITHeapRange.h [new file with mode: 0644]
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jsc.cpp
Source/WTF/ChangeLog
Source/WTF/wtf/MathExtras.h
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/ForwardingHeaders/domjit/DOMJITAbstractHeap.h [new file with mode: 0644]
Source/WebCore/ForwardingHeaders/domjit/DOMJITEffect.h [new file with mode: 0644]
Source/WebCore/ForwardingHeaders/domjit/DOMJITHeapRange.h [new file with mode: 0644]
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp [new file with mode: 0644]
Source/WebCore/domjit/DOMJITAbstractHeapRepository.h [new file with mode: 0644]
Source/WebCore/domjit/DOMJITHelpers.h
Source/WebCore/domjit/JSNodeDOMJIT.cpp

index a640337..58ddad3 100644 (file)
@@ -1,3 +1,21 @@
+2016-10-23  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add a way for DOMJIT::Patchpoint to express effects
+        https://bugs.webkit.org/show_bug.cgi?id=163657
+
+        Reviewed by Saam Barati.
+
+        * 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.
+
 2016-10-24  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Font variations test gardening
diff --git a/LayoutTests/js/dom/domjit-accessor-different-effect-expected.txt b/LayoutTests/js/dom/domjit-accessor-different-effect-expected.txt
new file mode 100644 (file)
index 0000000..fe6a1ea
--- /dev/null
@@ -0,0 +1,9 @@
+Test DOMJIT accessors will handle different heap accesses correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS test() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-accessor-different-effect.html b/LayoutTests/js/dom/domjit-accessor-different-effect.html
new file mode 100644 (file)
index 0000000..d7130bf
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test DOMJIT accessors will handle different heap accesses correctly.');
+
+function test()
+{
+    var target = document.getElementById('target');
+    var firstChild = document.getElementById('firstChild');
+    var lastChild = document.getElementById('lastChild');
+    for (var i = 0; i < 1e4; ++i) {
+        var ret = target.firstChild === firstChild;
+        ret &= target.lastChild === lastChild;
+        ret &= target.firstChild === firstChild;
+        ret &= target.lastChild === lastChild;
+        if (!ret)
+            return false;
+    }
+    return true;
+}
+
+shouldBeTrue(`test()`);
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-accessor-effect-expected.txt b/LayoutTests/js/dom/domjit-accessor-effect-expected.txt
new file mode 100644 (file)
index 0000000..6fba608
--- /dev/null
@@ -0,0 +1,13 @@
+Test DOMJIT accessors will represent their heap accesses.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS func("firstChild", document.getElementById("target"), document.getElementById("firstChild")) is true
+PASS func("lastChild", document.getElementById("target"), document.getElementById("lastChild")) is true
+PASS func("nextSibling", document.getElementById("target"), document.getElementById("nextSibling")) is true
+PASS func("previousSibling", document.getElementById("target"), document.getElementById("previousSibling")) is true
+PASS func("parentNode", document.getElementById("target"), document.getElementById("parentNode")) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-accessor-effect-should-overlap-with-call-expected.txt b/LayoutTests/js/dom/domjit-accessor-effect-should-overlap-with-call-expected.txt
new file mode 100644 (file)
index 0000000..9a9d163
--- /dev/null
@@ -0,0 +1,9 @@
+Test function calls should overlap with effects of DOMJIT accessors.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS test() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-accessor-effect-should-overlap-with-call.html b/LayoutTests/js/dom/domjit-accessor-effect-should-overlap-with-call.html
new file mode 100644 (file)
index 0000000..c4b4ac1
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test function calls should overlap with effects of DOMJIT accessors.');
+
+function test()
+{
+    var target = document.getElementById('target');
+    var firstChild = document.getElementById('firstChild');
+    var lastChild = document.getElementById('lastChild');
+    for (var i = 0; i < 1e4; ++i) {
+        var ret = target.firstChild === firstChild;
+        target.appendChild(lastChild);
+        ret &= target.firstChild === firstChild;
+        if (!ret)
+            return false;
+    }
+    return true;
+}
+
+shouldBeTrue(`test()`);
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-accessor-effect.html b/LayoutTests/js/dom/domjit-accessor-effect.html
new file mode 100644 (file)
index 0000000..8043159
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test DOMJIT accessors will represent their heap accesses.');
+var tests = [
+    "firstChild",
+    "lastChild",
+    "nextSibling",
+    "previousSibling",
+    "parentNode",
+].map(function (name) {
+    var func = `
+        return function ${name}(name, element, result) {
+            for (var i = 0; i < 1e4; ++i) {
+                if (element.${name} !== result)
+                    return false;
+                if (element.${name} !== result)
+                    return false;
+                if (element.${name} !== result)
+                    return false;
+                if (element.${name} !== result)
+                    return false;
+                if (element.${name} !== result)
+                    return false;
+            }
+            return true;
+        };
+    `;
+    return [ name, Function(func)() ];
+});
+
+for (var [name, func] of tests) {
+    shouldBeTrue(`func("${name}", document.getElementById("target"), document.getElementById("${name}"))`);
+}
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-accessor-licm-expected.txt b/LayoutTests/js/dom/domjit-accessor-licm-expected.txt
new file mode 100644 (file)
index 0000000..55a3bfd
--- /dev/null
@@ -0,0 +1,8 @@
+Test DOMJIT accessor will be LICM-ed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-accessor-licm.html b/LayoutTests/js/dom/domjit-accessor-licm.html
new file mode 100644 (file)
index 0000000..e563eba
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+<script>
+
+</script>
+</body>
+</html>
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test DOMJIT accessor will be LICM-ed.');
+
+function test() {
+    var div = document.createElement('div');
+    var ret = 0;
+    for (var i = 0; i < 1e4; ++i)
+        ret = div.nodeType;
+    return ret;
+}
+var result;
+(function () {
+    for (var i = 0; i < 100; ++i) {
+        result = test();
+        shouldBe(`result`, `Node.ELEMENT_NODE`, true);
+    }
+}());
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure-expected.txt b/LayoutTests/js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure-expected.txt
new file mode 100644 (file)
index 0000000..3622501
--- /dev/null
@@ -0,0 +1,9 @@
+Test function calls should not overlap with effects of DOMJIT's nodeType accessor since it is pure.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS test() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure.html b/LayoutTests/js/dom/domjit-accessor-node-type-effect-should-not-overlap-with-call-since-pure.html
new file mode 100644 (file)
index 0000000..e7c46a5
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description(`Test function calls should not overlap with effects of DOMJIT's nodeType accessor since it is pure.`);
+
+function test()
+{
+    var target = document.getElementById('target');
+    var firstChild = document.getElementById('firstChild');
+    var lastChild = document.getElementById('lastChild');
+    for (var i = 0; i < 1e4; ++i) {
+        var ret1 = target.nodeType;
+        target.appendChild(lastChild);
+        var ret2 = target.nodeType;
+        if (ret1 !== Node.ELEMENT_NODE || ret2 !== Node.ELEMENT_NODE)
+            return false;
+    }
+    return true;
+}
+
+shouldBeTrue(`test()`);
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 01cb294..87f73e5 100644 (file)
@@ -413,6 +413,9 @@ set(JavaScriptCore_SOURCES
     disassembler/udis86/udis86_syn-intel.c
     disassembler/udis86/udis86_syn.c
 
+    domjit/DOMJITAbstractHeap.cpp
+    domjit/DOMJITHeapRange.cpp
+
     ftl/FTLAbstractHeap.cpp
     ftl/FTLAbstractHeapRepository.cpp
     ftl/FTLAvailableRecovery.cpp
index 062eab0..f025d4e 100644 (file)
@@ -1,3 +1,125 @@
+2016-10-23  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add a way for DOMJIT::Patchpoint to express effects
+        https://bugs.webkit.org/show_bug.cgi?id=163657
+
+        Reviewed by Saam Barati.
+
+        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:
+
 2016-10-24  Alex Christensen  <achristensen@webkit.org>
 
         JSONParse should not crash with null Strings
index 97da376..b770bbb 100644 (file)
                E3555B8A1DAE03A500F36921 /* DOMJITCallDOMPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3555B891DAE03A200F36921 /* DOMJITCallDOMPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E355F3521B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */; };
                E355F3531B7DC85300C50DC5 /* ModuleLoaderPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E355F3511B7DC85300C50DC5 /* ModuleLoaderPrototype.h */; };
+               E35CA1531DBC3A5C00F83516 /* DOMJITHeapRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E35CA1511DBC3A5600F83516 /* DOMJITHeapRange.cpp */; };
+               E35CA1541DBC3A5C00F83516 /* DOMJITHeapRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA1521DBC3A5600F83516 /* DOMJITHeapRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E35CA1551DBC3A5F00F83516 /* DOMJITAbstractHeap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E35CA14F1DBC3A5600F83516 /* DOMJITAbstractHeap.cpp */; };
+               E35CA1561DBC3A5F00F83516 /* DOMJITAbstractHeap.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA1501DBC3A5600F83516 /* DOMJITAbstractHeap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E35E035F1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E35E035D1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp */; };
                E35E03601B7AB43E0073AD2A /* InspectorInstrumentationObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3794E751B77EB97005543AE /* ModuleAnalyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */; };
                E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */; };
                E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */; };
                E3C08E3C1DA41B810039478F /* DOMJITPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E3C79CAB1DB9A4DC00D1ECA4 /* DOMJITEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C79CAA1DB9A4D600D1ECA4 /* DOMJITEffect.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3D239C81B829C1C00BBEF67 /* JSModuleEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */; };
                E3D239C91B829C1C00BBEF67 /* JSModuleEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D239C71B829C1C00BBEF67 /* JSModuleEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3EF88721B66DF23003F26CB /* JSPropertyNameIterator.cpp */; };
                E3555B891DAE03A200F36921 /* DOMJITCallDOMPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITCallDOMPatchpoint.h; sourceTree = "<group>"; };
                E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleLoaderPrototype.cpp; sourceTree = "<group>"; };
                E355F3511B7DC85300C50DC5 /* ModuleLoaderPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleLoaderPrototype.h; sourceTree = "<group>"; };
+               E35CA14F1DBC3A5600F83516 /* DOMJITAbstractHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAbstractHeap.cpp; sourceTree = "<group>"; };
+               E35CA1501DBC3A5600F83516 /* DOMJITAbstractHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAbstractHeap.h; sourceTree = "<group>"; };
+               E35CA1511DBC3A5600F83516 /* DOMJITHeapRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITHeapRange.cpp; sourceTree = "<group>"; };
+               E35CA1521DBC3A5600F83516 /* DOMJITHeapRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITHeapRange.h; sourceTree = "<group>"; };
                E35E035D1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorInstrumentationObject.cpp; sourceTree = "<group>"; };
                E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorInstrumentationObject.h; sourceTree = "<group>"; };
                E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InspectorInstrumentationObject.js; sourceTree = "<group>"; };
                E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAccessCasePatchpointParams.cpp; sourceTree = "<group>"; };
                E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAccessCasePatchpointParams.h; sourceTree = "<group>"; };
                E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpoint.h; sourceTree = "<group>"; };
+               E3C79CAA1DB9A4D600D1ECA4 /* DOMJITEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITEffect.h; sourceTree = "<group>"; };
                E3CB1E241DA7540A00FA1E56 /* DOMJITSlowPathCalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITSlowPathCalls.h; sourceTree = "<group>"; };
                E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleEnvironment.cpp; sourceTree = "<group>"; };
                E3D239C71B829C1C00BBEF67 /* JSModuleEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleEnvironment.h; sourceTree = "<group>"; };
                E3FF752D1D9CE9EA00C7E16D /* domjit */ = {
                        isa = PBXGroup;
                        children = (
+                               E35CA14F1DBC3A5600F83516 /* DOMJITAbstractHeap.cpp */,
+                               E35CA1501DBC3A5600F83516 /* DOMJITAbstractHeap.h */,
                                E3555B891DAE03A200F36921 /* DOMJITCallDOMPatchpoint.h */,
+                               E3C79CAA1DB9A4D600D1ECA4 /* DOMJITEffect.h */,
                                E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */,
+                               E35CA1511DBC3A5600F83516 /* DOMJITHeapRange.cpp */,
+                               E35CA1521DBC3A5600F83516 /* DOMJITHeapRange.h */,
                                E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */,
                                E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */,
                                E37AD83B1DA4928000F3D412 /* DOMJITReg.h */,
                                0F96EBB316676EF6008BADE3 /* CodeBlockWithJITType.h in Headers */,
                                A77F1822164088B200640A47 /* CodeCache.h in Headers */,
                                99CC0B6318BE9950006CEBCC /* CodeGeneratorReplayInputs.py in Headers */,
+                               E3C79CAB1DB9A4DC00D1ECA4 /* DOMJITEffect.h in Headers */,
                                99CC0B6218BE9946006CEBCC /* CodeGeneratorReplayInputsTemplates.py in Headers */,
                                86E116B10FE75AC800B512BC /* CodeLocation.h in Headers */,
                                0FBD7E691447999600481315 /* CodeOrigin.h in Headers */,
                                AD2FCC1F1DB59CB200B3E736 /* WebAssemblyRuntimeErrorPrototype.lut.h in Headers */,
                                A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */,
                                9928FF3C18AC4AEC00B8CF12 /* JSReplayInputs.h in Headers */,
+                               E35CA1561DBC3A5F00F83516 /* DOMJITAbstractHeap.h in Headers */,
                                BC18C4260E16F5CD00B34460 /* JSRetainPtr.h in Headers */,
                                14874AE615EBDE4A002E3587 /* JSScope.h in Headers */,
                                0F33FCFB1C1625BE00323F67 /* B3CFG.h in Headers */,
                                7C008CE7187631B600955C24 /* Microtask.h in Headers */,
                                DC0184191D10C1890057B053 /* JITWorklist.h in Headers */,
                                86C568E211A213EE0007F7F0 /* MIPSAssembler.h in Headers */,
+                               E35CA1541DBC3A5C00F83516 /* DOMJITHeapRange.h in Headers */,
                                C4703CD7192844CC0013FBEA /* models.py in Headers */,
                                E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */,
                                E355F3531B7DC85300C50DC5 /* ModuleLoaderPrototype.h in Headers */,
                                0F61832B1C45BF070072450B /* AirCustom.cpp in Sources */,
                                0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */,
                                0FD3E40D1B618B6600C80E1E /* PropertyCondition.cpp in Sources */,
+                               E35CA1531DBC3A5C00F83516 /* DOMJITHeapRange.cpp in Sources */,
                                A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */,
                                14469DE8107EC7E700650446 /* PropertySlot.cpp in Sources */,
                                ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */,
                                8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */,
                                14280843107EC0930013E7B2 /* RegExpObject.cpp in Sources */,
                                14280844107EC0930013E7B2 /* RegExpPrototype.cpp in Sources */,
+                               E35CA1551DBC3A5F00F83516 /* DOMJITAbstractHeap.cpp in Sources */,
                                6540C7A01B82E1C3000F6B79 /* RegisterAtOffset.cpp in Sources */,
                                6540C7A11B82E1C3000F6B79 /* RegisterAtOffsetList.cpp in Sources */,
                                0FC3141518146D7000033232 /* RegisterSet.cpp in Sources */,
index cddf1c6..847128b 100644 (file)
@@ -1471,11 +1471,11 @@ void AccessCase::emitDOMJITGetter(AccessGenerationState& state, GPRReg baseForGe
     JSGlobalObject* globalObjectForDOMJIT = structure()->globalObject();
 
     regs.append(paramValueRegs);
+    regs.append(paramBaseGPR);
     if (patchpoint->requireGlobalObject) {
         ASSERT(paramGlobalObjectGPR != InvalidGPRReg);
         regs.append(DOMJIT::Value(paramGlobalObjectGPR, globalObjectForDOMJIT));
     }
-    regs.append(paramBaseGPR);
 
     if (patchpoint->numGPScratchRegisters) {
         unsigned i = 0;
index 1e11019..cd694bb 100644 (file)
@@ -45,6 +45,10 @@ void AbstractHeap::dump(PrintStream& out) const
     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(), ")");
 }
 
index 0abd502..97c3a34 100644 (file)
@@ -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 @@ namespace JSC { namespace DFG {
     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 @@ public:
     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)
index a12f09c..f09d41b 100644 (file)
@@ -2289,10 +2289,13 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         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);
index 4884206..0603168 100644 (file)
@@ -2673,6 +2673,13 @@ bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, const GetByIdVaria
     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 @@ bool ByteCodeParser::handleDOMJITGetter(int resultOperand, const GetByIdVariant&
     // 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;
 }
 
index d4630e3..ce3398e 100644 (file)
@@ -81,6 +81,23 @@ bool ClobberSet::overlaps(AbstractHeap heap) const
 {
     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))
index 729f39b..f93e27f 100644 (file)
@@ -52,11 +52,11 @@ public:
     
     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 @@ public:
     void dump(PrintStream&) const;
     
 private:
+    bool contains(AbstractHeap) const;
+
     HashSet<AbstractHeap> setOf(bool direct) const;
     
     // Maps heap to:
index f929337..f2625be 100644 (file)
@@ -33,6 +33,7 @@
 #include "DFGHeapLocation.h"
 #include "DFGLazyNode.h"
 #include "DFGPureValue.h"
+#include "DOMJITCallDOMPatchpoint.h"
 
 namespace JSC { namespace DFG {
 
@@ -907,10 +908,34 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         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:
index 3f13842..f35b66c 100644 (file)
@@ -118,7 +118,6 @@ bool doesGC(Graph& graph, Node* node)
     case CheckStructure:
     case GetExecutable:
     case GetButterfly:
-    case CallDOM:
     case CheckDOM:
     case CheckArray:
     case GetScope:
@@ -299,6 +298,7 @@ bool doesGC(Graph& graph, Node* node)
     case StringReplaceRegExp:
     case CreateRest:
     case ToLowerCase:
+    case CallDOM:
         return true;
         
     case MultiPutByOffset:
index 33c0cf1..dbc1017 100644 (file)
@@ -1711,11 +1711,10 @@ private:
             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;
         }
 
index 76b2bae..f957f5c 100644 (file)
@@ -901,6 +901,7 @@ public:
     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;
index 8470637..9b2292d 100644 (file)
@@ -152,6 +152,9 @@ void printInternal(PrintStream& out, LocationKind kind)
     case MapHasLoc:
         out.print("MapHasLoc");
         return;
+    case DOMStateLoc:
+        out.print("DOMStateLoc");
+        return;
     }
     
     RELEASE_ASSERT_NOT_REACHED();
index 704d191..6357be1 100644 (file)
@@ -60,7 +60,8 @@ enum LocationKind {
     StackPayloadLoc,
     MapBucketLoc,
     JSMapGetLoc,
-    MapHasLoc
+    MapHasLoc,
+    DOMStateLoc,
 };
 
 class HeapLocation {
index c9411d5..0d1a4b5 100644 (file)
@@ -59,6 +59,7 @@
 namespace JSC {
 
 namespace DOMJIT {
+class GetterSetter;
 class Patchpoint;
 class CallDOMPatchpoint;
 }
@@ -231,6 +232,11 @@ struct StackAccessData {
     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 @@ public:
         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
index 19b2825..75aa62e 100644 (file)
@@ -404,7 +404,7 @@ namespace JSC { namespace DFG {
     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).
index 5e64baf..6ccffb5 100644 (file)
@@ -7225,7 +7225,7 @@ static void allocateTemporaryRegistersForPatchpoint(SpeculativeJIT* jit, Vector<
 
 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 @@ void SpeculativeJIT::compileCallDOM(Node* node)
     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);
diff --git a/Source/JavaScriptCore/domjit/DOMJITAbstractHeap.cpp b/Source/JavaScriptCore/domjit/DOMJITAbstractHeap.cpp
new file mode 100644 (file)
index 0000000..f4855b9
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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 "DOMJITAbstractHeap.h"
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+void AbstractHeap::compute(unsigned begin)
+{
+    unsigned current = begin;
+    // Increment the end of the range.
+    if (m_children.isEmpty()) {
+        m_range = HeapRange(begin, current + 1);
+        return;
+    }
+    for (auto& child : m_children) {
+        child->compute(current);
+        current = child->range().end();
+    }
+    ASSERT(begin < UINT16_MAX);
+    ASSERT(current <= UINT16_MAX);
+    m_range = HeapRange(begin, current);
+}
+
+void AbstractHeap::dump(PrintStream& out) const
+{
+    shallowDump(out);
+    if (m_parent)
+        out.print("->", *m_parent);
+}
+
+void AbstractHeap::shallowDump(PrintStream& out) const
+{
+    out.print(m_name, "<", m_range, ">");
+}
+
+void AbstractHeap::deepDump(PrintStream& out, unsigned indent) const
+{
+    auto printIndent = [&] () {
+        for (unsigned i = indent; i--;)
+            out.print("    ");
+    };
+
+    printIndent();
+    shallowDump(out);
+
+    if (m_children.isEmpty()) {
+        out.print("\n");
+        return;
+    }
+
+    out.print(":\n");
+    for (auto* child : m_children)
+        child->deepDump(out, indent + 1);
+}
+
+} }
+
+#endif
diff --git a/Source/JavaScriptCore/domjit/DOMJITAbstractHeap.h b/Source/JavaScriptCore/domjit/DOMJITAbstractHeap.h
new file mode 100644 (file)
index 0000000..be87b07
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include "DOMJITHeapRange.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+class AbstractHeap {
+public:
+    AbstractHeap(const String& name)
+        : m_name(name)
+    {
+    }
+
+    void setParent(AbstractHeap* parent)
+    {
+        ASSERT(!m_parent);
+        parent->m_children.append(this);
+        m_parent = parent;
+    }
+
+    bool isRoot() const { return !m_parent; }
+
+    JS_EXPORT_PRIVATE void compute(unsigned begin);
+
+    bool isComputed() const { return !!m_range; }
+    HeapRange range() const { return m_range; }
+
+    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
+    JS_EXPORT_PRIVATE void shallowDump(PrintStream&) const;
+    JS_EXPORT_PRIVATE void deepDump(PrintStream&, unsigned indent = 0) const;
+
+private:
+    String m_name;
+    AbstractHeap* m_parent { nullptr };
+    Vector<AbstractHeap*> m_children { };
+    HeapRange m_range;
+};
+
+} }
+
+#endif
index 695820c..4edb233 100644 (file)
@@ -27,6 +27,7 @@
 
 #if ENABLE(JIT)
 
+#include "DOMJITEffect.h"
 #include "DOMJITPatchpoint.h"
 #include "RegisterSet.h"
 
@@ -45,6 +46,8 @@ public:
     // https://bugs.webkit.org/show_bug.cgi?id=162980
     bool requireGlobalObject { true };
 
+    Effect effect { };
+
 private:
     CallDOMPatchpoint() = default;
 };
diff --git a/Source/JavaScriptCore/domjit/DOMJITEffect.h b/Source/JavaScriptCore/domjit/DOMJITEffect.h
new file mode 100644 (file)
index 0000000..59e300c
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include "DOMJITHeapRange.h"
+#include <wtf/Optional.h>
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+struct Effect {
+    HeapRange reads { HeapRange::top() };
+    HeapRange writes { HeapRange::top() };
+    Optional<HeapRange> def;
+
+    static Effect forReadWrite(HeapRange readRange, HeapRange writeRange)
+    {
+        Effect effect;
+        effect.reads = readRange;
+        effect.writes = writeRange;
+        return effect;
+    }
+
+    static Effect forPure()
+    {
+        Effect effect;
+        effect.reads = HeapRange::none();
+        effect.writes = HeapRange::none();
+        effect.def = HeapRange::none();
+        return effect;
+    }
+
+    static Effect forDef(HeapRange def)
+    {
+        Effect effect;
+        effect.reads = def;
+        effect.writes = HeapRange::none();
+        effect.def = def;
+        return effect;
+    }
+
+    static Effect forDef(HeapRange def, HeapRange readRange, HeapRange writeRange)
+    {
+        Effect effect;
+        effect.reads = readRange;
+        effect.writes = writeRange;
+        effect.def = def;
+        return effect;
+    }
+
+    bool mustGenerate() const
+    {
+        return !!writes;
+    }
+};
+
+} }
+
+#endif
diff --git a/Source/JavaScriptCore/domjit/DOMJITHeapRange.cpp b/Source/JavaScriptCore/domjit/DOMJITHeapRange.cpp
new file mode 100644 (file)
index 0000000..d7b1123
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 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 "DOMJITHeapRange.h"
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+void HeapRange::dump(PrintStream& out) const
+{
+    out.printf("0x%x-0x%x", static_cast<unsigned>(begin()), static_cast<unsigned>(end()));
+}
+
+} }
+
+#endif
diff --git a/Source/JavaScriptCore/domjit/DOMJITHeapRange.h b/Source/JavaScriptCore/domjit/DOMJITHeapRange.h
new file mode 100644 (file)
index 0000000..fb93999
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <wtf/MathExtras.h>
+#include <wtf/PrintStream.h>
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+class HeapRange {
+public:
+    constexpr HeapRange()
+        : m_begin(UINT16_MAX)
+        , m_end(UINT16_MAX)
+    {
+    }
+
+    HeapRange(uint16_t begin, uint16_t end)
+        : m_begin(begin)
+        , m_end(end)
+    {
+        ASSERT_WITH_MESSAGE(begin <= end, "begin <= end is the invariant of this HeapRange.");
+    }
+
+private:
+    enum ConstExprTag { ConstExpr };
+    constexpr HeapRange(ConstExprTag, uint16_t begin, uint16_t end)
+        : m_begin(begin)
+        , m_end(end)
+    {
+    }
+
+    template<uint16_t begin, uint16_t end>
+    static constexpr HeapRange fromConstant()
+    {
+        static_assert(begin <= end, "begin <= end is the invariant of this HeapRange.");
+        return HeapRange(ConstExpr, begin, end);
+    }
+
+public:
+    enum RawRepresentationTag { RawRepresentation };
+    explicit constexpr HeapRange(RawRepresentationTag, uint32_t value)
+        : m_raw(value)
+    {
+    }
+
+    static HeapRange fromRaw(uint32_t value)
+    {
+        return HeapRange(RawRepresentation, value);
+    }
+
+    uint16_t begin() const { return m_begin; }
+    uint16_t end() const { return m_end; }
+    uint32_t rawRepresentation() { return m_raw; }
+
+    explicit operator bool() const
+    {
+        return m_begin != m_end;
+    }
+
+    bool operator==(const HeapRange& other) const
+    {
+        return m_begin == other.m_begin && m_end == other.m_end;
+    }
+
+    static constexpr HeapRange top() { return fromConstant<0, UINT16_MAX>(); }
+    static constexpr HeapRange none() { return fromConstant<UINT16_MAX, UINT16_MAX>(); } // Empty range.
+
+    bool isStrictSubtypeOf(const HeapRange& other) const
+    {
+        if (!*this || !other)
+            return false;
+        if (*this == other)
+            return false;
+        return other.m_begin <= m_begin && m_end <= other.m_end;
+    }
+
+    bool isSubtypeOf(const HeapRange& other) const
+    {
+        if (!*this || !other)
+            return false;
+        if (*this == other)
+            return true;
+        return isStrictSubtypeOf(other);
+    }
+
+    bool overlaps(const HeapRange& other) const
+    {
+        return WTF::rangesOverlap(m_begin, m_end, other.m_begin, other.m_end);
+    }
+
+    JS_EXPORT_PRIVATE void dump(PrintStream&) const;
+
+private:
+    union {
+        struct {
+            uint16_t m_begin;
+            uint16_t m_end;
+        };
+        uint32_t m_raw;
+    };
+};
+
+} }
+
+#endif
index a657e06..8ca44f8 100644 (file)
@@ -9064,25 +9064,24 @@ private:
 
     void compileCallDOM()
     {
-        DOMJIT::CallDOMPatchpoint* domJIT = m_node->callDOMPatchpoint();
-        int childIndex = 0;
+        DOMJIT::CallDOMPatchpoint* domJIT = m_node->callDOMData()->patchpoint;
+
+        Edge& baseEdge = m_node->child1();
+        LValue base = lowCell(baseEdge);
+        JSValue baseConstant = m_state.forNode(baseEdge).value();
 
         LValue globalObject;
         JSValue globalObjectConstant;
         if (domJIT->requireGlobalObject) {
-            Edge& globalObjectEdge = m_graph.varArgChild(m_node, childIndex++);
+            Edge& globalObjectEdge = m_node->child2();
             globalObject = lowCell(globalObjectEdge);
             globalObjectConstant = m_state.forNode(globalObjectEdge).value();
         }
 
-        Edge& baseEdge = m_graph.varArgChild(m_node, childIndex++);
-        LValue base = lowCell(baseEdge);
-        JSValue baseConstant = m_state.forNode(baseEdge).value();
-
         PatchpointValue* patchpoint = m_out.patchpoint(Int64);
+        patchpoint->appendSomeRegister(base);
         if (domJIT->requireGlobalObject)
             patchpoint->appendSomeRegister(globalObject);
-        patchpoint->appendSomeRegister(base);
         patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
         patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
         RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
@@ -9101,11 +9100,10 @@ private:
                 Vector<FPRReg> fpScratch;
                 Vector<DOMJIT::Value> regs;
 
-                int childIndex = 1;
                 regs.append(JSValueRegs(params[0].gpr()));
+                regs.append(DOMJIT::Value(params[1].gpr(), baseConstant));
                 if (domJIT->requireGlobalObject)
-                    regs.append(DOMJIT::Value(params[childIndex++].gpr(), globalObjectConstant));
-                regs.append(DOMJIT::Value(params[childIndex++].gpr(), baseConstant));
+                    regs.append(DOMJIT::Value(params[2].gpr(), globalObjectConstant));
 
                 for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
                     gpScratch.append(params.gpScratch(i));
index a8e7da4..5eb4d04 100644 (file)
@@ -733,7 +733,7 @@ public:
             patchpoint->numFPScratchRegisters = 3;
             patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
                 JSValueRegs results = params[0].jsValueRegs();
-                GPRReg domGPR = params[2].gpr();
+                GPRReg domGPR = params[1].gpr();
                 for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
                     jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i));
 
index 32282ac..773c36c 100644 (file)
@@ -1,3 +1,15 @@
+2016-10-23  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add a way for DOMJIT::Patchpoint to express effects
+        https://bugs.webkit.org/show_bug.cgi?id=163657
+
+        Reviewed by Saam Barati.
+
+        Simplify nonEmptyRangesOverlap.
+
+        * wtf/MathExtras.h:
+        (WTF::nonEmptyRangesOverlap):
+
 2016-10-23  Chris Dumez  <cdumez@apple.com>
 
         Another unreviewed attempt to fix the WatchOS / TvOS build after r207585.
index 1d2fc18..c1093fa 100644 (file)
@@ -444,12 +444,8 @@ inline bool nonEmptyRangesOverlap(T leftMin, T leftMax, T rightMin, T rightMax)
 {
     ASSERT(leftMin < leftMax);
     ASSERT(rightMin < rightMax);
-    
-    if (leftMin <= rightMin && leftMax > rightMin)
-        return true;
-    if (rightMin <= leftMin && rightMax > leftMin)
-        return true;
-    return false;
+
+    return leftMax > rightMin && rightMax > leftMin;
 }
 
 // Pass ranges with the min being inclusive and the max being exclusive. For example, this should
index e550902..078e145 100644 (file)
@@ -1536,6 +1536,7 @@ set(WebCore_SOURCES
 
     dom/default/PlatformMessagePortChannel.cpp
 
+    domjit/DOMJITAbstractHeapRepository.cpp
     domjit/JSNodeDOMJIT.cpp
 
     editing/AlternativeTextController.cpp
index d5f55f6..b6d69c5 100644 (file)
@@ -1,3 +1,55 @@
+2016-10-23  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add a way for DOMJIT::Patchpoint to express effects
+        https://bugs.webkit.org/show_bug.cgi?id=163657
+
+        Reviewed by Saam Barati.
+
+        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):
+
 2016-10-24  Dave Hyatt  <hyatt@apple.com>
 
         [CSS Parser] Fix :lang argument parsing
diff --git a/Source/WebCore/ForwardingHeaders/domjit/DOMJITAbstractHeap.h b/Source/WebCore/ForwardingHeaders/domjit/DOMJITAbstractHeap.h
new file mode 100644 (file)
index 0000000..bfb5422
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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 WebCore_FWD_DOMJITAbstractHeap_h
+#define WebCore_FWD_DOMJITAbstractHeap_h
+#include <JavaScriptCore/DOMJITAbstractHeap.h>
+#endif
diff --git a/Source/WebCore/ForwardingHeaders/domjit/DOMJITEffect.h b/Source/WebCore/ForwardingHeaders/domjit/DOMJITEffect.h
new file mode 100644 (file)
index 0000000..5dc2ef6
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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 WebCore_FWD_DOMJITEffect_h
+#define WebCore_FWD_DOMJITEffect_h
+#include <JavaScriptCore/DOMJITEffect.h>
+#endif
diff --git a/Source/WebCore/ForwardingHeaders/domjit/DOMJITHeapRange.h b/Source/WebCore/ForwardingHeaders/domjit/DOMJITHeapRange.h
new file mode 100644 (file)
index 0000000..237fa5e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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 WebCore_FWD_DOMJITHeapRange_h
+#define WebCore_FWD_DOMJITHeapRange_h
+#include <JavaScriptCore/DOMJITHeapRange.h>
+#endif
index 9c54e31..dd67ba7 100644 (file)
                E1FF8F6D180DB5BE00132674 /* CryptoAlgorithmRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FF8F6B180DB5BE00132674 /* CryptoAlgorithmRegistry.h */; };
                E3150EA61DA7219000194012 /* JSNodeDOMJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */; };
                E3150EA71DA7219300194012 /* DOMJITHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = E3150EA51DA7218D00194012 /* DOMJITHelpers.h */; };
+               E35CA14D1DBC3A3F00F83516 /* DOMJITAbstractHeapRepository.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E35CA14B1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.cpp */; };
+               E35CA14E1DBC3A4200F83516 /* DOMJITAbstractHeapRepository.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA14C1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.h */; };
                E377FE4D1DADE16500CDD025 /* NodeConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D049931DADC04500718F3C /* NodeConstants.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E38838981BAD145F00D62EE3 /* ScriptModuleLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38838941BAD145F00D62EE3 /* ScriptModuleLoader.cpp */; };
                E38838991BAD145F00D62EE3 /* ScriptModuleLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = E38838951BAD145F00D62EE3 /* ScriptModuleLoader.h */; };
                E1FF8F6A180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmRegistry.cpp; sourceTree = "<group>"; };
                E1FF8F6B180DB5BE00132674 /* CryptoAlgorithmRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmRegistry.h; sourceTree = "<group>"; };
                E3150EA51DA7218D00194012 /* DOMJITHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITHelpers.h; sourceTree = "<group>"; };
+               E35CA14B1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAbstractHeapRepository.cpp; sourceTree = "<group>"; };
+               E35CA14C1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAbstractHeapRepository.h; sourceTree = "<group>"; };
                E38838941BAD145F00D62EE3 /* ScriptModuleLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptModuleLoader.cpp; sourceTree = "<group>"; };
                E38838951BAD145F00D62EE3 /* ScriptModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptModuleLoader.h; sourceTree = "<group>"; };
                E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNodeDOMJIT.cpp; sourceTree = "<group>"; };
                E3AFA9631DA6E8AF002861BD /* domjit */ = {
                        isa = PBXGroup;
                        children = (
+                               E35CA14B1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.cpp */,
+                               E35CA14C1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.h */,
                                E3150EA51DA7218D00194012 /* DOMJITHelpers.h */,
                                E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */,
                        );
                                439046E812DA25E800AF80A2 /* RenderMathMLScripts.h in Headers */,
                                439046EC12DA25E800AF80A9 /* RenderMathMLToken.h in Headers */,
                                439046EA12DA25E800AF80A2 /* RenderMathMLUnderOver.h in Headers */,
+                               E35CA14E1DBC3A4200F83516 /* DOMJITAbstractHeapRepository.h in Headers */,
                                E4C279590CF9741900E97B98 /* RenderMedia.h in Headers */,
                                DEBCCDD216646E8200A452E1 /* RenderMediaControlElements.h in Headers */,
                                41FA303F1316C29C00C0BFC5 /* RenderMediaControls.h in Headers */,
                                B2C3DA620D006CD600EF6F26 /* FontCache.cpp in Sources */,
                                1C3969D01B74211E002BCFA7 /* FontCacheCoreText.cpp in Sources */,
                                3727DFD5142AAE4500D449CB /* FontCacheIOS.mm in Sources */,
+                               E35CA14D1DBC3A3F00F83516 /* DOMJITAbstractHeapRepository.cpp in Sources */,
                                B2AFFC7C0D00A5C10030074D /* FontCacheMac.mm in Sources */,
                                B2C3DA600D006CD600EF6F26 /* FontCascade.cpp in Sources */,
                                B2AFFC800D00A5C10030074D /* FontCascadeCocoa.mm in Sources */,
diff --git a/Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp b/Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp
new file mode 100644 (file)
index 0000000..1f4fbfa
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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 "DOMJITAbstractHeapRepository.h"
+
+#include <domjit/DOMJITAbstractHeap.h>
+#include <wtf/DataLog.h>
+#include <wtf/NeverDestroyed.h>
+
+#if ENABLE(JIT)
+
+namespace WebCore { namespace DOMJIT {
+
+static const bool verbose = false;
+
+AbstractHeapRepository::AbstractHeapRepository()
+{
+    JSC::DOMJIT::AbstractHeap DOMHeap("DOM");
+#define DOMJIT_DEFINE_HEAP(name, parent) JSC::DOMJIT::AbstractHeap name##Heap(#name);
+    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_DEFINE_HEAP)
+#undef DOMJIT_DEFINE_HEAP
+
+#define DOMJIT_INITIALIZE_HEAP(name, parent) name##Heap.setParent(&parent##Heap);
+    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_INITIALIZE_HEAP)
+#undef DOMJIT_INITIALIZE_HEAP
+
+    DOMHeap.compute(0);
+
+#define DOMJIT_INITIALIZE_MEMBER(name, parent) name = name##Heap.range();
+    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_INITIALIZE_MEMBER)
+#undef DOMJIT_INITIALIZE_MEMBER
+
+    if (verbose) {
+        dataLog("DOMJIT Heap Repository:\n");
+        DOMHeap.deepDump(WTF::dataFile());
+    }
+}
+
+const AbstractHeapRepository& AbstractHeapRepository::instance()
+{
+    static NeverDestroyed<AbstractHeapRepository> repository;
+    return repository.get();
+}
+
+} }
+
+#endif
diff --git a/Source/WebCore/domjit/DOMJITAbstractHeapRepository.h b/Source/WebCore/domjit/DOMJITAbstractHeapRepository.h
new file mode 100644 (file)
index 0000000..ec64490
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <domjit/DOMJITHeapRange.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Noncopyable.h>
+
+#if ENABLE(JIT)
+
+namespace WebCore { namespace DOMJIT {
+
+// Describe your abstract heap hierarchy here.
+// V(AbstractHeapName, Parent)
+#define DOMJIT_ABSTRACT_HEAP_LIST(V) \
+    V(Node, DOM) \
+    V(Node_firstChild, Node) \
+    V(Node_lastChild, Node) \
+    V(Node_parentNode, Node) \
+    V(Node_nextSibling, Node) \
+    V(Node_previousSibling, Node) \
+
+
+class AbstractHeapRepository {
+WTF_MAKE_NONCOPYABLE(AbstractHeapRepository);
+public:
+    friend class NeverDestroyed<AbstractHeapRepository>;
+    static const AbstractHeapRepository& instance();
+
+    JSC::DOMJIT::HeapRange DOM;
+
+#define DOMJIT_DEFINE_MEMBER(name, parent) JSC::DOMJIT::HeapRange name;
+    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_DEFINE_MEMBER)
+#undef DOMJIT_DEFINE_MEMBER
+
+private:
+    AbstractHeapRepository();
+};
+
+} }
+
+#endif
index 1806b2a..a85bcdc 100644 (file)
@@ -32,8 +32,7 @@
 
 #if ENABLE(JIT)
 
-namespace WebCore {
-namespace DOMJITHelpers {
+namespace WebCore { namespace DOMJIT {
 
 using JSC::CCallHelpers;
 using JSC::GPRReg;
index b9693ac..87f4db7 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(JIT)
 
+#include "DOMJITAbstractHeapRepository.h"
 #include "DOMJITHelpers.h"
 #include "JSDOMWrapper.h"
 #include "Node.h"
@@ -52,15 +53,16 @@ EncodedJSValue JIT_OPERATION toWrapperSlow(JSC::ExecState* exec, JSC::JSGlobalOb
 }
 
 template<typename WrappedNode>
-static Ref<DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
+static Ref<JSC::DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
 {
-    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
+    Ref<JSC::DOMJIT::CallDOMPatchpoint> patchpoint = JSC::DOMJIT::CallDOMPatchpoint::create();
     patchpoint->numGPScratchRegisters = 1;
-    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
+    patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
         JSValueRegs result = params[0].jsValueRegs();
-        GPRReg globalObject = params[1].gpr();
-        GPRReg node = params[2].gpr();
+        GPRReg node = params[1].gpr();
+        GPRReg globalObject = params[2].gpr();
         GPRReg scratch = params.gpScratch(0);
+        JSValue globalObjectValue = params[2].value();
 
         CCallHelpers::JumpList nullCases;
         // Load a wrapped object. "node" should be already type checked by CheckDOM.
@@ -72,7 +74,7 @@ static Ref<DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t off
         jit.loadPtr(CCallHelpers::Address(scratch, offset), scratch);
         nullCases.append(jit.branchTestPtr(CCallHelpers::Zero, scratch));
 
-        DOMJITHelpers::toWrapper<WrappedNode>(jit, params, scratch, globalObject, result, toWrapperSlow<WrappedNode>, params[1].value());
+        DOMJIT::toWrapper<WrappedNode>(jit, params, scratch, globalObject, result, toWrapperSlow<WrappedNode>, globalObjectValue);
         CCallHelpers::Jump done = jit.jump();
 
         nullCases.link(&jit);
@@ -83,83 +85,99 @@ static Ref<DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t off
     return patchpoint;
 }
 
-static Ref<DOMJIT::Patchpoint> checkNode()
+static Ref<JSC::DOMJIT::Patchpoint> checkNode()
 {
-    Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
-    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
+    Ref<JSC::DOMJIT::Patchpoint> patchpoint = JSC::DOMJIT::Patchpoint::create();
+    patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
         CCallHelpers::JumpList failureCases;
-        failureCases.append(DOMJITHelpers::branchIfNotNode(jit, params[0].gpr()));
+        failureCases.append(DOMJIT::branchIfNotNode(jit, params[0].gpr()));
         return failureCases;
     });
     return patchpoint;
 }
 
 // Node#firstChild.
-Ref<DOMJIT::Patchpoint> NodeFirstChildDOMJIT::checkDOM()
+Ref<JSC::DOMJIT::Patchpoint> NodeFirstChildDOMJIT::checkDOM()
 {
     return checkNode();
 }
 
-Ref<DOMJIT::CallDOMPatchpoint> NodeFirstChildDOMJIT::callDOM()
+Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeFirstChildDOMJIT::callDOM()
 {
-    return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
+    const auto& heap = DOMJIT::AbstractHeapRepository::instance();
+    auto patchpoint = createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_firstChild);
+    return patchpoint;
 }
 
 // Node#lastChild.
-Ref<DOMJIT::Patchpoint> NodeLastChildDOMJIT::checkDOM()
+Ref<JSC::DOMJIT::Patchpoint> NodeLastChildDOMJIT::checkDOM()
 {
     return checkNode();
 }
 
-Ref<DOMJIT::CallDOMPatchpoint> NodeLastChildDOMJIT::callDOM()
+Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeLastChildDOMJIT::callDOM()
 {
-    return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
+    const auto& heap = DOMJIT::AbstractHeapRepository::instance();
+    auto patchpoint = createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_lastChild);
+    return patchpoint;
 }
 
 // Node#nextSibling.
-Ref<DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::checkDOM()
+Ref<JSC::DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::checkDOM()
 {
     return checkNode();
 }
 
-Ref<DOMJIT::CallDOMPatchpoint> NodeNextSiblingDOMJIT::callDOM()
+Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeNextSiblingDOMJIT::callDOM()
 {
-    return createCallDOMForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+    const auto& heap = DOMJIT::AbstractHeapRepository::instance();
+    auto patchpoint = createCallDOMForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_nextSibling);
+    return patchpoint;
 }
 
 // Node#previousSibling.
-Ref<DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::checkDOM()
+Ref<JSC::DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::checkDOM()
 {
     return checkNode();
 }
 
-Ref<DOMJIT::CallDOMPatchpoint> NodePreviousSiblingDOMJIT::callDOM()
+Ref<JSC::DOMJIT::CallDOMPatchpoint> NodePreviousSiblingDOMJIT::callDOM()
 {
-    return createCallDOMForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+    const auto& heap = DOMJIT::AbstractHeapRepository::instance();
+    auto patchpoint = createCallDOMForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_previousSibling);
+    return patchpoint;
 }
 
 // Node#parentNode.
-Ref<DOMJIT::Patchpoint> NodeParentNodeDOMJIT::checkDOM()
+Ref<JSC::DOMJIT::Patchpoint> NodeParentNodeDOMJIT::checkDOM()
 {
     return checkNode();
 }
 
-Ref<DOMJIT::CallDOMPatchpoint> NodeParentNodeDOMJIT::callDOM()
+Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeParentNodeDOMJIT::callDOM()
 {
-    return createCallDOMForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+    const auto& heap = DOMJIT::AbstractHeapRepository::instance();
+    auto patchpoint = createCallDOMForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_parentNode);
+    return patchpoint;
 }
 
 // Node#nodeType.
-Ref<DOMJIT::Patchpoint> NodeNodeTypeDOMJIT::checkDOM()
+Ref<JSC::DOMJIT::Patchpoint> NodeNodeTypeDOMJIT::checkDOM()
 {
     return checkNode();
 }
 
-Ref<DOMJIT::CallDOMPatchpoint> NodeNodeTypeDOMJIT::callDOM()
+Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeNodeTypeDOMJIT::callDOM()
 {
-    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
+    Ref<JSC::DOMJIT::CallDOMPatchpoint> patchpoint = JSC::DOMJIT::CallDOMPatchpoint::create();
+    patchpoint->effect = JSC::DOMJIT::Effect::forPure();
     patchpoint->requireGlobalObject = false;
-    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
+    patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
         JSValueRegs result = params[0].jsValueRegs();
         GPRReg node = params[1].gpr();
         jit.load8(CCallHelpers::Address(node, JSC::JSCell::typeInfoTypeOffset()), result.payloadGPR());