Title: [207239] trunk
Revision
207239
Author
utatane....@gmail.com
Date
2016-10-12 13:47:51 -0700 (Wed, 12 Oct 2016)

Log Message

[DOMJIT][JSC] Explore the way to embed nodeType into JSC::JSType in WebCore
https://bugs.webkit.org/show_bug.cgi?id=163245

Reviewed by Filip Pizlo.

Source/_javascript_Core:

We reserve the highest bit of JSC::JSType for extensions outside JSC.
JSC does not use JSType bits so many: only 52 types are defined.

And we extend CallDOM patchpoint to claim that it does not require a global object.
This global object is used to generate a DOM wrapper. However, nodeType does not require
it since it just returns integer. In the future, we will extend CallDOM to claim
its result type. And we can decide this `requireGlobalObject` condition automatically
according to the result type.

* _javascript_Core.xcodeproj/project.pbxproj:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleDOMJITGetter):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasCheckDOMPatchpoint):
(JSC::DFG::Node::checkDOMPatchpoint):
(JSC::DFG::Node::hasCallDOMPatchpoint):
(JSC::DFG::Node::callDOMPatchpoint):
(JSC::DFG::Node::hasDOMJIT): Deleted.
(JSC::DFG::Node::domJIT): Deleted.
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCallDOM):
(JSC::DFG::SpeculativeJIT::compileCheckDOM):
* domjit/DOMJITCallDOMPatchpoint.h: Copied from Source/_javascript_Core/domjit/DOMJITGetterSetter.h.
(JSC::DOMJIT::CallDOMPatchpoint::create):
* domjit/DOMJITGetterSetter.h:
* domjit/DOMJITPatchpoint.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
* jsc.cpp:
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LowLevelInterpreter.asm:
* runtime/JSType.h:

Source/WebCore:

Node.nodeType accessor is so frequently called. For example, jQuery's $ function uses
this to distinguish DOM objects from the other JS objects. So every time you call `$(dom)`,
nodeType accessor is called. In addition to that, jQuery's prev, next, parent etc. also uses
this `nodeType`. And Ember.js also uses it. And ... So this function is super critical for DOM
performance.

The challenge is that there is no room for putting NodeType into C++ Node class. Node class
has a 32bit field to store some data. However, these bits are already exhausted. Extending
Node class is unacceptable since it significantly enlarges memory consumption of WebKit (Node
is everywhere!). Unfortunately, current Node::nodeType is implemented as a virtual function
even though this function is frequently called from JS world.

Interestingly, we already store some duplicate data in JSObject, JSC::JSType. WebCore already
extends it with JSElementType, JSNodeType, and JSDocumentWrapperType. And these types are
corresponding to specific NodeTypes. For example, JSElementType should have ELEMENT_NODE type.

This patch further extends this JSC::JSType in WebCore side safely. We embed NodeType bits into
JSC::JSType. This design offers significantly faster nodeType implementation. Furthermore, it
makes DOMJIT easy for nodeType accessor.

Even without the IC change[1], Dromaeo dom-query shows 8 - 10% improvement,
1452.96 runs/s vs 1578.56 runs/s. We can expect that this improvement will be applied to the
other benchmarks / real applications when the IC change is landed.

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

* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMWrapper.h:
* bindings/js/JSNodeCustom.h:
(WebCore::JSNode::nodeType):
* bindings/scripts/CodeGeneratorJS.pm:
(GetJSTypeForNode):
(GenerateHeader):
* dom/Node.idl:
* dom/NodeConstants.h: Copied from Source/_javascript_Core/domjit/DOMJITGetterSetter.h.
* domjit/JSNodeDOMJIT.cpp:
(WebCore::createCallDOMForOffsetAccess):
(WebCore::NodeFirstChildDOMJIT::callDOM):
(WebCore::NodeLastChildDOMJIT::callDOM):
(WebCore::NodeNextSiblingDOMJIT::callDOM):
(WebCore::NodePreviousSiblingDOMJIT::callDOM):
(WebCore::NodeParentNodeDOMJIT::callDOM):
(WebCore::NodeNodeTypeDOMJIT::checkDOM):
(WebCore::NodeNodeTypeDOMJIT::callDOM):

LayoutTests:

* js/dom/domjit-accessor-node-type.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (207238 => 207239)


--- trunk/LayoutTests/ChangeLog	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/LayoutTests/ChangeLog	2016-10-12 20:47:51 UTC (rev 207239)
@@ -1,3 +1,12 @@
+2016-10-12  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DOMJIT][JSC] Explore the way to embed nodeType into JSC::JSType in WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=163245
+
+        Reviewed by Filip Pizlo.
+
+        * js/dom/domjit-accessor-node-type.html: Added.
+
 2016-10-12  Chris Dumez  <cdu...@apple.com>
 
         Update more events to stop using legacy [ConstructorTemplate=Event]

Added: trunk/LayoutTests/js/dom/domjit-accessor-node-type.html (0 => 207239)


