<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[207932] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/207932">207932</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2016-10-26 20:42:13 -0700 (Wed, 26 Oct 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[DOMJIT] Implement Node::ownerDocument
https://bugs.webkit.org/show_bug.cgi?id=164004

Reviewed by Darin Adler.

Source/WebCore:

Test: js/dom/domjit-accessor-owner-document.html

Implement Node.ownerDocument DOMJIT accessor.
According to the result of the profiler, jQuery's prop()
function is frequently called in Ember.js SpeedoMeter.
And this function calls jQuery.isXMLDoc(). And this isXMLDoc()
function calls element.ownerDocument accessor. And our WebKit
inspector also uses ownerDocument accessor frequently.

Interesting thing is this ownerDocument functionality is used
in CSSJIT, so CSSJIT has similar helper function to look up the
owner document of the element. As a result, all the necessary
functionality is already implemented, DOMJIT just utilizes it.
For example, Node::treeScopeMemoryOffset() and
TreeScope::documentScopeMemoryOffset() is implemented before this
patch.

In the future, we will convert CSSJIT's Assembler&amp; to CCallHelpers&amp;
and share the code with DOMJIT[1].

[1]: https://bugs.webkit.org/show_bug.cgi?id=164006

* dom/Node.idl:
* domjit/DOMJITAbstractHeapRepository.h:
* domjit/JSNodeDOMJIT.cpp:
(WebCore::NodeOwnerDocumentDOMJIT::checkDOM):
(WebCore::NodeOwnerDocumentDOMJIT::callDOM):

LayoutTests:

