Title: [208412] trunk
Revision
208412
Author
[email protected]
Date
2016-11-04 18:15:17 -0700 (Fri, 04 Nov 2016)

Log Message

[DOMJIT] Add DOMJIT::Signature annotation to Document::getElementById
https://bugs.webkit.org/show_bug.cgi?id=164356

Reviewed by Filip Pizlo.

Source/WebCore:

This patch implements DOMJIT::Signature annotation for getElementById.
Since getElementById is also implemented in DocumentFragment, we implement
the branchIfDocumentFragment/branchIfNotDocumentFragment for that.

In dromaeo, we have a test like this.

test( "getElementById", function(){
    for ( var i = 0; i < num * 30; i++ ) {
        ret = document.getElementById("testA" + num).nodeType;
        ret = document.getElementById("testB" + num).nodeType;
        ret = document.getElementById("testC" + num).nodeType;
        ret = document.getElementById("testD" + num).nodeType;
        ret = document.getElementById("testE" + num).nodeType;
        ret = document.getElementById("testF" + num).nodeType;
    }
});

In the above test, JSC already knows the following things.

1. Since nodeType is now handled as CallDOMGetter, we know that it is pure.
2. getElementById look up becomes PureGetById since document is impure object. But it is kept as PureGetById. So it does not write DOMState.
3. `"testA" + num` will be converted to constant string.
4. CallDOM for getElementById said it just reads(DOMState:DOM). And it saids that it returns the same value as long as DOMState is not clobbered.
5. CheckCell leading CallDOM ensures the inlined getElementById node. (CallDOM node).

The key thing is that no node clobbers DOMState during the loop. So CallDOM & CallDOMGetter can be hoisted.
This improves dom-query significantly. Dromaeo dom-query getElementById becomes 40x faster (247796 v.s. 6197).
Dromaeo dom-query getElementById (not in document) becomes 89x faster (630317.8 v.s. 7066.).

Tests: js/dom/domjit-function-get-element-by-id-changed.html
       js/dom/domjit-function-get-element-by-id-licm.html
       js/dom/domjit-function-get-element-by-id.html

* dom/NonElementParentNode.idl:
* domjit/DOMJITCheckDOM.h:
(WebCore::DOMJIT::TypeChecker<DocumentFragment>::branchIfFail):
* domjit/DOMJITHelpers.h:
(WebCore::DOMJIT::branchIfDocumentFragment):
(WebCore::DOMJIT::branchIfNotDocumentFragment):

LayoutTests:

* js/dom/domjit-function-get-element-by-id-changed-expected.txt: Added.
* js/dom/domjit-function-get-element-by-id-changed.html: Added.
* js/dom/domjit-function-get-element-by-id-expected.txt: Added.
* js/dom/domjit-function-get-element-by-id-licm-expected.txt: Added.
* js/dom/domjit-function-get-element-by-id-licm.html: Added.
* js/dom/domjit-function-get-element-by-id.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (208411 => 208412)


--- trunk/LayoutTests/ChangeLog	2016-11-05 00:55:43 UTC (rev 208411)
+++ trunk/LayoutTests/ChangeLog	2016-11-05 01:15:17 UTC (rev 208412)
@@ -1,3 +1,17 @@
+2016-11-04  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Add DOMJIT::Signature annotation to Document::getElementById
+        https://bugs.webkit.org/show_bug.cgi?id=164356
+
+        Reviewed by Filip Pizlo.
+
+        * js/dom/domjit-function-get-element-by-id-changed-expected.txt: Added.
+        * js/dom/domjit-function-get-element-by-id-changed.html: Added.
+        * js/dom/domjit-function-get-element-by-id-expected.txt: Added.
+        * js/dom/domjit-function-get-element-by-id-licm-expected.txt: Added.
+        * js/dom/domjit-function-get-element-by-id-licm.html: Added.
+        * js/dom/domjit-function-get-element-by-id.html: Added.
+
 2016-11-04  Simon Fraser  <[email protected]>
 
         Layout viewport wrong with RTL documents

Added: trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-changed-expected.txt (0 => 208412)


--- trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-changed-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-changed-expected.txt	2016-11-05 01:15:17 UTC (rev 208412)
@@ -0,0 +1,8 @@
+Test LICM-ed DOMJIT function getElementById will work correctly when the function is replaced.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-changed.html (0 => 208412)


--- trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-changed.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-changed.html	2016-11-05 01:15:17 UTC (rev 208412)
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</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 LICM-ed DOMJIT function getElementById will work correctly when the function is replaced.');
+
+function test(flag) {
+    var ret = 0;
+    var text = document.createTextNode('Cocoa');
+    for (var i = 0; i < 1e4; ++i) {
+        ret = document.getElementById("target").nodeType;
+        ret = document.getElementById("target").nodeType;
+        if (i === 100 && flag)
+            document.getElementById = function (id) { return text; };
+        ret = document.getElementById("target").nodeType;
+        ret = document.getElementById("target").nodeType;
+    }
+    return ret;
+}
+var result;
+(function () {
+    for (var i = 0; i < 100; ++i) {
+        result = test(false);
+        shouldBe(`result`, `1`, true);
+    }
+    var original = document.getElementById;
+    result = test(true);
+    document.getElementById = original;
+    shouldBe(`result`, `Node.TEXT_NODE`, true);
+}());
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-expected.txt (0 => 208412)


--- trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-expected.txt	2016-11-05 01:15:17 UTC (rev 208412)
@@ -0,0 +1,8 @@
+Test DOMJIT function getElementById will be LICM-ed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-licm-expected.txt (0 => 208412)


--- trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-licm-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-licm-expected.txt	2016-11-05 01:15:17 UTC (rev 208412)
@@ -0,0 +1,8 @@
+Test DOMJIT function getElementById will be LICM-ed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-licm.html (0 => 208412)


--- trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-licm.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-function-get-element-by-id-licm.html	2016-11-05 01:15:17 UTC (rev 208412)
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</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 function getElementById will be LICM-ed.');
+
+function test() {
+    var ret = 0;
+    for (var i = 0; i < 1e4; ++i) {
+        ret = document.getElementById("target").nodeType;
+        ret = document.getElementById("target").nodeType;
+        ret = document.getElementById("target").nodeType;
+        ret = document.getElementById("target").nodeType;
+    }
+    return ret;
+}
+var result;
+(function () {
+    for (var i = 0; i < 100; ++i) {
+        result = test();
+        shouldBe(`result`, `1`, true);
+    }
+}());
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/dom/domjit-function-get-element-by-id.html (0 => 208412)


--- trunk/LayoutTests/js/dom/domjit-function-get-element-by-id.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-function-get-element-by-id.html	2016-11-05 01:15:17 UTC (rev 208412)
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</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 function getElementById will be LICM-ed.');
+
+function test(doc, id) {
+    var ret = 0;
+    for (var i = 0; i < 1e4; ++i) {
+        ret = doc.getElementById(id).nodeType;
+    }
+    return ret;
+}
+var result;
+(function () {
+    var fragment = document.createDocumentFragment();
+    var div = document.createElement('div');
+    div.setAttribute('id', 'target2');
+    fragment.appendChild(div);
+    for (var i = 0; i < 100; ++i) {
+        result = test(document, 'target');
+        shouldBe(`result`, `1`, true);
+        result = test(fragment, 'target2');
+        shouldBe(`result`, `1`, true);
+    }
+}());
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (208411 => 208412)