--- trunk/LayoutTests/js/dom/domjit-accessor-node-type.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/domjit-accessor-node-type.html	2016-10-12 20:47:51 UTC (rev 207239)
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<iframe id="xmlframe" _onload_="frameLoaded()" style="height:0px" src="" version='1.0' encoding='UTF-8'?><body/>"></iframe>
+<script>
+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 = [
+        [document.body, Node.ELEMENT_NODE],
+        [document.createAttribute('Cocoa'), Node.ATTRIBUTE_NODE],
+        [document.createTextNode('Cocoa'), Node.TEXT_NODE],
+        [xmlDocument.createCDATASection('test'), Node.CDATA_SECTION_NODE],
+        [xmlDocument.createProcessingInstruction('target', 'test'), Node.PROCESSING_INSTRUCTION_NODE],
+        [document.createComment('Cocoa'), Node.COMMENT_NODE],
+        [document, Node.DOCUMENT_NODE],
+        [document.doctype, Node.DOCUMENT_TYPE_NODE],
+        [document.createDocumentFragment(), Node.DOCUMENT_FRAGMENT_NODE],
+    ];
+
+    for ([target, result] of targets) {
+        var text = `
+            function test${result}(element, result)
+            {
+                for (var i = 0; i < 1e4; ++i) {
+                    if (element.nodeType !== result)
+                        return false;
+                }
+                return true;
+            }
+        `;
+        shouldBeTrue(`(${text})(target, ${result})`);
+    }
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+function frameLoaded()
+{
+    runTest();
+}
+</script>
+<script src=""
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (207238 => 207239)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-12 20:47:51 UTC (rev 207239)
@@ -1,3 +1,48 @@
+2016-10-12  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DOMJIT][JSC] Explore the way to embed nodeType into JSC::JSType in WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=163245
+
+        Reviewed by Filip Pizlo.
+
+        We reserve the highest bit of JSC::JSType for extensions outside JSC.
+        JSC does not use JSType bits so many: only 52 types are defined.
+
+        And we extend CallDOM patchpoint to claim that it does not require a global object.
+        This global object is used to generate a DOM wrapper. However, nodeType does not require
+        it since it just returns integer. In the future, we will extend CallDOM to claim
+        its result type. And we can decide this `requireGlobalObject` condition automatically
+        according to the result type.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleDOMJITGetter):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.h:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasCheckDOMPatchpoint):
+        (JSC::DFG::Node::checkDOMPatchpoint):
+        (JSC::DFG::Node::hasCallDOMPatchpoint):
+        (JSC::DFG::Node::callDOMPatchpoint):
+        (JSC::DFG::Node::hasDOMJIT): Deleted.
+        (JSC::DFG::Node::domJIT): Deleted.
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCallDOM):
+        (JSC::DFG::SpeculativeJIT::compileCheckDOM):
+        * domjit/DOMJITCallDOMPatchpoint.h: Copied from Source/_javascript_Core/domjit/DOMJITGetterSetter.h.
+        (JSC::DOMJIT::CallDOMPatchpoint::create):
+        * domjit/DOMJITGetterSetter.h:
+        * domjit/DOMJITPatchpoint.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
+        * jsc.cpp:
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/JSType.h:
+
 2016-10-12  Keith Miller  <keith_mil...@apple.com>
 
         Handle non-function, non-undefined comparator in Array.prototype.sort

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (207238 => 207239)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-12 20:47:51 UTC (rev 207239)
@@ -2096,6 +2096,7 @@
 		E33F50851B8437A000413856 /* JSInternalPromiseDeferred.h in Headers */ = {isa = PBXBuildFile; fileRef = E33F50831B8437A000413856 /* JSInternalPromiseDeferred.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E33F50871B8449EF00413856 /* JSInternalPromiseConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E33F50861B8449EF00413856 /* JSInternalPromiseConstructor.lut.h */; };
 		E354622B1B6065D100545386 /* ConstructAbility.h in Headers */ = {isa = PBXBuildFile; fileRef = E354622A1B6065D100545386 /* ConstructAbility.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E3555B8A1DAE03A500F36921 /* DOMJITCallDOMPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3555B891DAE03A200F36921 /* DOMJITCallDOMPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E355F3521B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */; };
 		E355F3531B7DC85300C50DC5 /* ModuleLoaderPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E355F3511B7DC85300C50DC5 /* ModuleLoaderPrototype.h */; };
 		E35E035F1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E35E035D1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp */; };
@@ -4399,6 +4400,7 @@
 		E33F50861B8449EF00413856 /* JSInternalPromiseConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSInternalPromiseConstructor.lut.h; sourceTree = "<group>"; };
 		E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = InternalPromiseConstructor.js; sourceTree = "<group>"; };
 		E354622A1B6065D100545386 /* ConstructAbility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstructAbility.h; sourceTree = "<group>"; };
+		E3555B891DAE03A200F36921 /* DOMJITCallDOMPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITCallDOMPatchpoint.h; sourceTree = "<group>"; };
 		E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleLoaderPrototype.cpp; sourceTree = "<group>"; };
 		E355F3511B7DC85300C50DC5 /* ModuleLoaderPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleLoaderPrototype.h; sourceTree = "<group>"; };
 		E35E035D1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorInstrumentationObject.cpp; sourceTree = "<group>"; };
@@ -7195,6 +7197,7 @@
 		E3FF752D1D9CE9EA00C7E16D /* domjit */ = {
 			isa = PBXGroup;
 			children = (
+				E3555B891DAE03A200F36921 /* DOMJITCallDOMPatchpoint.h */,
 				E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */,
 				E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */,
 				E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */,
@@ -8072,6 +8075,7 @@
 				A7C1EAF017987AB600299DB2 /* CLoopStackInlines.h in Headers */,
 				BC18C4270E16F5CD00B34460 /* JSString.h in Headers */,
 				86E85539111B9968001AF51E /* JSStringBuilder.h in Headers */,
+				E3555B8A1DAE03A500F36921 /* DOMJITCallDOMPatchpoint.h in Headers */,
 				70EC0EC31AA0D7DA00B6AAFA /* JSStringIterator.h in Headers */,
 				0F070A471D543A8B006E7232 /* CellContainer.h in Headers */,
 				2600B5A7152BAAA70091EE5F /* JSStringJoiner.h in Headers */,

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (207238 => 207239)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -2687,12 +2687,19 @@
         return false;
     addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), thisNode);
 