* js/dom/domjit-accessor-owner-document-expected.txt: Added.
* js/dom/domjit-accessor-owner-document.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomNodeidl">trunk/Source/WebCore/dom/Node.idl</a></li>
<li><a href="#trunkSourceWebCoredomjitDOMJITAbstractHeapRepositoryh">trunk/Source/WebCore/domjit/DOMJITAbstractHeapRepository.h</a></li>
<li><a href="#trunkSourceWebCoredomjitJSNodeDOMJITcpp">trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsdomdomjitaccessorownerdocumentexpectedtxt">trunk/LayoutTests/js/dom/domjit-accessor-owner-document-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsdomdomjitaccessorownerdocumenthtml">trunk/LayoutTests/js/dom/domjit-accessor-owner-document.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (207931 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-10-27 03:13:21 UTC (rev 207931)
+++ trunk/LayoutTests/ChangeLog        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-10-26  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        [DOMJIT] Implement Node::ownerDocument
+        https://bugs.webkit.org/show_bug.cgi?id=164004
+
+        Reviewed by Darin Adler.
+
+        * js/dom/domjit-accessor-owner-document-expected.txt: Added.
+        * js/dom/domjit-accessor-owner-document.html: Added.
+
</ins><span class="cx"> 2016-10-26  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Replace IDBKeyPath with a WTF::Variant
</span></span></pre></div>
<a id="trunkLayoutTestsjsdomdomjitaccessorownerdocumentexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dom/domjit-accessor-owner-document-expected.txt (0 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/domjit-accessor-owner-document-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-owner-document-expected.txt        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -0,0 +1,109 @@
</span><ins>+Test DOMJIT nodeType accessor works.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS (
+            function testElement(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testAttr(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testText(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testCDATA(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testProcessingInstruction(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testComment(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testDocument(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testXMLDocument(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testDocumentType(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+PASS (
+            function testDocumentFragment(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        )(target, result) is true
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsdomdomjitaccessorownerdocumenthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dom/domjit-accessor-owner-document.html (0 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dom/domjit-accessor-owner-document.html                                (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-owner-document.html        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;iframe id=&quot;xmlframe&quot; onload=&quot;frameLoaded()&quot; style=&quot;height:0px&quot; src=&quot;data:application/xhtml+xml,&lt;?xml version='1.0' encoding='UTF-8'?&gt;&lt;body/&gt;&quot;&gt;&lt;/iframe&gt;
+&lt;script&gt;
+description('Test DOMJIT nodeType accessor works.');
+
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+var target = null;
+var result = null;
+function runTest()
+{
+    var xmlDocument = document.getElementById('xmlframe').contentDocument;
+    var targets = [
+        ['Element', document.body, document],
+        ['Attr', document.createAttribute('Cocoa'), document],
+        ['Text', document.createTextNode('Cocoa'), document],
+        ['CDATA', xmlDocument.createCDATASection('test'), xmlDocument],
+        ['ProcessingInstruction', xmlDocument.createProcessingInstruction('target', 'test'), xmlDocument],
+        ['Comment', document.createComment('Cocoa'), document],
+        ['Document', document, null],
+        ['XMLDocument', xmlDocument, null],
+        ['DocumentType', document.doctype, document],
+        ['DocumentFragment', document.createDocumentFragment(), document],
+    ];
+
+    for ([name, target, result] of targets) {
+        var text = `
+            function test${name}(element, result)
+            {
+                for (var i = 0; i &lt; 1e4; ++i) {
+                    if (element.ownerDocument !== result)
+                        return false;
+                }
+                return true;
+            }
+        `;
+        shouldBeTrue(`(${text})(target, result)`);
+    }
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+function frameLoaded()
+{
+    runTest();
+}
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (207931 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-10-27 03:13:21 UTC (rev 207931)
+++ trunk/Source/WebCore/ChangeLog        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -1,3 +1,38 @@
</span><ins>+2016-10-26  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        [DOMJIT] Implement Node::ownerDocument
+        https://bugs.webkit.org/show_bug.cgi?id=164004
+
+        Reviewed by Darin Adler.
+
+        Test: js/dom/domjit-accessor-owner-document.html
+
+        Implement Node.ownerDocument DOMJIT accessor.
+        According to the result of the profiler, jQuery's prop()
+        function is frequently called in Ember.js SpeedoMeter.
+        And this function calls jQuery.isXMLDoc(). And this isXMLDoc()
+        function calls element.ownerDocument accessor. And our WebKit
+        inspector also uses ownerDocument accessor frequently.
+
+        Interesting thing is this ownerDocument functionality is used
+        in CSSJIT, so CSSJIT has similar helper function to look up the
+        owner document of the element. As a result, all the necessary
+        functionality is already implemented, DOMJIT just utilizes it.
+        For example, Node::treeScopeMemoryOffset() and
+        TreeScope::documentScopeMemoryOffset() is implemented before this
+        patch.
+
+        In the future, we will convert CSSJIT's Assembler&amp; to CCallHelpers&amp;
+        and share the code with DOMJIT[1].
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=164006
+
+        * dom/Node.idl:
+        * domjit/DOMJITAbstractHeapRepository.h:
+        * domjit/JSNodeDOMJIT.cpp:
+        (WebCore::NodeOwnerDocumentDOMJIT::checkDOM):
+        (WebCore::NodeOwnerDocumentDOMJIT::callDOM):
+
</ins><span class="cx"> 2016-10-26  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Replace IDBKeyPath with a WTF::Variant
</span></span></pre></div>
<a id="trunkSourceWebCoredomNodeidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Node.idl (207931 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Node.idl        2016-10-27 03:13:21 UTC (rev 207931)
+++ trunk/Source/WebCore/dom/Node.idl        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx">     [DOMJIT] readonly attribute Node? lastChild;
</span><span class="cx">     [DOMJIT] readonly attribute Node? previousSibling;
</span><span class="cx">     [DOMJIT] readonly attribute Node? nextSibling;
</span><del>-    readonly attribute Document? ownerDocument;
</del><ins>+    [DOMJIT] readonly attribute Document? ownerDocument;
</ins><span class="cx"> 
</span><span class="cx">     [CEReactions, Custom, MayThrowLegacyException] Node insertBefore(Node newChild, Node? refChild);
</span><span class="cx">     [CEReactions, Custom, MayThrowLegacyException] Node replaceChild(Node newChild, Node oldChild);
</span></span></pre></div>
<a id="trunkSourceWebCoredomjitDOMJITAbstractHeapRepositoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/domjit/DOMJITAbstractHeapRepository.h (207931 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/domjit/DOMJITAbstractHeapRepository.h        2016-10-27 03:13:21 UTC (rev 207931)
+++ trunk/Source/WebCore/domjit/DOMJITAbstractHeapRepository.h        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx">     V(Node_parentNode, Node) \
</span><span class="cx">     V(Node_nextSibling, Node) \
</span><span class="cx">     V(Node_previousSibling, Node) \
</span><ins>+    V(Node_ownerDocument, Node) \
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class AbstractHeapRepository {
</span></span></pre></div>
<a id="trunkSourceWebCoredomjitJSNodeDOMJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp (207931 => 207932)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp        2016-10-27 03:13:21 UTC (rev 207931)
+++ trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp        2016-10-27 03:42:13 UTC (rev 207932)
</span><span class="lines">@@ -96,7 +96,6 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Node#firstChild.
</del><span class="cx"> Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodeFirstChildDOMJIT::checkDOM()
</span><span class="cx"> {
</span><span class="cx">     return checkNode();
</span><span class="lines">@@ -110,7 +109,6 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Node#lastChild.
</del><span class="cx"> Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodeLastChildDOMJIT::checkDOM()
</span><span class="cx"> {
</span><span class="cx">     return checkNode();
</span><span class="lines">@@ -124,7 +122,6 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Node#nextSibling.
</del><span class="cx"> Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodeNextSiblingDOMJIT::checkDOM()
</span><span class="cx"> {
</span><span class="cx">     return checkNode();
</span><span class="lines">@@ -138,7 +135,6 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Node#previousSibling.
</del><span class="cx"> Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodePreviousSiblingDOMJIT::checkDOM()
</span><span class="cx"> {
</span><span class="cx">     return checkNode();
</span><span class="lines">@@ -152,7 +148,6 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Node#parentNode.
</del><span class="cx"> Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodeParentNodeDOMJIT::checkDOM()
</span><span class="cx"> {
</span><span class="cx">     return checkNode();
</span><span class="lines">@@ -166,7 +161,6 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Node#nodeType.
</del><span class="cx"> Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodeNodeTypeDOMJIT::checkDOM()
</span><span class="cx"> {
</span><span class="cx">     return checkNode();
</span><span class="lines">@@ -188,6 +182,41 @@
</span><span class="cx">     return patchpoint;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Ref&lt;JSC::DOMJIT::Patchpoint&gt; NodeOwnerDocumentDOMJIT::checkDOM()
+{
+    return checkNode();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Ref&lt;JSC::DOMJIT::CallDOMPatchpoint&gt; NodeOwnerDocumentDOMJIT::callDOM()
+{
+    const auto&amp; heap = DOMJIT::AbstractHeapRepository::shared();
+    Ref&lt;JSC::DOMJIT::CallDOMPatchpoint&gt; patchpoint = JSC::DOMJIT::CallDOMPatchpoint::create();
+    patchpoint-&gt;numGPScratchRegisters = 1;
+    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, JSC::DOMJIT::PatchpointParams&amp; params) {
+        JSValueRegs result = params[0].jsValueRegs();
+        GPRReg node = params[1].gpr();
+        GPRReg globalObject = params[2].gpr();
+        JSValue globalObjectValue = params[2].value();
+        GPRReg scratch = params.gpScratch(0);
+
+        // If the given node is a Document, Node#ownerDocument returns null.
+        auto notDocument = DOMJIT::branchIfNotDocumentWrapper(jit, node);
+        jit.moveValue(jsNull(), result);
+        auto done = jit.jump();
+
+        notDocument.link(&amp;jit);
+        jit.loadPtr(CCallHelpers::Address(node, JSNode::offsetOfWrapped()), scratch);
+        jit.loadPtr(CCallHelpers::Address(scratch, Node::treeScopeMemoryOffset()), scratch);
+        jit.loadPtr(CCallHelpers::Address(scratch, TreeScope::documentScopeMemoryOffset()), scratch);
+
+        DOMJIT::toWrapper&lt;Document&gt;(jit, params, scratch, globalObject, result, toWrapperSlow&lt;Document&gt;, globalObjectValue);
+        done.link(&amp;jit);
+        return CCallHelpers::JumpList();
+    });
+    patchpoint-&gt;effect = JSC::DOMJIT::Effect::forDef(heap.Node_ownerDocument);
+    return patchpoint;
+}
+
+}
+
</ins><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>