Title: [207013] trunk
Revision
207013
Author
[email protected]
Date
2016-10-10 12:57:55 -0700 (Mon, 10 Oct 2016)

Log Message

[DOMJIT] Implement Node accessors in DOMJIT
https://bugs.webkit.org/show_bug.cgi?id=163005

Reviewed by Filip Pizlo.

Source/_javascript_Core:

Add some helper methods and offsetOfXXX for JSC::Weak since it is used
for DOM wrapper caching.

And make DOMJIT::Patchpoint in FTL closer to one in DFG. We add resultConstraint
to avoid the situation that the same register is allocated to child and result.

We also extend DOMJIT::Patchpoint to tell useTagTypeNumberRegister / useTagMaskRegister.

* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* domjit/DOMJITSlowPathCalls.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
* heap/WeakImpl.h:
(JSC::WeakImpl::offsetOfJSValue):
(JSC::WeakImpl::offsetOfWeakHandleOwner):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::boxCell):
(JSC::AssemblyHelpers::boxInt32): Deleted.
* jit/JITOperations.h:

Source/WebCore:

This patch implements DOMJIT accessors in WebCore. We plan to offer 2 things in DOMJIT.

    1. Hand written DOM inlining.

    We inject DOMJIT::Patchpoint compiler into JSC. And JSC uses this to inline DOM operation,
    and drop type checks. Since the operation is fully inlined, potentially it has large
    performance boost. Note that CSS Selector JIT compiler already does the similar things:
    accessing parentNode etc. directly by using offsets.

    2. Exposing signature information.

    We will offer function type signature by some representation and pass it to JSC.
    JSC will use to drop type checks. Since IDL code generator already knows this,
    we can automatically generate such a information. Since we don't perform any inlining,
    the performance boost may be limited. But it's worth doing.

This patch implements the first one, hand written DOM inlining facility. We add a new IDL attribute,
"DOMJIT". This means that "This readonly attribute have a DOMJIT patchpoint compiler".
We annotate several accessors at first. "firstChild", "lastChild", "nextSibling", "previousSibling",
and "parentNode". And we implement DOMJIT::Patchpoint for that in JSNodeDOMJIT.cpp.

This patchpoint will be integrated into JSC's DFG and FTL. And these tiers can drop type checks and
inline the entire code of these accessors. JSC compiler still does not know much about DOM. And WebCore
does not know much about each tier of JSC. WebCore just offers the generic patchpoints and they are
used in both DFG and FTL tiers. The layer separation is still kept.

While very small microbenchmark[1] shows performance benefit, still we cannot improve DOM
benchmarks due to the lack of following implementations. Once the following implementations
are implemented, we will get performance boost.

1. Super polymorphic sites.

    This inlining is super effective if we run some microbenchmarks. However, Dromaeo does not
    show so much performance benefit. This is because Dromaeo's dom-traverse.html is super
    polymorphic call site where JSC gives up optimization. For example, in the following
    dromaeo's benchmark, we can see so various DOM nodes at the `cur.firstChild` site, like,
    HTMLDivElement, HTMLAnchorElement, Text, Comment etc. JSC gives up optimization since we
    encounter so many Structures. This should be optimized since they share the large part of
    prototype-chain and they hit the exactly same CustomGetter, Node.prototype.firstChild.
    We will handle this and when we optimize it, this DOMJIT works well on Dromaeo.

        test( "firstChild", function(){
            var nodes = document.body.childNodes, nl = nodes.length;

            for ( var i = 0; i < num; i++ ) {
                for ( var j = 0; j < nl; j++ ) {
                    var cur = nodes[j];
                    while ( cur )
                        cur = cur.firstChild;
                    ret = cur;
                }
            }
        });

2. Emit code in IC.

    Currently, we only optimize DOMJIT accessors in DFG and FTL. However, we should leverage
    this DOMJIT::Patchpoint to emit inlined code even in Inline Caching (IC). We will emit
    CheckDOM's code for IC's guard phase, and emit CallDOM's code for IC's get phase. This
    offers performance benefit even if we live in baseline JIT code. And this should be easy.

[1]: With the following one, we can see 3x improvement (26ms v.s. 80ms).

    var element = document.getElementsByTagName('div')[3];
    var before = Date.now();
    for (var i = 0; i < 1e7; ++i)
        element.firstChild;
    console.log(Date.now() - before);

* CMakeLists.txt:
* ForwardingHeaders/domjit/DOMJITGetterSetter.h:
* ForwardingHeaders/domjit/DOMJITPatchpoint.h: Copied from Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h.
* ForwardingHeaders/domjit/DOMJITPatchpointParams.h: Copied from Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h.
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMGlobalObject.h:
* bindings/js/JSDOMWrapper.h:
(WebCore::JSDOMWrapper::offsetOfWrapped):
(WebCore::JSDOMWrapper::wrapped): Deleted.
* bindings/js/ScriptWrappable.h:
(WebCore::ScriptWrappable::offsetOfWrapper):
* bindings/scripts/CodeGeneratorJS.pm:
(GetJSCAttributesForAttribute):
(GenerateHeader):
(GeneratePropertiesHashTable):
(GenerateImplementation):
(GenerateHashTableValueArray):
* bindings/scripts/IDLAttributes.txt:
* dom/ContainerNode.h:
(WebCore::ContainerNode::lastChildMemoryOffset):
(WebCore::ContainerNode::lastChild): Deleted.
* dom/Node.h:
(WebCore::Node::flagIsContainer):
(WebCore::Node::flagIsText): Deleted.
* dom/Node.idl:
* domjit/DOMJITHelpers.h: Added.
(WebCore::DOMJITHelpers::branchIfNotWorldIsNormal):
(WebCore::DOMJITHelpers::branchIfNotWeakIsLive):
(WebCore::DOMJITHelpers::tryLookUpWrapperCache):
(WebCore::DOMJITHelpers::toWrapper):
(WebCore::DOMJITHelpers::branchIfDOMWrapper):
(WebCore::DOMJITHelpers::branchIfNotDOMWrapper):
(WebCore::DOMJITHelpers::branchIfNode):
(WebCore::DOMJITHelpers::branchIfNotNode):
(WebCore::DOMJITHelpers::branchIfElement):
(WebCore::DOMJITHelpers::branchIfNotElement):
(WebCore::DOMJITHelpers::branchIfDocumentWrapper):
(WebCore::DOMJITHelpers::branchIfNotDocumentWrapper):
* domjit/JSNodeDOMJIT.cpp: Added.
(WebCore::toWrapperSlow):
(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):