+    Ref<DOMJIT::Patchpoint> checkDOMPatchpoint = domJIT->checkDOM();
+    m_graph.m_domJITPatchpoints.append(checkDOMPatchpoint.ptr());
     // We do not need to emit CheckCell thingy here. When the custom accessor is replaced to different one, Structure transition occurs.
-    addToGraph(CheckDOM, OpInfo(domJIT), OpInfo(domJIT->thisClassInfo()), thisNode);
-    Node* globalObject = addToGraph(GetGlobalObject, thisNode);
-    addVarArgChild(globalObject); // GlobalObject of thisNode is always used to create a DOMWrapper.
+    addToGraph(CheckDOM, OpInfo(checkDOMPatchpoint.ptr()), OpInfo(domJIT->thisClassInfo()), thisNode);
+
+    Ref<DOMJIT::CallDOMPatchpoint> callDOMPatchpoint = domJIT->callDOM();
+    m_graph.m_domJITPatchpoints.append(callDOMPatchpoint.ptr());
+    if (callDOMPatchpoint->requireGlobalObject) {
+        Node* globalObject = addToGraph(GetGlobalObject, thisNode);
+        addVarArgChild(globalObject); // GlobalObject of thisNode is always used to create a DOMWrapper.
+    }
     addVarArgChild(thisNode);
-    set(VirtualRegister(resultOperand), addToGraph(Node::VarArg, CallDOM, OpInfo(domJIT), OpInfo(prediction)));
+    set(VirtualRegister(resultOperand), addToGraph(Node::VarArg, CallDOM, OpInfo(callDOMPatchpoint.ptr()), OpInfo(prediction)));
     return true;
 }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (207238 => 207239)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -1703,10 +1703,14 @@
             fixEdge<CellUse>(node->child1());
             break;
 
-        case CallDOM:
-            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0)); // GlobalObject.
-            fixEdge<CellUse>(m_graph.varArgChild(node, 1)); // DOM.
+        case CallDOM: {
+            int childIndex = 0;
+            DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMPatchpoint();
+            if (patchpoint->requireGlobalObject)
+                fixEdge<KnownCellUse>(m_graph.varArgChild(node, childIndex++)); // GlobalObject.
+            fixEdge<CellUse>(m_graph.varArgChild(node, childIndex++)); // DOM.
             break;
+        }
 
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (207238 => 207239)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -904,6 +904,7 @@
     HashMap<CodeBlock*, std::unique_ptr<BytecodeKills>> m_bytecodeKills;
     HashSet<std::pair<JSObject*, PropertyOffset>> m_safeToLoad;
     HashMap<PropertyTypeKey, InferredType::Descriptor> m_inferredTypes;
+    Vector<RefPtr<DOMJIT::Patchpoint>> m_domJITPatchpoints;
     std::unique_ptr<Dominators> m_dominators;
     std::unique_ptr<PrePostNumbering> m_prePostNumbering;
     std::unique_ptr<NaturalLoops> m_naturalLoops;

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (207238 => 207239)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -59,7 +59,8 @@
 namespace JSC {
 
 namespace DOMJIT {
-class GetterSetter;
+class Patchpoint;
+class CallDOMPatchpoint;
 }
 
 namespace Profiler {
@@ -2314,17 +2315,28 @@
         return m_opInfo.as<BasicBlockLocation*>();
     }
 
-    bool hasDOMJIT() const
+    bool hasCheckDOMPatchpoint() const
     {
-        return op() == CheckDOM || op() == CallDOM;
+        return op() == CheckDOM;
     }
 
-    DOMJIT::GetterSetter* domJIT()
+    DOMJIT::Patchpoint* checkDOMPatchpoint()
     {
-        ASSERT(hasDOMJIT());
-        return m_opInfo.as<DOMJIT::GetterSetter*>();
+        ASSERT(hasCheckDOMPatchpoint());
+        return m_opInfo.as<DOMJIT::Patchpoint*>();
     }
 
+    bool hasCallDOMPatchpoint() const
+    {
+        return op() == CallDOM;
+    }
+
+    DOMJIT::CallDOMPatchpoint* callDOMPatchpoint()
+    {
+        ASSERT(hasCallDOMPatchpoint());
+        return m_opInfo.as<DOMJIT::CallDOMPatchpoint*>();
+    }
+
     bool hasClassInfo() const
     {
         return op() == CheckDOM;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (207238 => 207239)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -7130,29 +7130,31 @@
 
 void SpeculativeJIT::compileCallDOM(Node* node)
 {
-    Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->callDOM();
+    DOMJIT::CallDOMPatchpoint* patchpoint = node->callDOMPatchpoint();
 
     Vector<GPRReg> gpScratch;
     Vector<FPRReg> fpScratch;
     Vector<DOMJIT::Value> regs;
 
-    // FIXME: patchpoint should have a way to tell this can reuse "base" register.
-    // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
-    SpeculateCellOperand globalObject(this, m_jit.graph().varArgChild(node, 0));
-    SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 1));
     JSValueRegsTemporary result(this);
-
     regs.append(result.regs());
-    regs.append(DOMJIT::Value(globalObject.gpr(), m_state.forNode(m_jit.graph().varArgChild(node, 0)).value()));
-    regs.append(DOMJIT::Value(base.gpr(), m_state.forNode(m_jit.graph().varArgChild(node, 1)).value()));
-#if USE(JSVALUE64)
-    regs.append(static_cast<GPRReg>(GPRInfo::tagMaskRegister));
-    regs.append(static_cast<GPRReg>(GPRInfo::tagTypeNumberRegister));
-#endif
 
+    int childIndex = 0;
+
+    Optional<SpeculateCellOperand> globalObject;
+    if (patchpoint->requireGlobalObject) {
+        Edge& globalObjectEdge = m_jit.graph().varArgChild(node, childIndex++);
+        globalObject = SpeculateCellOperand(this, globalObjectEdge);
+        regs.append(DOMJIT::Value(globalObject->gpr(), m_state.forNode(globalObjectEdge).value()));
+    }
+
+    Edge& baseEdge = m_jit.graph().varArgChild(node, childIndex++);
+    SpeculateCellOperand base(this, baseEdge);
+    regs.append(DOMJIT::Value(base.gpr(), m_state.forNode(baseEdge).value()));
+
     Vector<GPRTemporary> gpTempraries;
     Vector<FPRTemporary> fpTempraries;
-    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
+    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, *patchpoint);
     DOMJITPatchpointParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     patchpoint->generator()->run(m_jit, params);
     jsValueResult(result.regs(), node);