--- trunk/Source/WebCore/ChangeLog	2016-11-05 00:55:43 UTC (rev 208411)
+++ trunk/Source/WebCore/ChangeLog	2016-11-05 01:15:17 UTC (rev 208412)
@@ -1,3 +1,50 @@
+2016-11-04  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Add DOMJIT::Signature annotation to Document::getElementById
+        https://bugs.webkit.org/show_bug.cgi?id=164356
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements DOMJIT::Signature annotation for getElementById.
+        Since getElementById is also implemented in DocumentFragment, we implement
+        the branchIfDocumentFragment/branchIfNotDocumentFragment for that.
+
+        In dromaeo, we have a test like this.
+
+        test( "getElementById", function(){
+            for ( var i = 0; i < num * 30; i++ ) {
+                ret = document.getElementById("testA" + num).nodeType;
+                ret = document.getElementById("testB" + num).nodeType;
+                ret = document.getElementById("testC" + num).nodeType;
+                ret = document.getElementById("testD" + num).nodeType;
+                ret = document.getElementById("testE" + num).nodeType;
+                ret = document.getElementById("testF" + num).nodeType;
+            }
+        });
+
+        In the above test, JSC already knows the following things.
+
+        1. Since nodeType is now handled as CallDOMGetter, we know that it is pure.
+        2. getElementById look up becomes PureGetById since document is impure object. But it is kept as PureGetById. So it does not write DOMState.
+        3. `"testA" + num` will be converted to constant string.
+        4. CallDOM for getElementById said it just reads(DOMState:DOM). And it saids that it returns the same value as long as DOMState is not clobbered.
+        5. CheckCell leading CallDOM ensures the inlined getElementById node. (CallDOM node).
+
+        The key thing is that no node clobbers DOMState during the loop. So CallDOM & CallDOMGetter can be hoisted.
+        This improves dom-query significantly. Dromaeo dom-query getElementById becomes 40x faster (247796 v.s. 6197).
+        Dromaeo dom-query getElementById (not in document) becomes 89x faster (630317.8 v.s. 7066.).
+
+        Tests: js/dom/domjit-function-get-element-by-id-changed.html
+               js/dom/domjit-function-get-element-by-id-licm.html
+               js/dom/domjit-function-get-element-by-id.html
+
+        * dom/NonElementParentNode.idl:
+        * domjit/DOMJITCheckDOM.h:
+        (WebCore::DOMJIT::TypeChecker<DocumentFragment>::branchIfFail):
+        * domjit/DOMJITHelpers.h:
+        (WebCore::DOMJIT::branchIfDocumentFragment):
+        (WebCore::DOMJIT::branchIfNotDocumentFragment):
+
 2016-11-04  Simon Fraser  <[email protected]>
 
         Rename unscaledUnobscuredVisibleContentSize and unscaledVisibleContentSizeIncludingObscuredArea for attempted clarity

Modified: trunk/Source/WebCore/dom/NonElementParentNode.idl (208411 => 208412)


--- trunk/Source/WebCore/dom/NonElementParentNode.idl	2016-11-05 00:55:43 UTC (rev 208411)
+++ trunk/Source/WebCore/dom/NonElementParentNode.idl	2016-11-05 01:15:17 UTC (rev 208412)
@@ -28,5 +28,5 @@
 [
     NoInterfaceObject,
 ] interface NonElementParentNode {
-    Element getElementById([RequiresExistingAtomicString] DOMString elementId);
+    [DOMJIT=ReadDOM] Element? getElementById([RequiresExistingAtomicString] DOMString elementId);
 };

Modified: trunk/Source/WebCore/domjit/DOMJITCheckDOM.h (208411 => 208412)


--- trunk/Source/WebCore/domjit/DOMJITCheckDOM.h	2016-11-05 00:55:43 UTC (rev 208411)
+++ trunk/Source/WebCore/domjit/DOMJITCheckDOM.h	2016-11-05 01:15:17 UTC (rev 208412)
@@ -58,6 +58,14 @@
 };
 
 template<>
+struct TypeChecker<DocumentFragment> {
+    static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom)
+    {
+        return DOMJIT::branchIfNotDocumentFragment(jit, dom);
+    }
+};
+
+template<>
 struct TypeChecker<Event> {
     static CCallHelpers::Jump branchIfFail(CCallHelpers& jit, GPRReg dom)
     {

Modified: trunk/Source/WebCore/domjit/DOMJITHelpers.h (208411 => 208412)


--- trunk/Source/WebCore/domjit/DOMJITHelpers.h	2016-11-05 00:55:43 UTC (rev 208411)
+++ trunk/Source/WebCore/domjit/DOMJITHelpers.h	2016-11-05 01:15:17 UTC (rev 208412)
@@ -152,6 +152,16 @@
         CCallHelpers::TrustedImm32(JSC::JSType(JSElementType)));
 }
 
+inline CCallHelpers::Jump branchIfDocumentFragment(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branchIfType(target, JSC::JSType(JSDocumentFragmentNodeType));
+}
+
+inline CCallHelpers::Jump branchIfNotDocumentFragment(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branchIfNotType(target, JSC::JSType(JSDocumentFragmentNodeType));
+}
+
 inline CCallHelpers::Jump branchIfDocumentWrapper(CCallHelpers& jit, GPRReg target)
 {
     return jit.branchIfType(target, JSC::JSType(JSDocumentWrapperType));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to