Source/WTF:

Add CAST_OFFSET. It is not necessary for JSCell thingy
since we don't use virtual member functions. However, it
is not true for WebCore DOM wrapped objects.

* wtf/StdLibExtras.h:

LayoutTests:

* js/dom/domjit-accessor-monomorphic-expected.txt: Added.
* js/dom/domjit-accessor-monomorphic.html: Added.
* js/dom/domjit-accessor-polymorphic-expected.txt: Added.
* js/dom/domjit-accessor-polymorphic.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (207012 => 207013)


--- trunk/LayoutTests/ChangeLog	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/LayoutTests/ChangeLog	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1,3 +1,15 @@
+2016-10-10  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Implement Node accessors in DOMJIT
+        https://bugs.webkit.org/show_bug.cgi?id=163005
+
+        Reviewed by Filip Pizlo.
+
+        * js/dom/domjit-accessor-monomorphic-expected.txt: Added.
+        * js/dom/domjit-accessor-monomorphic.html: Added.
+        * js/dom/domjit-accessor-polymorphic-expected.txt: Added.
+        * js/dom/domjit-accessor-polymorphic.html: Added.
+
 2016-10-10  Ryan Haddad  <[email protected]>
 
         Marking media/controls/airplay-picker.html as flaky on ElCapitan+.

Added: trunk/LayoutTests/js/dom/domjit-accessor-monomorphic-expected.txt (0 => 207013)


--- trunk/LayoutTests/js/dom/domjit-accessor-monomorphic-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-monomorphic-expected.txt	2016-10-10 19:57:55 UTC (rev 207013)
@@ -0,0 +1,13 @@
+Test DOMJIT accessors work in monomorphic call sites.
+
+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
+

Added: trunk/LayoutTests/js/dom/domjit-accessor-monomorphic.html (0 => 207013)