@@ -7161,7 +7163,7 @@
 void SpeculativeJIT::compileCheckDOM(Node* node)
 {
     // FIXME: We can add the fallback implementation that inlines jsDynamicCast things here.
-    Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->checkDOM();
+    DOMJIT::Patchpoint* patchpoint = node->checkDOMPatchpoint();
 
     Vector<GPRReg> gpScratch;
     Vector<FPRReg> fpScratch;
@@ -7173,7 +7175,7 @@
 
     Vector<GPRTemporary> gpTempraries;
     Vector<FPRTemporary> fpTempraries;
-    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
+    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, *patchpoint);
 
     DOMJITPatchpointParams params(this, WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
     CCallHelpers::JumpList failureCases = patchpoint->generator()->run(m_jit, params);

Copied: trunk/Source/_javascript_Core/domjit/DOMJITCallDOMPatchpoint.h (from rev 207238, trunk/Source/_javascript_Core/domjit/DOMJITGetterSetter.h) (0 => 207239)


--- trunk/Source/_javascript_Core/domjit/DOMJITCallDOMPatchpoint.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/domjit/DOMJITCallDOMPatchpoint.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -0,0 +1,54 @@
+/*
+ * 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
+
+#if ENABLE(JIT)
+
+#include "DOMJITPatchpoint.h"
+#include "RegisterSet.h"
+
+namespace JSC { namespace DOMJIT {
+
+class CallDOMPatchpoint : public Patchpoint {
+public:
+    static Ref<CallDOMPatchpoint> create()
+    {
+        return adoptRef(*new CallDOMPatchpoint());
+    }
+
+    // To look up DOMWrapper cache, GlobalObject is required.
+    // FIXME: Later, we will extend this patchpoint to represent the result type by DOMJIT::Signature.
+    // And after that, we will automatically pass a global object when the result type includes a DOM wrapper thing.
+    // https://bugs.webkit.org/show_bug.cgi?id=162980
+    bool requireGlobalObject { true };
+
+private:
+    CallDOMPatchpoint() = default;
+};
+
+} }
+
+#endif

Modified: trunk/Source/_javascript_Core/domjit/DOMJITGetterSetter.h (207238 => 207239)


--- trunk/Source/_javascript_Core/domjit/DOMJITGetterSetter.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/domjit/DOMJITGetterSetter.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include "DOMJITPatchpoint.h"
+#include "DOMJITCallDOMPatchpoint.h"
 #include "PropertySlot.h"
 #include "PutPropertySlot.h"
 #include "SpeculatedType.h"
@@ -51,7 +51,7 @@
     const ClassInfo* thisClassInfo() const { return m_thisClassInfo; }
 
 #if ENABLE(JIT)
-    virtual Ref<DOMJIT::Patchpoint> callDOM() = 0;
+    virtual Ref<DOMJIT::CallDOMPatchpoint> callDOM() = 0;
     virtual Ref<DOMJIT::Patchpoint> checkDOM() = 0;
 #endif
 

Modified: trunk/Source/_javascript_Core/domjit/DOMJITPatchpoint.h (207238 => 207239)


--- trunk/Source/_javascript_Core/domjit/DOMJITPatchpoint.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/domjit/DOMJITPatchpoint.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -62,9 +62,10 @@
     uint8_t numGPScratchRegisters { 0 };
     uint8_t numFPScratchRegisters { 0 };
 
-private:
+protected:
     Patchpoint() = default;
 
+private:
     RefPtr<PatchpointGenerator> m_generator;
 };
 

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (207238 => 207239)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -8724,7 +8724,7 @@
     {
         LValue cell = lowCell(m_node->child1());
 
-        RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->checkDOM();
+        DOMJIT::Patchpoint* domJIT = m_node->checkDOMPatchpoint();
 
         PatchpointValue* patchpoint = m_out.patchpoint(Void);
         patchpoint->appendSomeRegister(cell);
@@ -8769,13 +8769,25 @@
 
     void compileCallDOM()
     {
-        LValue globalObject = lowCell(m_graph.varArgChild(m_node, 0));
-        LValue cell = lowCell(m_graph.varArgChild(m_node, 1));
+        DOMJIT::CallDOMPatchpoint* domJIT = m_node->callDOMPatchpoint();
+        int childIndex = 0;
 
-        RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->callDOM();
+        LValue globalObject;
+        JSValue globalObjectConstant;
+        if (domJIT->requireGlobalObject) {
+            Edge& globalObjectEdge = m_graph.varArgChild(m_node, childIndex++);
+            globalObject = lowCell(globalObjectEdge);
+            globalObjectConstant = m_state.forNode(globalObjectEdge).value();
+        }
+
+        Edge& baseEdge = m_graph.varArgChild(m_node, childIndex++);
+        LValue base = lowCell(baseEdge);
+        JSValue baseConstant = m_state.forNode(baseEdge).value();
+
         PatchpointValue* patchpoint = m_out.patchpoint(Int64);
-        patchpoint->appendSomeRegister(globalObject);
-        patchpoint->appendSomeRegister(cell);
+        if (domJIT->requireGlobalObject)
+            patchpoint->appendSomeRegister(globalObject);
+        patchpoint->appendSomeRegister(base);
         patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
         patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
         RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
@@ -8786,8 +8798,6 @@
 
         State* state = &m_ftlState;
         Node* node = m_node;
-        JSValue child1Constant = m_state.forNode(m_graph.varArgChild(m_node, 0)).value();
-        JSValue child2Constant = m_state.forNode(m_graph.varArgChild(m_node, 1)).value();
         patchpoint->setGenerator(
             [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
                 AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -8796,11 +8806,11 @@
                 Vector<FPRReg> fpScratch;
                 Vector<DOMJIT::Value> regs;
 
-                // FIXME: patchpoint should have a way to tell this can reuse "base" register.
-                // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
+                int childIndex = 1;
                 regs.append(JSValueRegs(params[0].gpr()));
-                regs.append(DOMJIT::Value(params[1].gpr(), child1Constant));
-                regs.append(DOMJIT::Value(params[2].gpr(), child2Constant));
+                if (domJIT->requireGlobalObject)
+                    regs.append(DOMJIT::Value(params[childIndex++].gpr(), globalObjectConstant));
+                regs.append(DOMJIT::Value(params[childIndex++].gpr(), baseConstant));
 
                 for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
                     gpScratch.append(params.gpScratch(i));

Modified: trunk/Source/_javascript_Core/jsc.cpp (207238 => 207239)


--- trunk/Source/_javascript_Core/jsc.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/jsc.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -620,12 +620,13 @@
             return patchpoint;
         }
 
-        Ref<DOMJIT::Patchpoint> callDOM() override
+        Ref<DOMJIT::CallDOMPatchpoint> callDOM() override
         {
-            Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+            Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
+            patchpoint->requireGlobalObject = false;
             patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
                 JSValueRegs results = params[0].jsValueRegs();
-                GPRReg dom = params[2].gpr();
+                GPRReg dom = params[1].gpr();
 
                 params.addSlowPathCall(jit.jump(), jit, static_cast<EncodedJSValue(*)(ExecState*, void*)>([](ExecState*, void* pointer) {
                     return JSValue::encode(jsNumber(static_cast<DOMJITGetter*>(pointer)->value()));

Modified: trunk/Source/_javascript_Core/llint/LLIntData.cpp (207238 => 207239)


--- trunk/Source/_javascript_Core/llint/LLIntData.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/llint/LLIntData.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -161,16 +161,16 @@
     STATIC_ASSERT(JSFunctionType == 23);
     STATIC_ASSERT(ArrayType == 31);
     STATIC_ASSERT(DerivedArrayType == 32);
-    STATIC_ASSERT(ProxyObjectType == 116);
-    STATIC_ASSERT(Int8ArrayType == 100);
-    STATIC_ASSERT(Int16ArrayType == 101);
-    STATIC_ASSERT(Int32ArrayType == 102);
-    STATIC_ASSERT(Uint8ArrayType == 103);
-    STATIC_ASSERT(Uint8ClampedArrayType == 104);
-    STATIC_ASSERT(Uint16ArrayType == 105);
-    STATIC_ASSERT(Uint32ArrayType == 106);
-    STATIC_ASSERT(Float32ArrayType == 107);
-    STATIC_ASSERT(Float64ArrayType == 108);
+    STATIC_ASSERT(ProxyObjectType == 49);
+    STATIC_ASSERT(Int8ArrayType == 33);
+    STATIC_ASSERT(Int16ArrayType == 34);
+    STATIC_ASSERT(Int32ArrayType == 35);
+    STATIC_ASSERT(Uint8ArrayType == 36);
+    STATIC_ASSERT(Uint8ClampedArrayType == 37);
+    STATIC_ASSERT(Uint16ArrayType == 38);
+    STATIC_ASSERT(Uint32ArrayType == 39);
+    STATIC_ASSERT(Float32ArrayType == 40);
+    STATIC_ASSERT(Float64ArrayType == 41);
     STATIC_ASSERT(MasqueradesAsUndefined == 1);
     STATIC_ASSERT(ImplementsDefaultHasInstance == 2);
     STATIC_ASSERT(FirstConstantRegisterIndex == 0x40000000);

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (207238 => 207239)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2016-10-12 20:47:51 UTC (rev 207239)
@@ -350,19 +350,19 @@
 const JSFunctionType = 23
 const ArrayType = 31
 const DerivedArrayType = 32
-const ProxyObjectType = 116
+const ProxyObjectType = 49
 
 # The typed array types need to be numbered in a particular order because of the manually written
 # switch statement in get_by_val and put_by_val.
-const Int8ArrayType = 100
-const Int16ArrayType = 101
-const Int32ArrayType = 102
-const Uint8ArrayType = 103
-const Uint8ClampedArrayType = 104
-const Uint16ArrayType = 105
-const Uint32ArrayType = 106
-const Float32ArrayType = 107
-const Float64ArrayType = 108
+const Int8ArrayType = 33
+const Int16ArrayType = 34
+const Int32ArrayType = 35
+const Uint8ArrayType = 36
+const Uint8ClampedArrayType = 37
+const Uint16ArrayType = 38
+const Uint32ArrayType = 39
+const Float32ArrayType = 40
+const Float64ArrayType = 41
 
 const FirstArrayType = Int8ArrayType
 const LastArrayType = Float64ArrayType

Modified: trunk/Source/_javascript_Core/runtime/JSType.h (207238 => 207239)


--- trunk/Source/_javascript_Core/runtime/JSType.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/_javascript_Core/runtime/JSType.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -65,7 +65,7 @@
     ArrayType,
     DerivedArrayType,
 
-    Int8ArrayType = 100,
+    Int8ArrayType,
     Int16ArrayType,
     Int32ArrayType,
     Uint8ArrayType,
@@ -87,8 +87,10 @@
     JSSetType,
 
     LastJSCObjectType = JSSetType,
+    MaxJSType = 0b11111111,
 };
 
-COMPILE_ASSERT(sizeof(JSType) == sizeof(uint8_t), sizeof_jstype_is_one_byte);
+static_assert(sizeof(JSType) == sizeof(uint8_t), "sizeof(JSType) is one byte.");
+static_assert(LastJSCObjectType < 128, "The highest bit is reserved for embedder's extension.");
 
 } // namespace JSC

Modified: trunk/Source/WebCore/ChangeLog (207238 => 207239)


--- trunk/Source/WebCore/ChangeLog	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/ChangeLog	2016-10-12 20:47:51 UTC (rev 207239)
@@ -1,3 +1,55 @@
+2016-10-12  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DOMJIT][JSC] Explore the way to embed nodeType into JSC::JSType in WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=163245
+
+        Reviewed by Filip Pizlo.
+
+        Node.nodeType accessor is so frequently called. For example, jQuery's $ function uses
+        this to distinguish DOM objects from the other JS objects. So every time you call `$(dom)`,
+        nodeType accessor is called. In addition to that, jQuery's prev, next, parent etc. also uses
+        this `nodeType`. And Ember.js also uses it. And ... So this function is super critical for DOM
+        performance.
+
+        The challenge is that there is no room for putting NodeType into C++ Node class. Node class
+        has a 32bit field to store some data. However, these bits are already exhausted. Extending
+        Node class is unacceptable since it significantly enlarges memory consumption of WebKit (Node
+        is everywhere!). Unfortunately, current Node::nodeType is implemented as a virtual function
+        even though this function is frequently called from JS world.
+
+        Interestingly, we already store some duplicate data in JSObject, JSC::JSType. WebCore already
+        extends it with JSElementType, JSNodeType, and JSDocumentWrapperType. And these types are
+        corresponding to specific NodeTypes. For example, JSElementType should have ELEMENT_NODE type.
+
+        This patch further extends this JSC::JSType in WebCore side safely. We embed NodeType bits into
+        JSC::JSType. This design offers significantly faster nodeType implementation. Furthermore, it
+        makes DOMJIT easy for nodeType accessor.
+
+        Even without the IC change[1], Dromaeo dom-query shows 8 - 10% improvement,
+        1452.96 runs/s vs 1578.56 runs/s. We can expect that this improvement will be applied to the
+        other benchmarks / real applications when the IC change is landed.
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=163226
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMWrapper.h:
+        * bindings/js/JSNodeCustom.h:
+        (WebCore::JSNode::nodeType):
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GetJSTypeForNode):
+        (GenerateHeader):
+        * dom/Node.idl:
+        * dom/NodeConstants.h: Copied from Source/_javascript_Core/domjit/DOMJITGetterSetter.h.
+        * domjit/JSNodeDOMJIT.cpp:
+        (WebCore::createCallDOMForOffsetAccess):
+        (WebCore::NodeFirstChildDOMJIT::callDOM):
+        (WebCore::NodeLastChildDOMJIT::callDOM):
+        (WebCore::NodeNextSiblingDOMJIT::callDOM):
+        (WebCore::NodePreviousSiblingDOMJIT::callDOM):
+        (WebCore::NodeParentNodeDOMJIT::callDOM):
+        (WebCore::NodeNodeTypeDOMJIT::checkDOM):
+        (WebCore::NodeNodeTypeDOMJIT::callDOM):
+
 2016-10-12  Chris Dumez  <cdu...@apple.com>
 
         Update more events to stop using legacy [ConstructorTemplate=Event]

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (207238 => 207239)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2016-10-12 20:47:51 UTC (rev 207239)
@@ -6143,6 +6143,7 @@
 		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 */; };
+		E377FE4D1DADE16500CDD025 /* NodeConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D049931DADC04500718F3C /* NodeConstants.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E38838981BAD145F00D62EE3 /* ScriptModuleLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38838941BAD145F00D62EE3 /* ScriptModuleLoader.cpp */; };
 		E38838991BAD145F00D62EE3 /* ScriptModuleLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = E38838951BAD145F00D62EE3 /* ScriptModuleLoader.h */; };
 		E3B2F0EB1D7F4C9D00B0C9D1 /* LoadableClassicScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3B2F0E31D7F35EC00B0C9D1 /* LoadableClassicScript.cpp */; };
@@ -13784,6 +13785,7 @@
 		E3B2F0E71D7F35EC00B0C9D1 /* LoadableScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableScript.h; sourceTree = "<group>"; };
 		E3B2F0E81D7F35EC00B0C9D1 /* LoadableScriptClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableScriptClient.h; sourceTree = "<group>"; };
 		E3B2F0E91D7F3D3C00B0C9D1 /* LoadableScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadableScript.cpp; sourceTree = "<group>"; };
+		E3D049931DADC04500718F3C /* NodeConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeConstants.h; sourceTree = "<group>"; };
 		E3FA38611D716E7600AA5950 /* PendingScriptClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PendingScriptClient.h; sourceTree = "<group>"; };
 		E401C27417CE53EC00C41A35 /* ElementIteratorAssertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIteratorAssertions.h; sourceTree = "<group>"; };
 		E401E0A31C3C0B8300F34D10 /* StyleChange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleChange.h; sourceTree = "<group>"; };
@@ -23275,6 +23277,7 @@
 				63D7B32C0E78CD3F00F7617C /* NodeRenderStyle.h */,
 				E43105B716750F0C00DB2FB8 /* NodeTraversal.cpp */,
 				E43105BA16750F1600DB2FB8 /* NodeTraversal.h */,