--- trunk/LayoutTests/js/dom/domjit-accessor-monomorphic.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-monomorphic.html	2016-10-10 19:57:55 UTC (rev 207013)
@@ -0,0 +1,41 @@
+<!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 accessors work in monomorphic call sites.');
+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;
+            }
+            return true;
+        };
+    `;
+    return [ name, Function(func)() ];
+});
+
+for (var [name, func] of tests) {
+    shouldBeTrue(`func("${name}", document.getElementById("target"), document.getElementById("${name}"))`);
+}
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/dom/domjit-accessor-polymorphic-expected.txt (0 => 207013)


--- trunk/LayoutTests/js/dom/domjit-accessor-polymorphic-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-polymorphic-expected.txt	2016-10-10 19:57:55 UTC (rev 207013)
@@ -0,0 +1,8 @@
+Test DOMJIT accessors work in polymorphic call sites.
+
+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-accessor-polymorphic.html (0 => 207013)


--- trunk/LayoutTests/js/dom/domjit-accessor-polymorphic.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-polymorphic.html	2016-10-10 19:57:55 UTC (rev 207013)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode0">
+<div id="previousSibling0"></div><div id="target0"><div id="firstChild0"></div><div id="lastChild0"></div></div><div id="nextSibling0"></div>
+</div>
+
+<section id="parentNode1">
+<section id="previousSibling1"></section><section id="target1"><section id="firstChild1"></section><section id="lastChild1"></section></section><section id="nextSibling1"></section>
+</section>
+
+<span id="parentNode2">
+<span id="previousSibling2"></span><span id="target2"><span id="firstChild2"></span><span id="lastChild2"></span></span><span id="nextSibling2"></span>
+</span>
+
+<script>
+description('Test DOMJIT accessors work in polymorphic call sites.');
+var tests = [
+    "firstChild",
+    "lastChild",
+    "nextSibling",
+    "previousSibling",
+    "parentNode",
+].map(function (name) {
+    var func = `
+        return function ${name}(name, element, result) {
+            if (element.${name} !== result)
+                return false;
+            return true;
+        };
+    `;
+    return [ name, Function(func)() ];
+});
+
+for (var [name, func] of tests) {
+    for (var i = 0; i < 1e4; ++i) {
+        for (var j = 0; j < 3; ++j) {
+            shouldBeTrueQuiet(`func("${name}", document.getElementById("target${j}"), document.getElementById("${name}${j}"))`);
+        }
+    }
+}
+
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (207012 => 207013)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1,3 +1,32 @@
+2016-10-10  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Implement Node accessors in DOMJIT
+        https://bugs.webkit.org/show_bug.cgi?id=163005
+
+        Reviewed by Filip Pizlo.
+
+        Add some helper methods and offsetOfXXX for JSC::Weak since it is used
+        for DOM wrapper caching.
+
+        And make DOMJIT::Patchpoint in FTL closer to one in DFG. We add resultConstraint
+        to avoid the situation that the same register is allocated to child and result.
+
+        We also extend DOMJIT::Patchpoint to tell useTagTypeNumberRegister / useTagMaskRegister.
+
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * domjit/DOMJITSlowPathCalls.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
+        * heap/WeakImpl.h:
+        (JSC::WeakImpl::offsetOfJSValue):
+        (JSC::WeakImpl::offsetOfWeakHandleOwner):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::boxCell):
+        (JSC::AssemblyHelpers::boxInt32): Deleted.
+        * jit/JITOperations.h:
+
 2016-10-09  Filip Pizlo  <[email protected]>
 
         Air should expose API for pinning registers

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (207012 => 207013)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1639,6 +1639,11 @@
         m_jit.setupArgumentsWithExecState(arg1, arg2);
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EGP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_JITOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1894,6 +1899,11 @@
         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer));
         return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
     }
+    JITCompiler::Call callOperation(J_JITOperation_EGP operation, JSValueRegs result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
+    }
     JITCompiler::Call callOperation(J_JITOperation_EP operation, JSValueRegs result, GPRReg arg1)
     {
         m_jit.setupArgumentsWithExecState(arg1);

Modified: trunk/Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h (207012 => 207013)


--- trunk/Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -30,5 +30,6 @@
 // macro(OperationType, ArgType1, ArgType2, ...)
 #define DOMJIT_SLOW_PATH_CALLS(macro) \
     macro(J_JITOperation_EP, JSValueRegs, GPRReg) \
+    macro(J_JITOperation_EGP, JSValueRegs, GPRReg, GPRReg) \
 
 #endif

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (207012 => 207013)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-10 19:57:55 UTC (rev 207013)
@@ -8731,6 +8731,8 @@
         patchpoint->appendSomeRegister(cell);
         patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
         patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
+        patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
+        patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
 
         State* state = &m_ftlState;
         Node* node = m_node;
@@ -8774,17 +8776,20 @@
         PatchpointValue* patchpoint = m_out.patchpoint(Int64);
         patchpoint->appendSomeRegister(globalObject);
         patchpoint->appendSomeRegister(cell);
-        patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
-        patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
+        patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
+        patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
         RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
         patchpoint->clobber(RegisterSet::macroScratchRegisters());
         patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
         patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
+        patchpoint->resultConstraint = ValueRep::SomeEarlyRegister;
 
         State* state = &m_ftlState;
         Node* node = m_node;
         patchpoint->setGenerator(
             [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                AllowMacroScratchRegisterUsage allowScratch(jit);
+
                 Vector<GPRReg> gpScratch;
                 Vector<FPRReg> fpScratch;
                 Vector<DOMJIT::Reg> regs;
@@ -8794,8 +8799,6 @@
                 regs.append(JSValueRegs(params[0].gpr()));
                 regs.append(params[1].gpr());
                 regs.append(params[2].gpr());
-                regs.append(params[3].gpr());
-                regs.append(params[4].gpr());
 
                 for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
                     gpScratch.append(params.gpScratch(i));

Modified: trunk/Source/_javascript_Core/heap/WeakImpl.h (207012 => 207013)


--- trunk/Source/_javascript_Core/heap/WeakImpl.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/heap/WeakImpl.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -51,7 +51,9 @@
     void setState(State);
 
     const JSValue& jsValue();
+    static ptrdiff_t offsetOfJSValue() { return OBJECT_OFFSETOF(WeakImpl, m_jsValue); }
     WeakHandleOwner* weakHandleOwner();
+    static ptrdiff_t offsetOfWeakHandleOwner() { return OBJECT_OFFSETOF(WeakImpl, m_weakHandleOwner); }
     void* context();
 
     static WeakImpl* asWeakImpl(JSValue*);

Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (207012 => 207013)


--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1204,6 +1204,16 @@
         move(TrustedImm32(JSValue::Int32Tag), boxedRegs.tagGPR());
 #endif
     }
+
+    void boxCell(GPRReg cellGPR, JSValueRegs boxedRegs)
+    {
+#if USE(JSVALUE64)
+        move(cellGPR, boxedRegs.gpr());
+#else
+        move(cellGPR, boxedRegs.payloadGPR());
+        move(TrustedImm32(JSValue::CellTag), boxedRegs.tagGPR());
+#endif
+    }
     
     void callExceptionFuzz();
     

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (207012 => 207013)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -155,6 +155,7 @@
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssReo)(ExecState*, JSString*, RegExpObject*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssReoJss)(ExecState*, JSString*, RegExpObject*, JSString*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJP)(ExecState*, EncodedJSValue, void*);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGP)(ExecState*, JSGlobalObject*, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EP)(ExecState*, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EPP)(ExecState*, void*, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EPS)(ExecState*, void*, size_t);

Modified: trunk/Source/WTF/ChangeLog (207012 => 207013)


--- trunk/Source/WTF/ChangeLog	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WTF/ChangeLog	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1,3 +1,16 @@
+2016-10-10  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Implement Node accessors in DOMJIT
+        https://bugs.webkit.org/show_bug.cgi?id=163005
+
+        Reviewed by Filip Pizlo.
+
+        Add CAST_OFFSET. It is not necessary for JSCell thingy
+        since we don't use virtual member functions. However, it
+        is not true for WebCore DOM wrapped objects.
+
+        * wtf/StdLibExtras.h:
+
 2016-10-07  Chris Dumez  <[email protected]>
 
         window.navigator.language incorrectly returns all lowercase string

Modified: trunk/Source/WTF/wtf/StdLibExtras.h (207012 => 207013)


--- trunk/Source/WTF/wtf/StdLibExtras.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WTF/wtf/StdLibExtras.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -68,6 +68,8 @@
 // NULL can cause compiler problems, especially in cases of multiple inheritance.
 #define OBJECT_OFFSETOF(class, field) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->field)) - 0x4000)
 
+#define CAST_OFFSET(from, to) (reinterpret_cast<uintptr_t>(static_cast<to>((reinterpret_cast<from>(0x4000)))) - 0x4000)
+
 // STRINGIZE: Can convert any value to quoted string, even expandable macros
 #define STRINGIZE(exp) #exp
 #define STRINGIZE_VALUE_OF(exp) STRINGIZE(exp)

Modified: trunk/Source/WebCore/CMakeLists.txt (207012 => 207013)


--- trunk/Source/WebCore/CMakeLists.txt	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/CMakeLists.txt	2016-10-10 19:57:55 UTC (rev 207013)
@@ -49,6 +49,7 @@
     "${WEBCORE_DIR}/cssjit"
     "${WEBCORE_DIR}/dom"
     "${WEBCORE_DIR}/dom/default"
+    "${WEBCORE_DIR}/domjit"
     "${WEBCORE_DIR}/editing"
     "${WEBCORE_DIR}/fileapi"
     "${WEBCORE_DIR}/history"
@@ -1529,6 +1530,8 @@
 
     dom/default/PlatformMessagePortChannel.cpp
 
+    domjit/JSNodeDOMJIT.cpp
+
     editing/AlternativeTextController.cpp
     editing/AppendNodeCommand.cpp
     editing/ApplyBlockElementCommand.cpp

Modified: trunk/Source/WebCore/ChangeLog (207012 => 207013)


--- trunk/Source/WebCore/ChangeLog	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/ChangeLog	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1,3 +1,132 @@
+2016-10-10  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Implement Node accessors in DOMJIT
+        https://bugs.webkit.org/show_bug.cgi?id=163005
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements DOMJIT accessors in WebCore. We plan to offer 2 things in DOMJIT.
+
+            1. Hand written DOM inlining.
+
+            We inject DOMJIT::Patchpoint compiler into JSC. And JSC uses this to inline DOM operation,
+            and drop type checks. Since the operation is fully inlined, potentially it has large
+            performance boost. Note that CSS Selector JIT compiler already does the similar things:
+            accessing parentNode etc. directly by using offsets.
+
+            2. Exposing signature information.
+
+            We will offer function type signature by some representation and pass it to JSC.
+            JSC will use to drop type checks. Since IDL code generator already knows this,
+            we can automatically generate such a information. Since we don't perform any inlining,
+            the performance boost may be limited. But it's worth doing.
+
+        This patch implements the first one, hand written DOM inlining facility. We add a new IDL attribute,
+        "DOMJIT". This means that "This readonly attribute have a DOMJIT patchpoint compiler".
+        We annotate several accessors at first. "firstChild", "lastChild", "nextSibling", "previousSibling",
+        and "parentNode". And we implement DOMJIT::Patchpoint for that in JSNodeDOMJIT.cpp.
+
+        This patchpoint will be integrated into JSC's DFG and FTL. And these tiers can drop type checks and
+        inline the entire code of these accessors. JSC compiler still does not know much about DOM. And WebCore
+        does not know much about each tier of JSC. WebCore just offers the generic patchpoints and they are
+        used in both DFG and FTL tiers. The layer separation is still kept.
+
+        While very small microbenchmark[1] shows performance benefit, still we cannot improve DOM
+        benchmarks due to the lack of following implementations. Once the following implementations
+        are implemented, we will get performance boost.
+
+        1. Super polymorphic sites.
+
+            This inlining is super effective if we run some microbenchmarks. However, Dromaeo does not
+            show so much performance benefit. This is because Dromaeo's dom-traverse.html is super
+            polymorphic call site where JSC gives up optimization. For example, in the following
+            dromaeo's benchmark, we can see so various DOM nodes at the `cur.firstChild` site, like,
+            HTMLDivElement, HTMLAnchorElement, Text, Comment etc. JSC gives up optimization since we
+            encounter so many Structures. This should be optimized since they share the large part of
+            prototype-chain and they hit the exactly same CustomGetter, Node.prototype.firstChild.
+            We will handle this and when we optimize it, this DOMJIT works well on Dromaeo.
+
+                test( "firstChild", function(){
+                    var nodes = document.body.childNodes, nl = nodes.length;
+
+                    for ( var i = 0; i < num; i++ ) {
+                        for ( var j = 0; j < nl; j++ ) {
+                            var cur = nodes[j];
+                            while ( cur )
+                                cur = cur.firstChild;
+                            ret = cur;
+                        }
+                    }
+                });
+
+        2. Emit code in IC.
+
+            Currently, we only optimize DOMJIT accessors in DFG and FTL. However, we should leverage
+            this DOMJIT::Patchpoint to emit inlined code even in Inline Caching (IC). We will emit
+            CheckDOM's code for IC's guard phase, and emit CallDOM's code for IC's get phase. This
+            offers performance benefit even if we live in baseline JIT code. And this should be easy.
+
+        [1]: With the following one, we can see 3x improvement (26ms v.s. 80ms).
+
+            var element = document.getElementsByTagName('div')[3];
+            var before = Date.now();
+            for (var i = 0; i < 1e7; ++i)
+                element.firstChild;
+            console.log(Date.now() - before);
+
+        * CMakeLists.txt:
+        * ForwardingHeaders/domjit/DOMJITGetterSetter.h:
+        * ForwardingHeaders/domjit/DOMJITPatchpoint.h: Copied from Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h.
+        * ForwardingHeaders/domjit/DOMJITPatchpointParams.h: Copied from Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h.
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMGlobalObject.h:
+        * bindings/js/JSDOMWrapper.h:
+        (WebCore::JSDOMWrapper::offsetOfWrapped):
+        (WebCore::JSDOMWrapper::wrapped): Deleted.
+        * bindings/js/ScriptWrappable.h:
+        (WebCore::ScriptWrappable::offsetOfWrapper):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GetJSCAttributesForAttribute):
+        (GenerateHeader):
+        (GeneratePropertiesHashTable):
+        (GenerateImplementation):
+        (GenerateHashTableValueArray):
+        * bindings/scripts/IDLAttributes.txt:
+        * dom/ContainerNode.h:
+        (WebCore::ContainerNode::lastChildMemoryOffset):
+        (WebCore::ContainerNode::lastChild): Deleted.
+        * dom/Node.h:
+        (WebCore::Node::flagIsContainer):
+        (WebCore::Node::flagIsText): Deleted.
+        * dom/Node.idl:
+        * domjit/DOMJITHelpers.h: Added.
+        (WebCore::DOMJITHelpers::branchIfNotWorldIsNormal):
+        (WebCore::DOMJITHelpers::branchIfNotWeakIsLive):
+        (WebCore::DOMJITHelpers::tryLookUpWrapperCache):
+        (WebCore::DOMJITHelpers::toWrapper):
+        (WebCore::DOMJITHelpers::branchIfDOMWrapper):
+        (WebCore::DOMJITHelpers::branchIfNotDOMWrapper):
+        (WebCore::DOMJITHelpers::branchIfNode):
+        (WebCore::DOMJITHelpers::branchIfNotNode):
+        (WebCore::DOMJITHelpers::branchIfElement):
+        (WebCore::DOMJITHelpers::branchIfNotElement):
+        (WebCore::DOMJITHelpers::branchIfDocumentWrapper):
+        (WebCore::DOMJITHelpers::branchIfNotDocumentWrapper):
+        * domjit/JSNodeDOMJIT.cpp: Added.
+        (WebCore::toWrapperSlow):
+        (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):
+
 2016-10-10  Wenson Hsieh  <[email protected]>
 
         Support InputEvent.data for the new InputEvent spec

Modified: trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITGetterSetter.h (207012 => 207013)


--- trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITGetterSetter.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITGetterSetter.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -1,3 +1,28 @@
+/*
+ * 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_DOMJITGetterSetter_h
 #define WebCore_FWD_DOMJITGetterSetter_h
 #include <_javascript_Core/DOMJITGetterSetter.h>

Copied: trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITPatchpoint.h (from rev 207012, trunk/Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h) (0 => 207013)


--- trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITPatchpoint.h	                        (rev 0)
+++ trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITPatchpoint.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -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_DOMJITPatchpoint_h
+#define WebCore_FWD_DOMJITPatchpoint_h
+#include <_javascript_Core/DOMJITPatchpoint.h>
+#endif

Copied: trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITPatchpointParams.h (from rev 207012, trunk/Source/_javascript_Core/domjit/DOMJITSlowPathCalls.h) (0 => 207013)


--- trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITPatchpointParams.h	                        (rev 0)
+++ trunk/Source/WebCore/ForwardingHeaders/domjit/DOMJITPatchpointParams.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -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_DOMJITPatchpointParams_h
+#define WebCore_FWD_DOMJITPatchpointParams_h
+#include <_javascript_Core/DOMJITPatchpointParams.h>
+#endif

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (207012 => 207013)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-10-10 19:57:55 UTC (rev 207013)
@@ -6142,6 +6142,8 @@
 		E1FF57A60F01256B00891EBB /* ThreadGlobalData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FF57A50F01256B00891EBB /* ThreadGlobalData.cpp */; };
 		E1FF8F6C180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FF8F6A180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp */; };
 		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 */; };
 		E38838981BAD145F00D62EE3 /* ScriptModuleLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38838941BAD145F00D62EE3 /* ScriptModuleLoader.cpp */; };
 		E38838991BAD145F00D62EE3 /* ScriptModuleLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = E38838951BAD145F00D62EE3 /* ScriptModuleLoader.h */; };
 		E3B2F0EB1D7F4C9D00B0C9D1 /* LoadableClassicScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3B2F0E31D7F35EC00B0C9D1 /* LoadableClassicScript.cpp */; };
@@ -13774,8 +13776,10 @@
 		E1FF8F661807460800132674 /* JSWebKitSubtleCryptoCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebKitSubtleCryptoCustom.cpp; sourceTree = "<group>"; };
 		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>"; };
 		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>"; };
 		E3B2F0E31D7F35EC00B0C9D1 /* LoadableClassicScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadableClassicScript.cpp; sourceTree = "<group>"; };
 		E3B2F0E41D7F35EC00B0C9D1 /* LoadableClassicScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableClassicScript.h; sourceTree = "<group>"; };
 		E3B2F0E71D7F35EC00B0C9D1 /* LoadableScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableScript.h; sourceTree = "<group>"; };
@@ -14882,6 +14886,7 @@
 				F523D18402DE42E8018635CA /* css */,
 				26B9998D1803ADFA00D01121 /* cssjit */,
 				F523D32402DE4478018635CA /* dom */,
+				E3AFA9631DA6E8AF002861BD /* domjit */,
 				93309D86099E64910056E581 /* editing */,
 				976D6C57122B8A18001FD1F7 /* fileapi */,
 				51741D080B07257000ED442C /* history */,
@@ -22318,6 +22323,15 @@
 			name = Crypto;
 			sourceTree = "<group>";
 		};
+		E3AFA9631DA6E8AF002861BD /* domjit */ = {
+			isa = PBXGroup;
+			children = (
+				E3150EA51DA7218D00194012 /* DOMJITHelpers.h */,
+				E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */,
+			);
+			path = domjit;
+			sourceTree = "<group>";
+		};
 		E46E97860DAAD61B0071E894 /* animation */ = {
 			isa = PBXGroup;
 			children = (
@@ -24787,6 +24801,7 @@
 				A871DC240A15205700B12A68 /* HTMLMetaElement.h in Headers */,
 				A454424B119B3661009BE912 /* HTMLMeterElement.h in Headers */,
 				A8CFF7A70A156978000A4234 /* HTMLModElement.h in Headers */,
+				E3150EA71DA7219300194012 /* DOMJITHelpers.h in Headers */,
 				A8DF3FD4097FA0FC0052981B /* HTMLNameCollection.h in Headers */,
 				A871D45A0A127CBC00B12A68 /* HTMLObjectElement.h in Headers */,
 				A8EA79F10A1916DF00A8EF5F /* HTMLOListElement.h in Headers */,
@@ -28698,6 +28713,7 @@
 				BCC065870F3CE2A700CD2D87 /* JSClientRect.cpp in Sources */,
 				46A58AC51D46B3FA00432036 /* JSClientRectCustom.cpp in Sources */,
 				BCC065890F3CE2A700CD2D87 /* JSClientRectList.cpp in Sources */,
+				E3150EA61DA7219000194012 /* JSNodeDOMJIT.cpp in Sources */,
 				51FB5505113E3E9100821176 /* JSCloseEvent.cpp in Sources */,
 				A584FE3B1864E2D800843B10 /* JSCommandLineAPIHost.cpp in Sources */,
 				A584FE381864DAC100843B10 /* JSCommandLineAPIHostCustom.cpp in Sources */,

Modified: trunk/Source/WebCore/bindings/js/JSDOMGlobalObject.h (207012 => 207013)


--- trunk/Source/WebCore/bindings/js/JSDOMGlobalObject.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/bindings/js/JSDOMGlobalObject.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -72,6 +72,7 @@
 
         DOMWrapperWorld& world() { return m_world.get(); }
         bool worldIsNormal() const { return m_worldIsNormal; }
+        static ptrdiff_t offsetOfWorldIsNormal() { return OBJECT_OFFSETOF(JSDOMGlobalObject, m_worldIsNormal); }
 
         JSBuiltinInternalFunctions& builtinInternalFunctions() { return m_builtinInternalFunctions; }
 
@@ -95,7 +96,7 @@
 
         Event* m_currentEvent;
         Ref<DOMWrapperWorld> m_world;
-        bool m_worldIsNormal;
+        uint8_t m_worldIsNormal;
 
     private:
         void addBuiltinGlobals(JSC::VM&);

Modified: trunk/Source/WebCore/bindings/js/JSDOMWrapper.h (207012 => 207013)


--- trunk/Source/WebCore/bindings/js/JSDOMWrapper.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/bindings/js/JSDOMWrapper.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -59,6 +59,7 @@
     static constexpr bool isDOMWrapper = true;
 
     ImplementationClass& wrapped() const { return const_cast<ImplementationClass&>(m_wrapped.get()); }
+    static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSDOMWrapper<ImplementationClass>, m_wrapped); }
 
 protected:
     JSDOMWrapper(JSC::Structure* structure, JSC::JSGlobalObject& globalObject, Ref<ImplementationClass>&& impl)

Modified: trunk/Source/WebCore/bindings/js/ScriptWrappable.h (207012 => 207013)


--- trunk/Source/WebCore/bindings/js/ScriptWrappable.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/bindings/js/ScriptWrappable.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -48,6 +48,9 @@
     void setWrapper(JSDOMObject*, JSC::WeakHandleOwner*, void*);
     void clearWrapper(JSDOMObject*);
 
+    template<typename Derived>
+    static ptrdiff_t offsetOfWrapper() { return CAST_OFFSET(Derived*, ScriptWrappable*) + OBJECT_OFFSETOF(ScriptWrappable, m_wrapper); }
+
 protected:
     ~ScriptWrappable() { }
 

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (207012 => 207013)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-10-10 19:57:55 UTC (rev 207013)
@@ -641,6 +641,7 @@
     push(@specials, "DontEnum") if ($attribute->signature->extendedAttributes->{NotEnumerable} || $is_global_constructor);
     push(@specials, "ReadOnly") if IsReadonly($attribute);
     push(@specials, "CustomAccessor") unless $is_global_constructor or IsJSBuiltin($interface, $attribute);
+    push(@specials, "DOMJITAttribute") if $attribute->signature->extendedAttributes->{"DOMJIT"};
     push(@specials, "Accessor | Builtin") if  IsJSBuiltin($interface, $attribute);
     return (@specials > 0) ? join(" | ", @specials) : "0";
 }
@@ -1418,6 +1419,8 @@
     my $hasForwardDeclaringFunctions = 0;
     my $hasForwardDeclaringAttributes = 0;
 
+    my $hasDOMJITAttributes = 0;
+
     # Attribute and function enums
     if ($numAttributes > 0) {
         push(@headerContent, "    static ${className}* castForAttribute(JSC::ExecState*, JSC::EncodedJSValue);\n");
@@ -1434,6 +1437,7 @@
                 $needsVisitChildren = 1;
                 push(@headerContent, "#endif\n") if $conditionalString;
             }
+            $hasDOMJITAttributes = 1 if $attribute->signature->extendedAttributes->{"DOMJIT"};
 
             $hasForwardDeclaringAttributes = 1 if $attribute->signature->extendedAttributes->{ForwardDeclareInHeader};
         }
@@ -1641,6 +1645,29 @@
         }
     }
 
+    if ($hasDOMJITAttributes) {
+        $headerIncludes{"<domjit/DOMJITGetterSetter.h>"} = 1;
+        push(@headerContent,"// DOMJIT emitters for attributes\n\n");
+        foreach my $attribute (@{$interface->attributes}) {
+            next unless $attribute->signature->extendedAttributes->{"DOMJIT"};
+
+            my $interfaceName = $interface->name;
+            my $className = $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name);
+            my $domJITClassName = $className . "DOMJIT";
+
+            push(@headerContent, "JSC::DOMJIT::GetterSetter* domJITGetterSetterFor$className(void);\n");
+
+            push(@headerContent, "class $domJITClassName : public JSC::DOMJIT::GetterSetter {\n");
+            push(@headerContent, "public:\n");
+            push(@headerContent, "    $domJITClassName();\n");
+            push(@headerContent, "#if ENABLE(JIT)\n");
+            push(@headerContent, "    Ref<JSC::DOMJIT::Patchpoint> checkDOM() override;\n");
+            push(@headerContent, "    Ref<JSC::DOMJIT::Patchpoint> callDOM() override;\n");
+            push(@headerContent, "#endif\n");
+            push(@headerContent, "};\n\n");
+        }
+    }
+
     if (HasCustomConstructor($interface)) {
         push(@headerContent, "// Custom constructor\n");
         push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState&);\n\n");
@@ -1720,14 +1747,19 @@
         my $special = GetJSCAttributesForAttribute($interface, $attribute);
         push(@$hashSpecials, $special);
 
-        my $getter = GetAttributeGetterName($interface, $className, $attribute);
-        push(@$hashValue1, $getter);
-
-        if (IsReadonly($attribute)) {
+        if ($attribute->signature->extendedAttributes->{"DOMJIT"}) {
+            push(@$hashValue1, "domJITGetterSetterFor" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name));
             push(@$hashValue2, "0");
         } else {
-            my $setter = GetAttributeSetterName($interface, $className, $attribute);
-            push(@$hashValue2, $setter);
+            my $getter = GetAttributeGetterName($interface, $className, $attribute);
+            push(@$hashValue1, $getter);
+
+            if (IsReadonly($attribute)) {
+                push(@$hashValue2, "0");
+            } else {
+                my $setter = GetAttributeSetterName($interface, $className, $attribute);
+                push(@$hashValue2, $setter);
+            }
         }
 
         my $conditional = $attribute->signature->extendedAttributes->{Conditional};
@@ -2506,17 +2538,23 @@
             my @specials = ();
             push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{Deletable};
             push(@specials, "ReadOnly") if IsReadonly($attribute);
+            push(@specials, "DOMJITAttribute") if $attribute->signature->extendedAttributes->{"DOMJIT"};
             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
             push(@hashSpecials, $special);
 
-            my $getter = GetAttributeGetterName($interface, $className, $attribute);
-            push(@hashValue1, $getter);
-
-            if (IsReadonly($attribute)) {
+            if ($attribute->signature->extendedAttributes->{"DOMJIT"}) {
+                push(@hashValue1, "domJITGetterSetterFor" . $interface->name . $codeGenerator->WK_ucfirst($attribute->signature->name));
                 push(@hashValue2, "0");
             } else {
-                my $setter = GetAttributeSetterName($interface, $className, $attribute);
-                push(@hashValue2, $setter);
+                my $getter = GetAttributeGetterName($interface, $className, $attribute);
+                push(@hashValue1, $getter);
+
+                if (IsReadonly($attribute)) {
+                    push(@hashValue2, "0");
+                } else {
+                    my $setter = GetAttributeSetterName($interface, $className, $attribute);
+                    push(@hashValue2, $setter);
+                }
             }
 
             my $conditional = $attribute->signature->extendedAttributes->{Conditional};
@@ -3094,6 +3132,26 @@
 
             push(@implContent, "}\n\n");
 
+            if ($attribute->signature->extendedAttributes->{"DOMJIT"}) {
+                $implIncludes{"<wtf/NeverDestroyed.h>"} = 1;
+                my $interfaceName = $interface->name;
+                my $attributeName = $attribute->signature->name;
+                my $generatorName = $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name);
+                my $domJITClassName = $generatorName . "DOMJIT";
+                my $getter = GetAttributeGetterName($interface, $generatorName, $attribute);
+                my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $generatorName, $attribute);
+                push(@implContent, "$domJITClassName::$domJITClassName()\n");
+                push(@implContent, "    : JSC::DOMJIT::GetterSetter($getter, $setter, ${className}::info())\n");
+                push(@implContent, "{\n");
+                push(@implContent, "}\n\n");
+
+                push(@implContent, "JSC::DOMJIT::GetterSetter* domJITGetterSetterFor" . $generatorName . "()\n");
+                push(@implContent, "{\n");
+                push(@implContent, "    static NeverDestroyed<$domJITClassName> compiler;\n");
+                push(@implContent, "    return &compiler.get();\n");
+                push(@implContent, "}\n\n");
+            }
+
             push(@implContent, "#endif\n\n") if $attributeConditionalString;
         }
 
@@ -5094,6 +5152,8 @@
             $firstTargetType = "static_cast<BuiltinGenerator>";
         } elsif ("@$specials[$i]" =~ m/ConstantInteger/) {
             $firstTargetType = "";
+        } elsif ("@$specials[$i]" =~ m/DOMJITAttribute/) {
+            $firstTargetType = "static_cast<DOMJITGetterSetterGenerator>";
         } else {
             $firstTargetType = "static_cast<PropertySlot::GetValueFunc>";
             $secondTargetType = "static_cast<PutPropertySlot::PutValueFunc>";

Modified: trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt (207012 => 207013)


--- trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt	2016-10-10 19:57:55 UTC (rev 207013)
@@ -55,6 +55,7 @@
 CustomSetPrototype
 CustomSetter
 CustomToJSObject
+DOMJIT
 Deletable
 DoNotCheckConstants
 DoNotCheckSecurity

Modified: trunk/Source/WebCore/dom/ContainerNode.h (207012 => 207013)


--- trunk/Source/WebCore/dom/ContainerNode.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/dom/ContainerNode.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -41,6 +41,7 @@
     Node* firstChild() const { return m_firstChild; }
     static ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); }
     Node* lastChild() const { return m_lastChild; }
+    static ptrdiff_t lastChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_lastChild); }
     bool hasChildNodes() const { return m_firstChild; }
     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
 

Modified: trunk/Source/WebCore/dom/Node.h (207012 => 207013)


--- trunk/Source/WebCore/dom/Node.h	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/dom/Node.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -559,10 +559,11 @@
     void updateAncestorConnectedSubframeCountForRemoval() const;
     void updateAncestorConnectedSubframeCountForInsertion() const;
 
-#if ENABLE(CSS_SELECTOR_JIT)
+#if ENABLE(JIT)
     static ptrdiff_t nodeFlagsMemoryOffset() { return OBJECT_OFFSETOF(Node, m_nodeFlags); }
     static ptrdiff_t rareDataMemoryOffset() { return OBJECT_OFFSETOF(Node, m_data.m_rareData); }
     static int32_t flagIsText() { return IsTextFlag; }
+    static int32_t flagIsContainer() { return IsContainerFlag; }
     static int32_t flagIsElement() { return IsElementFlag; }
     static int32_t flagIsHTML() { return IsHTMLFlag; }
     static int32_t flagIsLink() { return IsLinkFlag; }
@@ -574,7 +575,7 @@
 
     static int32_t flagAffectsNextSiblingElementStyle() { return AffectsNextSiblingElementStyle; }
     static int32_t flagStyleIsAffectedByPreviousSibling() { return StyleIsAffectedByPreviousSibling; }
-#endif // ENABLE(CSS_SELECTOR_JIT)
+#endif // ENABLE(JIT)
 
 protected:
     enum NodeFlags {

Modified: trunk/Source/WebCore/dom/Node.idl (207012 => 207013)


--- trunk/Source/WebCore/dom/Node.idl	2016-10-10 19:42:51 UTC (rev 207012)
+++ trunk/Source/WebCore/dom/Node.idl	2016-10-10 19:57:55 UTC (rev 207013)
@@ -47,12 +47,12 @@
     [SetterMayThrowLegacyException] attribute DOMString? nodeValue;
 
     readonly attribute unsigned short nodeType;
-    readonly attribute Node? parentNode;
+    [DOMJIT] readonly attribute Node? parentNode;
     readonly attribute NodeList childNodes;
-    readonly attribute Node? firstChild;
-    readonly attribute Node? lastChild;
-    readonly attribute Node? previousSibling;
-    readonly attribute Node? nextSibling;
+    [DOMJIT] readonly attribute Node? firstChild;
+    [DOMJIT] readonly attribute Node? lastChild;
+    [DOMJIT] readonly attribute Node? previousSibling;
+    [DOMJIT] readonly attribute Node? nextSibling;
     readonly attribute Document? ownerDocument;
 
     [Custom, MayThrowLegacyException] Node insertBefore([CustomReturn] Node newChild, Node? refChild);

Added: trunk/Source/WebCore/domjit/DOMJITHelpers.h (0 => 207013)


--- trunk/Source/WebCore/domjit/DOMJITHelpers.h	                        (rev 0)
+++ trunk/Source/WebCore/domjit/DOMJITHelpers.h	2016-10-10 19:57:55 UTC (rev 207013)
@@ -0,0 +1,134 @@
+/*
+ * 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 "JSDOMWrapper.h"
+#include <domjit/DOMJITPatchpoint.h>
+#include <domjit/DOMJITPatchpointParams.h>
+
+#if ENABLE(JIT)
+
+namespace WebCore {
+namespace DOMJITHelpers {
+
+using JSC::CCallHelpers;
+using JSC::GPRReg;
+using JSC::JSValueRegs;
+
+inline CCallHelpers::Jump branchIfNotWorldIsNormal(CCallHelpers& jit, GPRReg globalObject)
+{
+    return jit.branchTest8(CCallHelpers::Zero, CCallHelpers::Address(globalObject, JSDOMGlobalObject::offsetOfWorldIsNormal()));
+}
+
+inline CCallHelpers::Jump branchIfNotWeakIsLive(CCallHelpers& jit, GPRReg weakImpl)
+{
+    return jit.branchTestPtr(CCallHelpers::NonZero, CCallHelpers::Address(weakImpl, JSC::WeakImpl::offsetOfWeakHandleOwner()), CCallHelpers::TrustedImm32(JSC::WeakImpl::StateMask));
+}
+
+template<typename WrappedType>
+void tryLookUpWrapperCache(CCallHelpers& jit, CCallHelpers::JumpList& failureCases, GPRReg wrapped, GPRReg resultGPR)
+{
+    jit.loadPtr(CCallHelpers::Address(wrapped, ScriptWrappable::offsetOfWrapper<WrappedType>()), resultGPR);
+    failureCases.append(jit.branchTestPtr(CCallHelpers::Zero, resultGPR));
+    failureCases.append(branchIfNotWeakIsLive(jit, resultGPR));
+    jit.loadPtr(CCallHelpers::Address(resultGPR, JSC::WeakImpl::offsetOfJSValue() + JSC::JSValue::offsetOfPayload()), resultGPR);
+}
+
+template<typename WrappedType, typename ToJSFunction>
+void toWrapper(CCallHelpers& jit, const JSC::DOMJIT::PatchpointParams& params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function)
+{
+    ASSERT(wrapped != result.payloadGPR());
+    ASSERT(globalObject != result.payloadGPR());
+    GPRReg payloadGPR = result.payloadGPR();
+    CCallHelpers::JumpList slowCases;
+    slowCases.append(branchIfNotWorldIsNormal(jit, globalObject));
+    tryLookUpWrapperCache<WrappedType>(jit, slowCases, wrapped, payloadGPR);
+    jit.boxCell(payloadGPR, result);
+    params.addSlowPathCall(slowCases, jit, function, result, globalObject, wrapped);
+}
+
+inline CCallHelpers::Jump branchIfDOMWrapper(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branch8(
+        CCallHelpers::AboveOrEqual,
+        CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()),
+        CCallHelpers::TrustedImm32(JSC::JSType(JSDOMWrapperType)));
+}
+
+inline CCallHelpers::Jump branchIfNotDOMWrapper(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branch8(
+        CCallHelpers::Below,
+        CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()),
+        CCallHelpers::TrustedImm32(JSC::JSType(JSDOMWrapperType)));
+}
+
+inline CCallHelpers::Jump branchIfNode(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branch8(
+        CCallHelpers::AboveOrEqual,
+        CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()),
+        CCallHelpers::TrustedImm32(JSC::JSType(JSNodeType)));
+}
+
+inline CCallHelpers::Jump branchIfNotNode(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branch8(
+        CCallHelpers::Below,
+        CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()),
+        CCallHelpers::TrustedImm32(JSC::JSType(JSNodeType)));
+}
+
+inline CCallHelpers::Jump branchIfElement(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branch8(
+        CCallHelpers::AboveOrEqual,
+        CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()),
+        CCallHelpers::TrustedImm32(JSC::JSType(JSElementType)));
+}
+
+inline CCallHelpers::Jump branchIfNotElement(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branch8(
+        CCallHelpers::Below,
+        CCallHelpers::Address(target, JSC::JSCell::typeInfoTypeOffset()),
+        CCallHelpers::TrustedImm32(JSC::JSType(JSElementType)));
+}
+
+inline CCallHelpers::Jump branchIfDocumentWrapper(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branchIfType(target, JSC::JSType(JSDocumentWrapperType));
+}
+
+inline CCallHelpers::Jump branchIfNotDocumentWrapper(CCallHelpers& jit, GPRReg target)
+{
+    return jit.branchIfNotType(target, JSC::JSType(JSDocumentWrapperType));
+}
+
+} }
+
+#endif

Added: trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp (0 => 207013)


--- trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp	                        (rev 0)
+++ trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp	2016-10-10 19:57:55 UTC (rev 207013)
@@ -0,0 +1,152 @@
+/*
+ * 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 "JSNode.h"
+
+#if ENABLE(JIT)
+
+#include "DOMJITHelpers.h"
+#include "JSDOMWrapper.h"
+#include "Node.h"
+#include <domjit/DOMJITPatchpoint.h>
+#include <domjit/DOMJITPatchpointParams.h>
+
+using namespace JSC;
+
+namespace WebCore {
+
+enum class IsContainerGuardRequirement { Required, NotRequired };
+
+template<typename WrappedNode>
+EncodedJSValue toWrapperSlow(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, void* result)
+{
+    ASSERT(exec);
+    ASSERT(result);
+    ASSERT(globalObject);
+    return JSValue::encode(toJS(exec, static_cast<JSDOMGlobalObject*>(globalObject), *static_cast<WrappedNode*>(result)));
+}
+
+template<typename WrappedNode>
+static Ref<DOMJIT::Patchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
+{
+    Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+    patchpoint->numGPScratchRegisters = 1;
+    patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+        JSValueRegs result = params[0].jsValueRegs();
+        GPRReg globalObject = params[1].gpr();
+        GPRReg node = params[2].gpr();
+        GPRReg scratch = params.gpScratch(0);
+
+        CCallHelpers::JumpList nullCases;
+        // Load a wrapped object. "node" should be already type checked by CheckDOM.
+        jit.loadPtr(CCallHelpers::Address(node, JSNode::offsetOfWrapped()), scratch);
+
+        if (isContainerGuardRequirement == IsContainerGuardRequirement::Required)
+            nullCases.append(jit.branchTest32(CCallHelpers::Zero, CCallHelpers::Address(scratch, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsContainer())));
+
+        jit.loadPtr(CCallHelpers::Address(scratch, offset), scratch);
+        nullCases.append(jit.branchTestPtr(CCallHelpers::Zero, scratch));
+
+        DOMJITHelpers::toWrapper<WrappedNode>(jit, params, scratch, globalObject, result, toWrapperSlow<WrappedNode>);
+        CCallHelpers::Jump done = jit.jump();
+
+        nullCases.link(&jit);
+        jit.moveValue(jsNull(), result);
+        done.link(&jit);
+        return CCallHelpers::JumpList();
+    });
+    return patchpoint;
+}
+
+static Ref<DOMJIT::Patchpoint> checkNode()
+{
+    Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+    patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+        CCallHelpers::JumpList failureCases;
+        failureCases.append(DOMJITHelpers::branchIfNotNode(jit, params[0].gpr()));
+        return failureCases;
+    });
+    return patchpoint;
+}
+
+// Node#firstChild.
+Ref<DOMJIT::Patchpoint> NodeFirstChildDOMJIT::checkDOM()
+{
+    return checkNode();
+}
+
+Ref<DOMJIT::Patchpoint> NodeFirstChildDOMJIT::callDOM()
+{
+    return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
+}
+
+// Node#lastChild.
+Ref<DOMJIT::Patchpoint> NodeLastChildDOMJIT::checkDOM()
+{
+    return checkNode();
+}
+
+Ref<DOMJIT::Patchpoint> NodeLastChildDOMJIT::callDOM()
+{
+    return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
+}
+
+// Node#nextSibling.
+Ref<DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::checkDOM()
+{
+    return checkNode();
+}
+
+Ref<DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::callDOM()
+{
+    return createCallDOMForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+}
+
+// Node#previousSibling.
+Ref<DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::checkDOM()
+{
+    return checkNode();
+}
+
+Ref<DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::callDOM()
+{
+    return createCallDOMForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+}
+
+// Node#parentNode.
+Ref<DOMJIT::Patchpoint> NodeParentNodeDOMJIT::checkDOM()
+{
+    return checkNode();
+}
+
+Ref<DOMJIT::Patchpoint> NodeParentNodeDOMJIT::callDOM()
+{
+    return createCallDOMForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
+}
+
+}
+
+#endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to