+				E3D049931DADC04500718F3C /* NodeConstants.h */,
 				9382AAB10D8C386100F357A6 /* NodeWithIndex.h */,
 				E46B41F81CB24E70008F11DE /* NoEventDispatchAssertion.h */,
 				8369E58F1AFDD0300087DF68 /* NonDocumentTypeChildNode.idl */,
@@ -25847,6 +25850,7 @@
 				51058AE21D67C229009A538C /* MockGamepadProvider.h in Headers */,
 				5EA3D6DF1C859D7F00300BBB /* MockMediaEndpoint.h in Headers */,
 				CDF2B0131820540600F2B424 /* MockMediaPlayerMediaSource.h in Headers */,
+				E377FE4D1DADE16500CDD025 /* NodeConstants.h in Headers */,
 				CDF2B0151820540600F2B424 /* MockMediaSourcePrivate.h in Headers */,
 				07D6A4F41BED5F8800174146 /* MockRealtimeAudioSource.h in Headers */,
 				07D6A4F01BECF2D200174146 /* MockRealtimeMediaSource.h in Headers */,

Modified: trunk/Source/WebCore/bindings/js/JSDOMWrapper.h (207238 => 207239)


--- trunk/Source/WebCore/bindings/js/JSDOMWrapper.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/bindings/js/JSDOMWrapper.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "JSDOMGlobalObject.h"
+#include "NodeConstants.h"
 #include <runtime/JSDestructibleObject.h>
 
 namespace WebCore {
@@ -29,11 +30,26 @@
 class JSDOMWindow;
 class ScriptExecutionContext;
 
-static const uint8_t JSDOMWrapperType = JSC::LastJSCObjectType + 1;
-static const uint8_t JSNodeType = JSC::LastJSCObjectType + 2;
-static const uint8_t JSDocumentWrapperType = JSC::LastJSCObjectType + 3;
-static const uint8_t JSElementType = JSC::LastJSCObjectType + 4;
+// We encode Node type into JSType. The format is the following.
+// offset | 7 | 6 5 4 | 3 2 1 0  |
+// value  | 1 | Kind  | NodeType |
+static const uint8_t JSNodeTypeMask                  = 0b00001111;
 
+static const uint8_t JSDOMWrapperType                = 0b10000000;
+static const uint8_t JSNodeType                      = 0b10010000;
+static const uint8_t JSTextNodeType                  = JSNodeType | NodeConstants::TEXT_NODE;
+static const uint8_t JSProcessingInstructionNodeType = JSNodeType | NodeConstants::PROCESSING_INSTRUCTION_NODE;
+static const uint8_t JSDocumentTypeNodeType          = JSNodeType | NodeConstants::DOCUMENT_TYPE_NODE;
+static const uint8_t JSDocumentFragmentNodeType      = JSNodeType | NodeConstants::DOCUMENT_FRAGMENT_NODE;
+static const uint8_t JSDocumentWrapperType           = JSNodeType | NodeConstants::DOCUMENT_NODE;
+static const uint8_t JSCommentNodeType               = JSNodeType | NodeConstants::COMMENT_NODE;
+static const uint8_t JSCDATASectionNodeType          = JSNodeType | NodeConstants::CDATA_SECTION_NODE;
+static const uint8_t JSAttrNodeType                  = JSNodeType | NodeConstants::ATTRIBUTE_NODE;
+static const uint8_t JSElementType                   = 0b10100000 | NodeConstants::ELEMENT_NODE;
+
+static_assert(JSDOMWrapperType > JSC::LastJSCObjectType, "JSC::JSType offers the highest bit.");
+static_assert(NodeConstants::LastNodeType <= JSNodeTypeMask, "NodeType should be represented in 4bit.");
+
 class JSDOMObject : public JSC::JSDestructibleObject {
 public:
     typedef JSC::JSDestructibleObject Base;

Modified: trunk/Source/WebCore/bindings/js/JSNodeCustom.h (207238 => 207239)


--- trunk/Source/WebCore/bindings/js/JSNodeCustom.h	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/bindings/js/JSNodeCustom.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -85,4 +85,9 @@
     return value.asCell()->type() >= JSNodeType ? JSC::jsCast<JSNode*>(value) : nullptr;
 }
 
+ALWAYS_INLINE JSC::JSValue JSNode::nodeType(JSC::ExecState&) const
+{
+    return JSC::jsNumber(static_cast<uint8_t>(type()) & JSNodeTypeMask);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (207238 => 207239)


--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm	2016-10-12 20:47:51 UTC (rev 207239)
@@ -1170,6 +1170,40 @@
     return $result;
 }
 
+sub GetJSTypeForNode
+{
+    my ($codeGenerator, $interface) = @_;
+
+    if ($codeGenerator->InheritsInterface($interface, "Document")) {
+        return "JSDocumentWrapperType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "DocumentFragment")) {
+        return "JSDocumentFragmentNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "DocumentType")) {
+        return "JSDocumentTypeNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "ProcessingInstruction")) {
+        return "JSProcessingInstructionNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "CDATASection")) {
+        return "JSCDATASectionNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "Attr")) {
+        return "JSAttrNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "Comment")) {
+        return "JSCommentNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "Text")) {
+        return "JSTextNodeType";
+    }
+    if ($codeGenerator->InheritsInterface($interface, "Element")) {
+        return "JSElementType";
+    }
+    return "JSNodeType";
+}
+
 sub GenerateHeader
 {
     my ($object, $interface, $enumerations, $dictionaries) = @_;
@@ -1368,12 +1402,9 @@
     push(@headerContent, "    {\n");
     if (IsDOMGlobalObject($interface)) {
         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), info());\n");
-    } elsif ($codeGenerator->InheritsInterface($interface, "Document")) {
-        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSDocumentWrapperType), StructureFlags), info());\n");
-    } elsif ($codeGenerator->InheritsInterface($interface, "Element")) {
-        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSElementType), StructureFlags), info());\n");
     } elsif ($codeGenerator->InheritsInterface($interface, "Node")) {
-        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType(JSNodeType), StructureFlags), info());\n");
+        my $type = GetJSTypeForNode($codeGenerator, $interface);
+        push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSType($type), StructureFlags), info());\n");
     } else {
         push(@headerContent, "        return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());\n");
     }
@@ -1669,7 +1700,7 @@
             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, "    Ref<JSC::DOMJIT::CallDOMPatchpoint> callDOM() override;\n");
             push(@headerContent, "#endif\n");
             push(@headerContent, "};\n\n");
         }

Modified: trunk/Source/WebCore/dom/Node.idl (207238 => 207239)


--- trunk/Source/WebCore/dom/Node.idl	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/dom/Node.idl	2016-10-12 20:47:51 UTC (rev 207239)
@@ -46,7 +46,7 @@
     // FIXME: the spec says this can also raise on retrieval.
     [CEReactions, SetterMayThrowLegacyException] attribute DOMString? nodeValue;
 
-    readonly attribute unsigned short nodeType;
+    [DOMJIT, CustomGetter] readonly attribute unsigned short nodeType;
     [DOMJIT] readonly attribute Node? parentNode;
     readonly attribute NodeList childNodes;
     [DOMJIT] readonly attribute Node? firstChild;

Copied: trunk/Source/WebCore/dom/NodeConstants.h (from rev 207238, trunk/Source/_javascript_Core/domjit/DOMJITGetterSetter.h) (0 => 207239)


--- trunk/Source/WebCore/dom/NodeConstants.h	                        (rev 0)
+++ trunk/Source/WebCore/dom/NodeConstants.h	2016-10-12 20:47:51 UTC (rev 207239)
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+namespace WebCore {
+
+struct NodeConstants {
+    enum NodeType {
+        ELEMENT_NODE = 1,
+        ATTRIBUTE_NODE = 2,
+        TEXT_NODE = 3,
+        CDATA_SECTION_NODE = 4,
+        PROCESSING_INSTRUCTION_NODE = 7,
+        COMMENT_NODE = 8,
+        DOCUMENT_NODE = 9,
+        DOCUMENT_TYPE_NODE = 10,
+        DOCUMENT_FRAGMENT_NODE = 11,
+    };
+
+    enum DeprecatedNodeType {
+        ENTITY_REFERENCE_NODE = 5,
+        ENTITY_NODE = 6,
+        NOTATION_NODE = 12,
+    };
+
+    static const uint8_t LastNodeType = NOTATION_NODE;
+};
+
+} // namespace WebCore::NodeType

Modified: trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp (207238 => 207239)


--- trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp	2016-10-12 20:41:49 UTC (rev 207238)
+++ trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp	2016-10-12 20:47:51 UTC (rev 207239)
@@ -50,9 +50,9 @@
 }
 
 template<typename WrappedNode>
-static Ref<DOMJIT::Patchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
+static Ref<DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
 {
-    Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
     patchpoint->numGPScratchRegisters = 1;
     patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
         JSValueRegs result = params[0].jsValueRegs();
@@ -98,7 +98,7 @@
     return checkNode();
 }
 
-Ref<DOMJIT::Patchpoint> NodeFirstChildDOMJIT::callDOM()
+Ref<DOMJIT::CallDOMPatchpoint> NodeFirstChildDOMJIT::callDOM()
 {
     return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
 }
@@ -109,7 +109,7 @@
     return checkNode();
 }
 
-Ref<DOMJIT::Patchpoint> NodeLastChildDOMJIT::callDOM()
+Ref<DOMJIT::CallDOMPatchpoint> NodeLastChildDOMJIT::callDOM()
 {
     return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
 }
@@ -120,7 +120,7 @@
     return checkNode();
 }
 
-Ref<DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::callDOM()
+Ref<DOMJIT::CallDOMPatchpoint> NodeNextSiblingDOMJIT::callDOM()
 {
     return createCallDOMForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
 }
@@ -131,7 +131,7 @@
     return checkNode();
 }
 
-Ref<DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::callDOM()
+Ref<DOMJIT::CallDOMPatchpoint> NodePreviousSiblingDOMJIT::callDOM()
 {
     return createCallDOMForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
 }
@@ -142,11 +142,32 @@
     return checkNode();
 }
 
-Ref<DOMJIT::Patchpoint> NodeParentNodeDOMJIT::callDOM()
+Ref<DOMJIT::CallDOMPatchpoint> NodeParentNodeDOMJIT::callDOM()
 {
     return createCallDOMForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
 }
 
+// Node#nodeType.
+Ref<DOMJIT::Patchpoint> NodeNodeTypeDOMJIT::checkDOM()
+{
+    return checkNode();
 }
 
+Ref<DOMJIT::CallDOMPatchpoint> NodeNodeTypeDOMJIT::callDOM()
+{
+    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
+    patchpoint->requireGlobalObject = false;
+    patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+        JSValueRegs result = params[0].jsValueRegs();
+        GPRReg node = params[1].gpr();
+        jit.load8(CCallHelpers::Address(node, JSC::JSCell::typeInfoTypeOffset()), result.payloadGPR());
+        jit.and32(CCallHelpers::TrustedImm32(JSNodeTypeMask), result.payloadGPR());
+        jit.boxInt32(result.payloadGPR(), result);
+        return CCallHelpers::JumpList();
+    });
+    return patchpoint;
+}
+
+}
+
 #endif
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to