Title: [206846] trunk
Revision
206846
Author
[email protected]
Date
2016-10-05 22:20:10 -0700 (Wed, 05 Oct 2016)

Log Message

[DOMJIT] Add initial CheckDOM and CallDOM implementations
https://bugs.webkit.org/show_bug.cgi?id=162941

Reviewed by Filip Pizlo.

JSTests:

* stress/domjit-getter-poly.js: Added.
(shouldBe):
(access):
* stress/domjit-getter-proto.js: Added.
(shouldBe):
(access):
* stress/domjit-getter-super-poly.js: Added.
(shouldBe):
(access):
* stress/domjit-getter.js: Added.
(shouldBe):
(access):

Source/_javascript_Core:

This patch implements a prototype of DOMJIT accelerated getter.
We add two new DFG nodes, CheckDOM and CallDOM.

CheckDOM is used to filter inappropriate |this| object for DOM getter. Its functionality
is equivalent to jsDynamicCast's Check. You can use like "CheckDOM, @1, JSNode::info()",
and this CheckDOM incurs a BadType exit if the class of the given @1 is not a subclass of
JSNode::info().

CallDOM is used to emit actual DOM operations. It takes GlobalObject and checked DOM
object. And it returns JSValue as its result.

Both CheckDOM and CallDOM can take a DOMJIT::Patchpoint. This is somewhat code snippet
generator, and is injectable to DFG and FTL. DFG and FTL set up registers correctly
according to DOMJIT::Patchpoint's requirement and invoke this patchpoint generator to emit code.
While CallDOM always requires a patchpoint, ideally CheckDOM does not require it since
isSubclassOf check can be implemented in DFG / FTL side. However, some classes have a
faster way to query isSubclassOf. For example, JSNode in WebCore introduces a special
JSType to optimize this query. CheckDOM's patchpoint gives us a chance to emit special
faster code for such a case.

By leveraging above nodes, we can construct DOMJIT accelerated getter. When DFG recognizes the
given getter call is CustomGetter and it has DOMJIT::GetterSetter information, DFG emits the above nodes.
We implemented a prototype in jsc.cpp shell as DOMJITGetter to test the functionality.

Notes about the future extensions.

1. Currently, we do not allow CallDOM to emit any function calls. This will be extended by
   adding `addSlowPathCall` functionality to DOMJIT::Patchpoint later. Interesting thing is that
   we need to create an abstraction over DFG slow path call and FTL slow path call!

2. CheckDOM is not handled in DFGTypeCheckHoistingPhase yet. And we have a chance to merge several CheckDOM into one.
   For example, given CheckDOM A and CheckDOM B to the same target. If A is subclass of B, we can merge them to CheckDOM A.

* _javascript_Core.xcodeproj/project.pbxproj:
* b3/B3Effects.h:
(JSC::B3::Effects::forCheck):
* b3/B3Value.cpp:
(JSC::B3::Value::effects):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
(JSC::GetByIdStatus::makesCalls):
(JSC::GetByIdStatus::dump):
* bytecode/GetByIdStatus.h:
(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::isCustom):
(JSC::GetByIdStatus::takesSlowPath):
(JSC::GetByIdStatus::isSimple): Deleted.
* bytecode/SpeculatedType.cpp:
(JSC::speculationFromClassInfo):
* dfg/DFGAbstractInterpreter.h:
(JSC::DFG::AbstractInterpreter::filterClassInfo):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::filterClassInfo):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::filterClassInfo):
* dfg/DFGAbstractValue.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleDOMJITGetter):
(JSC::DFG::ByteCodeParser::handleGetById):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasDOMJIT):
(JSC::DFG::Node::domJIT):
(JSC::DFG::Node::hasClassInfo):
(JSC::DFG::Node::classInfo):
(JSC::DFG::Node::OpInfoWrapper::OpInfoWrapper):
(JSC::DFG::Node::OpInfoWrapper::operator=):
* dfg/DFGNodeType.h:
* dfg/DFGOpInfo.h:
(JSC::DFG::OpInfo::OpInfo):
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::allocateTemporaryRegistersForPatchpoint):
(JSC::DFG::SpeculativeJIT::compileCallDOM):
(JSC::DFG::SpeculativeJIT::compileCheckDOM):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureAbstractValue.cpp:
(JSC::DFG::StructureAbstractValue::filterClassInfoSlow):
(JSC::DFG::StructureAbstractValue::isSubClassOf):
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::filterClassInfo):
(JSC::DFG::StructureAbstractValue::filter): Deleted.
* domjit/DOMJITPatchpointParams.h: Copied from Source/_javascript_Core/dfg/DFGOpInfo.h.
(JSC::DOMJIT::PatchpointParams::~PatchpointParams):
(JSC::DOMJIT::PatchpointParams::size):
(JSC::DOMJIT::PatchpointParams::at):
(JSC::DOMJIT::PatchpointParams::operator[]):
(JSC::DOMJIT::PatchpointParams::gpScratch):
(JSC::DOMJIT::PatchpointParams::fpScratch):
(JSC::DOMJIT::PatchpointParams::PatchpointParams):
* domjit/DOMJITReg.h: Added.
(JSC::DOMJIT::Reg::Reg):
(JSC::DOMJIT::Reg::isGPR):
(JSC::DOMJIT::Reg::isFPR):
(JSC::DOMJIT::Reg::isJSValueRegs):
(JSC::DOMJIT::Reg::gpr):
(JSC::DOMJIT::Reg::fpr):
(JSC::DOMJIT::Reg::jsValueRegs):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
(JSC::FTL::DFG::LowerDFGToB3::compileUnreachable): Deleted.
* jit/AssemblyHelpers.h:
* jsc.cpp:
(WTF::DOMJITNode::DOMJITNode):
(WTF::DOMJITNode::createStructure):
(WTF::DOMJITNode::create):
(WTF::DOMJITNode::value):
(WTF::DOMJITNode::offsetOfValue):
(WTF::DOMJITGetter::DOMJITGetter):
(WTF::DOMJITGetter::createStructure):
(WTF::DOMJITGetter::create):
(WTF::DOMJITGetter::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
(WTF::DOMJITGetter::domJITNodeGetterSetter):
(WTF::DOMJITGetter::finishCreation):
(WTF::DOMJITGetter::customGetter):
(GlobalObject::finishCreation):
(functionCreateDOMJITNodeObject):
(functionCreateDOMJITGetterObject):

Source/WTF:

* wtf/Box.h:
(WTF::Box::Box):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (206845 => 206846)


--- trunk/JSTests/ChangeLog	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/JSTests/ChangeLog	2016-10-06 05:20:10 UTC (rev 206846)
@@ -1,3 +1,23 @@
+2016-10-05  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Add initial CheckDOM and CallDOM implementations
+        https://bugs.webkit.org/show_bug.cgi?id=162941
+
+        Reviewed by Filip Pizlo.
+
+        * stress/domjit-getter-poly.js: Added.
+        (shouldBe):
+        (access):
+        * stress/domjit-getter-proto.js: Added.
+        (shouldBe):
+        (access):
+        * stress/domjit-getter-super-poly.js: Added.
+        (shouldBe):
+        (access):
+        * stress/domjit-getter.js: Added.
+        (shouldBe):
+        (access):
+
 2016-10-04  Saam Barati  <[email protected]>
 
         String.prototype.toLowerCase should be a DFG/FTL intrinsic

Added: trunk/JSTests/stress/domjit-getter-poly.js (0 => 206846)


--- trunk/JSTests/stress/domjit-getter-poly.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter-poly.js	2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjit1 = createDOMJITGetterObject();
+var domjit2 = createDOMJITGetterObject();
+
+function access(domjit)
+{
+    return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e4; ++i)
+    shouldBe(access((i & 0x1) ? domjit1 : domjit2), 84);
+
+shouldBe(access({ customGetter: 42 }), 84);
+domjit1.test = 44;
+shouldBe(access(domjit1), 84);

Added: trunk/JSTests/stress/domjit-getter-proto.js (0 => 206846)


--- trunk/JSTests/stress/domjit-getter-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter-proto.js	2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjit = createDOMJITNodeObject();
+function access(domjit)
+{
+    return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e4; ++i)
+    shouldBe(access(domjit), 84);
+
+shouldBe(access({ customGetter: 42 }), 84);
+domjit.test = 44;
+shouldBe(access(domjit), 84);

Added: trunk/JSTests/stress/domjit-getter-super-poly.js (0 => 206846)


--- trunk/JSTests/stress/domjit-getter-super-poly.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter-super-poly.js	2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjits = [];
+for (var i = 0; i < 100; ++i)
+    domjits.push(createDOMJITGetterObject());
+
+function access(domjit)
+{
+    return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e2; ++i) {
+    for (var j = 0; j < domjits.length; ++j)
+        shouldBe(access(domjits[j]), 84);
+}

Added: trunk/JSTests/stress/domjit-getter.js (0 => 206846)


--- trunk/JSTests/stress/domjit-getter.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter.js	2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjit = createDOMJITGetterObject();
+
+function access(domjit)
+{
+    return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e4; ++i)
+    shouldBe(access(domjit), 84);
+
+shouldBe(access({ customGetter: 42 }), 84);
+domjit.test = 44;
+shouldBe(access(domjit), 84);

Modified: trunk/Source/_javascript_Core/ChangeLog (206845 => 206846)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-06 05:20:10 UTC (rev 206846)
@@ -1,5 +1,150 @@
 2016-10-05  Yusuke Suzuki  <[email protected]>
 
+        [DOMJIT] Add initial CheckDOM and CallDOM implementations
+        https://bugs.webkit.org/show_bug.cgi?id=162941
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements a prototype of DOMJIT accelerated getter.
+        We add two new DFG nodes, CheckDOM and CallDOM.
+
+        CheckDOM is used to filter inappropriate |this| object for DOM getter. Its functionality
+        is equivalent to jsDynamicCast's Check. You can use like "CheckDOM, @1, JSNode::info()",
+        and this CheckDOM incurs a BadType exit if the class of the given @1 is not a subclass of
+        JSNode::info().
+
+        CallDOM is used to emit actual DOM operations. It takes GlobalObject and checked DOM
+        object. And it returns JSValue as its result.
+
+        Both CheckDOM and CallDOM can take a DOMJIT::Patchpoint. This is somewhat code snippet
+        generator, and is injectable to DFG and FTL. DFG and FTL set up registers correctly
+        according to DOMJIT::Patchpoint's requirement and invoke this patchpoint generator to emit code.
+        While CallDOM always requires a patchpoint, ideally CheckDOM does not require it since
+        isSubclassOf check can be implemented in DFG / FTL side. However, some classes have a
+        faster way to query isSubclassOf. For example, JSNode in WebCore introduces a special
+        JSType to optimize this query. CheckDOM's patchpoint gives us a chance to emit special
+        faster code for such a case.
+
+        By leveraging above nodes, we can construct DOMJIT accelerated getter. When DFG recognizes the
+        given getter call is CustomGetter and it has DOMJIT::GetterSetter information, DFG emits the above nodes.
+        We implemented a prototype in jsc.cpp shell as DOMJITGetter to test the functionality.
+
+        Notes about the future extensions.
+
+        1. Currently, we do not allow CallDOM to emit any function calls. This will be extended by
+           adding `addSlowPathCall` functionality to DOMJIT::Patchpoint later. Interesting thing is that
+           we need to create an abstraction over DFG slow path call and FTL slow path call!
+
+        2. CheckDOM is not handled in DFGTypeCheckHoistingPhase yet. And we have a chance to merge several CheckDOM into one.
+           For example, given CheckDOM A and CheckDOM B to the same target. If A is subclass of B, we can merge them to CheckDOM A.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * b3/B3Effects.h:
+        (JSC::B3::Effects::forCheck):
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::effects):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
+        (JSC::GetByIdStatus::makesCalls):
+        (JSC::GetByIdStatus::dump):
+        * bytecode/GetByIdStatus.h:
+        (JSC::GetByIdStatus::GetByIdStatus):
+        (JSC::GetByIdStatus::isCustom):
+        (JSC::GetByIdStatus::takesSlowPath):
+        (JSC::GetByIdStatus::isSimple): Deleted.
+        * bytecode/SpeculatedType.cpp:
+        (JSC::speculationFromClassInfo):
+        * dfg/DFGAbstractInterpreter.h:
+        (JSC::DFG::AbstractInterpreter::filterClassInfo):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterClassInfo):
+        * dfg/DFGAbstractValue.cpp:
+        (JSC::DFG::AbstractValue::filterClassInfo):
+        * dfg/DFGAbstractValue.h:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleDOMJITGetter):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        (JSC::DFG::Node::hasDOMJIT):
+        (JSC::DFG::Node::domJIT):
+        (JSC::DFG::Node::hasClassInfo):
+        (JSC::DFG::Node::classInfo):
+        (JSC::DFG::Node::OpInfoWrapper::OpInfoWrapper):
+        (JSC::DFG::Node::OpInfoWrapper::operator=):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOpInfo.h:
+        (JSC::DFG::OpInfo::OpInfo):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::allocateTemporaryRegistersForPatchpoint):
+        (JSC::DFG::SpeculativeJIT::compileCallDOM):
+        (JSC::DFG::SpeculativeJIT::compileCheckDOM):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureAbstractValue.cpp:
+        (JSC::DFG::StructureAbstractValue::filterClassInfoSlow):
+        (JSC::DFG::StructureAbstractValue::isSubClassOf):
+        * dfg/DFGStructureAbstractValue.h:
+        (JSC::DFG::StructureAbstractValue::filterClassInfo):
+        (JSC::DFG::StructureAbstractValue::filter): Deleted.
+        * domjit/DOMJITPatchpointParams.h: Copied from Source/_javascript_Core/dfg/DFGOpInfo.h.
+        (JSC::DOMJIT::PatchpointParams::~PatchpointParams):
+        (JSC::DOMJIT::PatchpointParams::size):
+        (JSC::DOMJIT::PatchpointParams::at):
+        (JSC::DOMJIT::PatchpointParams::operator[]):
+        (JSC::DOMJIT::PatchpointParams::gpScratch):
+        (JSC::DOMJIT::PatchpointParams::fpScratch):
+        (JSC::DOMJIT::PatchpointParams::PatchpointParams):
+        * domjit/DOMJITReg.h: Added.
+        (JSC::DOMJIT::Reg::Reg):
+        (JSC::DOMJIT::Reg::isGPR):
+        (JSC::DOMJIT::Reg::isFPR):
+        (JSC::DOMJIT::Reg::isJSValueRegs):
+        (JSC::DOMJIT::Reg::gpr):
+        (JSC::DOMJIT::Reg::fpr):
+        (JSC::DOMJIT::Reg::jsValueRegs):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
+        (JSC::FTL::DFG::LowerDFGToB3::compileUnreachable): Deleted.
+        * jit/AssemblyHelpers.h:
+        * jsc.cpp:
+        (WTF::DOMJITNode::DOMJITNode):
+        (WTF::DOMJITNode::createStructure):
+        (WTF::DOMJITNode::create):
+        (WTF::DOMJITNode::value):
+        (WTF::DOMJITNode::offsetOfValue):
+        (WTF::DOMJITGetter::DOMJITGetter):
+        (WTF::DOMJITGetter::createStructure):
+        (WTF::DOMJITGetter::create):
+        (WTF::DOMJITGetter::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
+        (WTF::DOMJITGetter::domJITNodeGetterSetter):
+        (WTF::DOMJITGetter::finishCreation):
+        (WTF::DOMJITGetter::customGetter):
+        (GlobalObject::finishCreation):
+        (functionCreateDOMJITNodeObject):
+        (functionCreateDOMJITGetterObject):
+
+2016-10-05  Yusuke Suzuki  <[email protected]>
+
         [JSC] Do not construct Simple GetByIdStatus against self-custom-accessor case
         https://bugs.webkit.org/show_bug.cgi?id=162993
 

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (206845 => 206846)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-06 05:20:10 UTC (rev 206846)
@@ -2098,6 +2098,8 @@
 		E35E03601B7AB43E0073AD2A /* InspectorInstrumentationObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E3794E751B77EB97005543AE /* ModuleAnalyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */; };
 		E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = E3794E741B77EB97005543AE /* ModuleAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */ = {isa = PBXBuildFile; fileRef = E37AD83B1DA4928000F3D412 /* DOMJITReg.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E3963CEE1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */; };
 		E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E39DA4A61B7E8B7C0084F33A /* JSModuleRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */; };
@@ -4397,6 +4399,8 @@
 		E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = InspectorInstrumentationObject.js; sourceTree = "<group>"; };
 		E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleAnalyzer.cpp; sourceTree = "<group>"; };
 		E3794E741B77EB97005543AE /* ModuleAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleAnalyzer.h; sourceTree = "<group>"; };
+		E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpointParams.h; sourceTree = "<group>"; };
+		E37AD83B1DA4928000F3D412 /* DOMJITReg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITReg.h; sourceTree = "<group>"; };
 		E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodesAnalyzeModule.cpp; sourceTree = "<group>"; };
 		E39D9D841D39000600667282 /* InterpreterInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterpreterInlines.h; sourceTree = "<group>"; };
 		E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; };
@@ -7183,6 +7187,8 @@
 			children = (
 				E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */,
 				E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */,
+				E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */,
+				E37AD83B1DA4928000F3D412 /* DOMJITReg.h */,
 			);
 			path = domjit;
 			sourceTree = "<group>";
@@ -7600,6 +7606,7 @@
 				E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */,
 				0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
 				0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */,
+				E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */,
 				0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */,
 				0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */,
 				0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */,
@@ -8428,6 +8435,7 @@
 				9959E92E1BD17FA4001AA413 /* xxd.pl in Headers */,
 				79B1788E1D399B8000B1A567 /* JITMathICForwards.h in Headers */,
 				451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
+				E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */,
 				86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
 				86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
 				0FB4767F1D99AEAD008EA6CB /* GCDeferralContextInlines.h in Headers */,

Modified: trunk/Source/_javascript_Core/b3/B3Effects.h (206845 => 206846)


--- trunk/Source/_javascript_Core/b3/B3Effects.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/b3/B3Effects.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -78,6 +78,15 @@
         return result;
     }
 
+    static Effects forCheck()
+    {
+        Effects result;
+        result.exitsSideways = true;
+        // The program could read anything after exiting, and it's on us to declare this.
+        result.reads = HeapRange::top();
+        return result;
+    }
+
     bool mustExecute() const
     {
         return terminal || exitsSideways || writesLocalState || writes;

Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/b3/B3Value.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -614,9 +614,7 @@
     case CheckSub:
     case CheckMul:
     case Check:
-        result.exitsSideways = true;
-        // The program could read anything after exiting, and it's on us to declare this.
-        result.reads = HeapRange::top();
+        result = Effects::forCheck();
         break;
     case Upsilon:
     case Set:

Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -246,6 +246,7 @@
                     domJIT = access.domJIT();
                     if (!domJIT)
                         return GetByIdStatus(slowPathState, true);
+                    result.m_state = Custom;
                     break;
                 }
                 default: {
@@ -263,6 +264,16 @@
 
                 if (!result.appendVariant(variant))
                     return GetByIdStatus(slowPathState, true);
+
+                if (domJIT) {
+                    // Give up when cutom accesses are not merged into one.
+                    if (result.numVariants() != 1)
+                        return GetByIdStatus(slowPathState, true);
+                } else {
+                    // Give up when custom access and simple access are mixed.
+                    if (result.m_state == Custom)
+                        return GetByIdStatus(slowPathState, true);
+                }
                 break;
             } }
         }
@@ -362,6 +373,7 @@
     switch (m_state) {
     case NoInformation:
     case TakesSlowPath:
+    case Custom:
         return false;
     case Simple:
         for (unsigned i = m_variants.size(); i--;) {
@@ -403,6 +415,9 @@
     case Simple:
         out.print("Simple");
         break;
+    case Custom:
+        out.print("Custom");
+        break;
     case TakesSlowPath:
         out.print("TakesSlowPath");
         break;

Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.h (206845 => 206846)


--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -44,6 +44,7 @@
         NoInformation,  // It's uncached so we have no information.
         Simple,         // It's cached for a simple access to a known object property with
                         // a possible structure chain and a possible specific value.
+        Custom,         // It's cached for a custom accessor with a possible structure chain.
         TakesSlowPath,  // It's known to often take slow path.
         MakesCalls      // It's known to take paths that make calls.
     };
@@ -64,7 +65,7 @@
         : m_state(state)
         , m_wasSeenInJIT(wasSeenInJIT)
     {
-        ASSERT((state == Simple) == variant.isSet());
+        ASSERT((state == Simple || state == Custom) == variant.isSet());
         m_variants.append(variant);
     }
     
@@ -82,6 +83,7 @@
     bool isSet() const { return m_state != NoInformation; }
     bool operator!() const { return !isSet(); }
     bool isSimple() const { return m_state == Simple; }
+    bool isCustom() const { return m_state == Custom; }
 
     size_t numVariants() const { return m_variants.size(); }
     const Vector<GetByIdVariant, 1>& variants() const { return m_variants; }
@@ -88,7 +90,7 @@
     const GetByIdVariant& at(size_t index) const { return m_variants[index]; }
     const GetByIdVariant& operator[](size_t index) const { return at(index); }
 
-    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
+    bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls || m_state == Custom; }
     bool makesCalls() const;
     
     bool wasSeenInJIT() const { return m_wasSeenInJIT; }

Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -353,6 +353,12 @@
 
 SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
 {
+    if (classInfo == JSString::info())
+        return SpecString;
+
+    if (classInfo == Symbol::info())
+        return SpecSymbol;
+
     if (classInfo == JSFinalObject::info())
         return SpecFinalObject;
     
@@ -385,6 +391,9 @@
     
     if (isTypedView(classInfo->typedArrayStorageType))
         return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
+
+    if (classInfo->isSubClassOf(JSArray::info()))
+        return SpecDerivedArray;
     
     if (classInfo->isSubClassOf(JSObject::info()))
         return SpecObjectOther;

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -134,10 +134,17 @@
         return filterByValue(forNode(node), value);
     }
     
+    template<typename T>
+    FiltrationResult filterClassInfo(T node, const ClassInfo* classInfo)
+    {
+        return filterClassInfo(forNode(node), classInfo);
+    }
+
     FiltrationResult filter(AbstractValue&, const StructureSet&, SpeculatedType admittedTypes = SpecNone);
     FiltrationResult filterArrayModes(AbstractValue&, ArrayModes);
     FiltrationResult filter(AbstractValue&, SpeculatedType);
     FiltrationResult filterByValue(AbstractValue&, FrozenValue);
+    FiltrationResult filterClassInfo(AbstractValue&, const ClassInfo*);
     
     PhiChildren* phiChildren() { return m_phiChildren.get(); }
     

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -29,6 +29,7 @@
 
 #include "ArrayConstructor.h"
 #include "DFGAbstractInterpreter.h"
+#include "DOMJITGetterSetter.h"
 #include "GetByIdStatus.h"
 #include "GetterSetter.h"
 #include "HashMapImpl.h"
@@ -2268,6 +2269,28 @@
     case ReallocatePropertyStorage:
         forNode(node).clear(); // The result is not a JS value.
         break;
+    case CheckDOM: {
+        JSValue constant = forNode(node->child1()).value();
+        if (constant) {
+            if (constant.isCell() && constant.asCell()->inherits(node->classInfo())) {
+                m_state.setFoundConstants(true);
+                ASSERT(constant);
+                break;
+            }
+        }
+
+        AbstractValue& value = forNode(node->child1());
+
+        if (value.m_structure.isSubClassOf(node->classInfo()))
+            m_state.setFoundConstants(true);
+
+        filterClassInfo(value, node->classInfo());
+        break;
+    }
+    case CallDOM:
+        clobberWorld(node->origin.semantic, clobberLimit);
+        forNode(node).makeBytecodeTop();
+        break;
     case CheckArray: {
         if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
             m_state.setFoundConstants(true);
@@ -3056,6 +3079,16 @@
 }
 
 template<typename AbstractStateType>
+FiltrationResult AbstractInterpreter<AbstractStateType>::filterClassInfo(
+    AbstractValue& value, const ClassInfo* classInfo)
+{
+    if (value.filterClassInfo(m_graph, classInfo) == FiltrationOK)
+        return FiltrationOK;
+    m_state.setIsValid(false);
+    return Contradiction;
+}
+
+template<typename AbstractStateType>
 void AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects(Node* node, double(*equivalentFunction)(double))
 {
     JSValue child = forNode(node->child1()).value();

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -306,6 +306,23 @@
     return normalizeClarity();
 }
 
+FiltrationResult AbstractValue::filterClassInfo(Graph& graph, const ClassInfo* classInfo)
+{
+    // FIXME: AI should track ClassInfo to leverage hierarchical class information.
+    // https://bugs.webkit.org/show_bug.cgi?id=162989
+    if (isClear())
+        return FiltrationOK;
+
+    m_type &= speculationFromClassInfo(classInfo);
+    m_structure.filterClassInfo(classInfo);
+
+    m_structure.filter(m_type);
+
+    filterArrayModesByType();
+    filterValueByType();
+    return normalizeClarity(graph);
+}
+
 FiltrationResult AbstractValue::filter(SpeculatedType type)
 {
     if ((m_type & type) == m_type)

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -307,6 +307,7 @@
     FiltrationResult filter(SpeculatedType);
     FiltrationResult filterByValue(const FrozenValue& value);
     FiltrationResult filter(const AbstractValue&);
+    FiltrationResult filterClassInfo(Graph&, const ClassInfo*);
 
     FiltrationResult filter(Graph&, const InferredType::Descriptor&);
     

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -219,6 +219,7 @@
     bool handleConstantInternalFunction(Node* callTargetNode, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind, SpeculatedType, const ChecksFunctor& insertChecks);
     Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, const InferredType::Descriptor&, Node* value);
     Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, const InferredType::Descriptor&, NodeType = GetByOffset);
+    bool handleDOMJITGetter(int resultOperand, const GetByIdVariant&, Node* thisNode, SpeculatedType prediction);
 
     // Create a presence ObjectPropertyCondition based on some known offset and structure set. Does not
     // check the validity of the condition, but it may return a null one if it encounters a contradiction.
@@ -2673,6 +2674,28 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+bool ByteCodeParser::handleDOMJITGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, SpeculatedType prediction)
+{
+    if (!variant.domJIT())
+        return false;
+
+    DOMJIT::GetterSetter* domJIT = variant.domJIT();
+
+    // We do not need to actually look up CustomGetterSetter here. Checking Structures or registering watchpoints are enough,
+    // since replacement of CustomGetterSetter always incurs Structure transition.
+    if (!check(variant.conditionSet()))
+        return false;
+    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), thisNode);
+
+    // 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.
+    addVarArgChild(thisNode);
+    set(VirtualRegister(resultOperand), addToGraph(Node::VarArg, CallDOM, OpInfo(domJIT), OpInfo(prediction)));
+    return true;
+}
+
 template<typename ChecksFunctor>
 bool ByteCodeParser::handleTypedArrayConstructor(
     int resultOperand, InternalFunction* function, int registerOffset,
@@ -3267,6 +3290,20 @@
     else
         getById = TryGetById;
 
+    // Special path for custom accessors since custom's offset does not have any meanings.
+    // So, this is completely different from Simple one. But we have a chance to optimize it when we use DOMJIT.
+    if (getByIdStatus.isCustom()) {
+        ASSERT(getByIdStatus.numVariants() == 1);
+        ASSERT(!getByIdStatus.makesCalls());
+        GetByIdVariant variant = getByIdStatus[0];
+        ASSERT(variant.domJIT());
+        if (handleDOMJITGetter(destinationOperand, variant, base, prediction)) {
+            if (m_graph.compilation())
+                m_graph.compilation()->noticeInlinedGetById();
+            return;
+        }
+    }
+
     ASSERT(type == AccessType::Get || !getByIdStatus.makesCalls());
     if (!getByIdStatus.isSimple() || !getByIdStatus.numVariants() || !Options::useAccessInlining()) {
         set(VirtualRegister(destinationOperand),

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -885,6 +885,15 @@
         def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
         return;
 
+    case CheckDOM:
+        def(PureValue(node, node->classInfo()));
+        return;
+
+    case CallDOM:
+        read(World);
+        write(Heap);
+        return;
+
     case Arrayify:
     case ArrayifyToStructure:
         read(JSCell_structureID);

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -158,6 +158,28 @@
                 }
                 break;
             }
+
+            case CheckDOM: {
+                JSValue constant = m_state.forNode(node->child1()).value();
+                if (constant) {
+                    if (constant.isCell() && constant.asCell()->inherits(node->classInfo())) {
+                        m_interpreter.execute(indexInBlock);
+                        node->remove();
+                        eliminated = true;
+                        break;
+                    }
+                }
+
+                AbstractValue& value = m_state.forNode(node->child1());
+
+                if (value.m_structure.isSubClassOf(node->classInfo())) {
+                    m_interpreter.execute(indexInBlock);
+                    node->remove();
+                    eliminated = true;
+                    break;
+                }
+                break;
+            }
                 
             case GetIndexedPropertyStorage: {
                 JSArrayBufferView* view = m_graph.tryGetFoldableView(

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -118,6 +118,8 @@
     case CheckStructure:
     case GetExecutable:
     case GetButterfly:
+    case CallDOM:
+    case CheckDOM:
     case CheckArray:
     case GetScope:
     case SkipScope:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -1699,6 +1699,15 @@
             break;
         }
 
+        case CheckDOM:
+            fixEdge<CellUse>(node->child1());
+            break;
+
+        case CallDOM:
+            fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0)); // GlobalObject.
+            fixEdge<CellUse>(m_graph.varArgChild(node, 1)); // DOM.
+            break;
+
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -1446,6 +1446,7 @@
         case StringReplaceRegExp:
         case ToNumber:
         case LoadFromJSMapBucket:
+        case CallDOM:
             return true;
         default:
             return false;
@@ -2312,7 +2313,28 @@
         ASSERT(hasBasicBlockLocation());
         return m_opInfo.as<BasicBlockLocation*>();
     }
-    
+
+    bool hasDOMJIT() const
+    {
+        return op() == CheckDOM || op() == CallDOM;
+    }
+
+    DOMJIT::GetterSetter* domJIT()
+    {
+        ASSERT(hasDOMJIT());
+        return m_opInfo.as<DOMJIT::GetterSetter*>();
+    }
+
+    bool hasClassInfo() const
+    {
+        return op() == CheckDOM;
+    }
+
+    const ClassInfo* classInfo()
+    {
+        return m_opInfo2.as<const ClassInfo*>();
+    }
+
     Node* replacement() const
     {
         return m_misc.replacement;
@@ -2392,6 +2414,11 @@
             u.int64 = 0;
             u.pointer = pointer;
         }
+        OpInfoWrapper(const void* constPointer)
+        {
+            u.int64 = 0;
+            u.constPointer = constPointer;
+        }
         OpInfoWrapper& operator=(uint32_t int32)
         {
             u.int64 = 0;
@@ -2415,12 +2442,23 @@
             u.pointer = pointer;
             return *this;
         }
+        OpInfoWrapper& operator=(const void* constPointer)
+        {
+            u.int64 = 0;
+            u.constPointer = constPointer;
+            return *this;
+        }
         template <typename T>
-        ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value, T>::type
+        ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && !std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
         {
             return static_cast<T>(u.pointer);
         }
         template <typename T>
+        ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
+        {
+            return static_cast<T>(u.constPointer);
+        }
+        template <typename T>
         ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 4, T>::type
         {
             return u.int32;
@@ -2434,6 +2472,7 @@
             uint32_t int32;
             uint64_t int64;
             void* pointer;
+            const void* constPointer;
         } u;
     };
     OpInfoWrapper m_opInfo;

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -398,6 +398,9 @@
     macro(IsNonEmptyMapBucket, NodeResultBoolean) \
     \
     macro(ToLowerCase, NodeResultJS) \
+    /* Nodes for DOM JIT */\
+    macro(CheckDOM, NodeMustGenerate) \
+    macro(CallDOM, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
 
 // This enum generates a monotonically increasing id for all Node types,
 // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).

Modified: trunk/Source/_javascript_Core/dfg/DFGOpInfo.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGOpInfo.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGOpInfo.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -43,6 +43,7 @@
     explicit OpInfo(uintptr_t value) : m_value(static_cast<uint64_t>(value)) { }
 #endif
     explicit OpInfo(void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
+    explicit OpInfo(const void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
     uint64_t m_value;
 };
 

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -699,7 +699,8 @@
         case GetClosureVar:
         case GetFromArguments:
         case LoadFromJSMapBucket:
-        case ToNumber: {
+        case ToNumber:
+        case CallDOM: {
             setPrediction(m_currentNode->getHeapPrediction());
             break;
         }
@@ -824,6 +825,9 @@
             break;
         }
 
+        case CheckDOM:
+            break;
+
         case CallObjectConstructor: {
             setPrediction(SpecObject);
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -218,6 +218,8 @@
     case CheckStructure:
     case GetExecutable:
     case GetButterfly:
+    case CallDOM:
+    case CheckDOM:
     case CheckArray:
     case Arrayify:
     case ArrayifyToStructure:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -38,6 +38,8 @@
 #include "DFGOSRExitFuzz.h"
 #include "DFGSaneStringGetByValSlowPathGenerator.h"
 #include "DFGSlowPathGenerator.h"
+#include "DOMJITPatchpoint.h"
+#include "DOMJITPatchpointParams.h"
 #include "DirectArguments.h"
 #include "JITAddGenerator.h"
 #include "JITBitAndGenerator.h"
@@ -7111,6 +7113,74 @@
     storageResult(resultGPR, node);
 }
 
+static void allocateTemporaryRegistersForPatchpoint(SpeculativeJIT* jit, Vector<GPRTemporary>& gpHolders, Vector<FPRTemporary>& fpHolders, Vector<GPRReg>& gpScratch, Vector<FPRReg>& fpScratch, DOMJIT::Patchpoint& patchpoint)
+{
+    for (unsigned i = 0; i < patchpoint.numGPScratchRegisters; ++i) {
+        GPRTemporary temporary(jit);
+        gpScratch.append(temporary.gpr());
+        gpHolders.append(WTFMove(temporary));
+    }
+
+    for (unsigned i = 0; i < patchpoint.numFPScratchRegisters; ++i) {
+        FPRTemporary temporary(jit);
+        fpScratch.append(temporary.fpr());
+        fpHolders.append(WTFMove(temporary));
+    }
+}
+
+void SpeculativeJIT::compileCallDOM(Node* node)
+{
+    Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->callDOM();
+
+    Vector<GPRReg> gpScratch;
+    Vector<FPRReg> fpScratch;
+    Vector<DOMJIT::Reg> 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(globalObject.gpr());
+    regs.append(base.gpr());
+#if USE(JSVALUE64)
+    regs.append(static_cast<GPRReg>(GPRInfo::tagMaskRegister));
+    regs.append(static_cast<GPRReg>(GPRInfo::tagTypeNumberRegister));
+#endif
+
+    Vector<GPRTemporary> gpTempraries;
+    Vector<FPRTemporary> fpTempraries;
+    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
+    DOMJIT::PatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+    patchpoint->generator()->run(m_jit, params);
+    jsValueResult(result.regs(), node);
+}
+
+void SpeculativeJIT::compileCheckDOM(Node* node)
+{
+    // FIXME: We can add the fallback implementation that inlines jsDynamicCast things here.
+    Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->checkDOM();
+
+    Vector<GPRReg> gpScratch;
+    Vector<FPRReg> fpScratch;
+    Vector<DOMJIT::Reg> regs;
+
+    SpeculateCellOperand base(this, node->child1());
+    GPRReg baseGPR = base.gpr();
+    regs.append(baseGPR);
+
+    Vector<GPRTemporary> gpTempraries;
+    Vector<FPRTemporary> fpTempraries;
+    allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
+
+    DOMJIT::PatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+    CCallHelpers::JumpList failureCases = patchpoint->generator()->run(m_jit, params);
+    speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), failureCases);
+    noResult(node);
+}
+
 GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode)
 {
     if (!putByValWillNeedExtraRegister(arrayMode))

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -2543,6 +2543,8 @@
     void compileAllocatePropertyStorage(Node*);
     void compileReallocatePropertyStorage(Node*);
     void compileGetButterfly(Node*);
+    void compileCallDOM(Node*);
+    void compileCheckDOM(Node*);
     
 #if USE(JSVALUE32_64)
     template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -5435,6 +5435,14 @@
         break;
     }
 
+    case CallDOM:
+        compileCallDOM(node);
+        break;
+
+    case CheckDOM:
+        compileCheckDOM(node);
+        break;
+
     case Unreachable:
         unreachable(node);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -5566,6 +5566,14 @@
         compileMaterializeNewObject(node);
         break;
 
+    case CallDOM:
+        compileCallDOM(node);
+        break;
+
+    case CheckDOM:
+        compileCheckDOM(node);
+        break;
+
 #if ENABLE(FTL_JIT)        
     case CheckTierUpInLoop: {
         MacroAssembler::Jump callTierUp = m_jit.branchAdd32(

Modified: trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -258,6 +258,15 @@
         });
 }
 
+void StructureAbstractValue::filterClassInfoSlow(const ClassInfo* classInfo)
+{
+    ASSERT(!isTop());
+    m_set.genericFilter(
+        [&] (Structure* structure) {
+            return structure->classInfo()->isSubClassOf(classInfo);
+        });
+}
+
 bool StructureAbstractValue::contains(Structure* structure) const
 {
     if (isInfinite())
@@ -319,6 +328,19 @@
     return overlaps(other.m_set);
 }
 
+bool StructureAbstractValue::isSubClassOf(const ClassInfo* classInfo) const
+{
+    if (isInfinite())
+        return false;
+
+    // Note taht this function returns true if the structure set is empty.
+    for (const Structure* structure : m_set) {
+        if (!structure->classInfo()->isSubClassOf(classInfo))
+            return false;
+    }
+    return true;
+}
+
 bool StructureAbstractValue::equalsSlow(const StructureAbstractValue& other) const
 {
     ASSERT(m_set.m_pointer != other.m_set.m_pointer);

Modified: trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.h (206845 => 206846)


--- trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -163,6 +163,12 @@
         if (isNeitherClearNorTop())
             filterSlow(type);
     }
+
+    ALWAYS_INLINE void filterClassInfo(const ClassInfo* classInfo)
+    {
+        if (isNeitherClearNorTop())
+            filterClassInfoSlow(classInfo);
+    }
     
     ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const
     {
@@ -231,6 +237,8 @@
     
     bool overlaps(const StructureSet& other) const;
     bool overlaps(const StructureAbstractValue& other) const;
+
+    bool isSubClassOf(const ClassInfo*) const;
     
     void validateReferences(const TrackedReferences&) const;
     
@@ -241,6 +249,7 @@
     static const unsigned clobberedSupremacyThreshold = 2;
     
     void filterSlow(SpeculatedType type);
+    void filterClassInfoSlow(const ClassInfo*);
     bool mergeSlow(const StructureAbstractValue& other);
     
     bool equalsSlow(const StructureAbstractValue& other) const;

Copied: trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h (from rev 206844, trunk/Source/_javascript_Core/dfg/DFGOpInfo.h) (0 => 206846)


--- trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,64 @@
+/*
+ * 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 "CCallHelpers.h"
+#include "DOMJITReg.h"
+#include "RegisterSet.h"
+
+namespace JSC { namespace DOMJIT {
+
+class PatchpointParams {
+WTF_MAKE_NONCOPYABLE(PatchpointParams);
+public:
+    virtual ~PatchpointParams() { }
+
+    unsigned size() const { return m_regs.size(); }
+    const Reg& at(unsigned index) const { return m_regs[index]; }
+    const Reg& operator[](unsigned index) const { return at(index); }
+
+    GPRReg gpScratch(unsigned index) const { return m_gpScratch[index]; }
+    FPRReg fpScratch(unsigned index) const { return m_fpScratch[index]; }
+
+    PatchpointParams(Vector<Reg>&& regs, Vector<GPRReg>&& gpScratch, Vector<FPRReg>&& fpScratch)
+        : m_regs(WTFMove(regs))
+        , m_gpScratch(WTFMove(gpScratch))
+        , m_fpScratch(WTFMove(fpScratch))
+    {
+    }
+
+private:
+
+    Vector<Reg> m_regs;
+    Vector<GPRReg> m_gpScratch;
+    Vector<FPRReg> m_fpScratch;
+};
+
+} }
+
+#endif

Added: trunk/Source/_javascript_Core/domjit/DOMJITReg.h (0 => 206846)


--- trunk/Source/_javascript_Core/domjit/DOMJITReg.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/domjit/DOMJITReg.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,93 @@
+/*
+ * 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 "Reg.h"
+#include <wtf/Variant.h>
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+// It is quite unfortunate that 32 bit environment exists on DFG! This means that JSValueRegs contains 2 registers
+// in such an environment. If we use GPRReg and FPRReg in DOMJITPatchpointParams, DOMJITPatchpointParams may contain
+// different number of registers in 32bit and 64bit environments when we pass JSValueRegs, it is confusing.
+// Therefore, we introduce an abstraction that DOMJIT::Reg, which is a polymorphic register class. It can refer FPRReg,
+// GPRReg, and "JSValueRegs". Note that isGPR() will return false if the target Reg is "JSValueRegs" even if the
+// environment is 64bit.
+//
+// FIXME: Eventually we should move this class into JSC and make is available for other JIT code.
+// https://bugs.webkit.org/show_bug.cgi?id=162990
+class Reg {
+public:
+    enum class Type : uint8_t {
+        GPR = 0,
+        FPR = 1,
+        JSValue = 2,
+    };
+
+    Reg(GPRReg reg)
+        : m_variant(reg)
+    {
+    }
+
+    Reg(FPRReg reg)
+        : m_variant(reg)
+    {
+    }
+
+    Reg(JSValueRegs regs)
+        : m_variant(regs)
+    {
+    }
+
+    bool isGPR() const { return m_variant.index() == static_cast<unsigned>(Type::GPR); }
+    bool isFPR() const { return m_variant.index() == static_cast<unsigned>(Type::FPR); }
+    bool isJSValueRegs() const { return m_variant.index() == static_cast<unsigned>(Type::JSValue); }
+
+    GPRReg gpr() const
+    {
+        ASSERT(isGPR());
+        return std::experimental::get<GPRReg>(m_variant);
+    }
+    FPRReg fpr() const
+    {
+        ASSERT(isFPR());
+        return std::experimental::get<FPRReg>(m_variant);
+    }
+    JSValueRegs jsValueRegs() const
+    {
+        ASSERT(isJSValueRegs());
+        return std::experimental::get<JSValueRegs>(m_variant);
+    }
+
+private:
+    std::experimental::variant<GPRReg, FPRReg, JSValueRegs> m_variant;
+};
+
+} }
+
+#endif

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -266,6 +266,8 @@
     case DefineDataProperty:
     case DefineAccessorProperty:
     case ToLowerCase:
+    case CheckDOM:
+    case CallDOM:
         // These are OK.
         break;
 

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -44,6 +44,8 @@
 #include "DFGInPlaceAbstractState.h"
 #include "DFGOSRAvailabilityAnalysisPhase.h"
 #include "DFGOSRExitFuzz.h"
+#include "DOMJITPatchpoint.h"
+#include "DOMJITPatchpointParams.h"
 #include "DirectArguments.h"
 #include "FTLAbstractHeapRepository.h"
 #include "FTLAvailableRecovery.h"
@@ -1046,6 +1048,12 @@
         case ToLowerCase:
             compileToLowerCase();
             break;
+        case CheckDOM:
+            compileCheckDOM();
+            break;
+        case CallDOM:
+            compileCallDOM();
+            break;
 
         case PhantomLocal:
         case LoopHint:
@@ -8712,6 +8720,94 @@
         
         crash();
     }
+
+    void compileCheckDOM()
+    {
+        LValue cell = lowCell(m_node->child1());
+
+        RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->checkDOM();
+
+        PatchpointValue* patchpoint = m_out.patchpoint(Void);
+        patchpoint->appendSomeRegister(cell);
+        patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
+        patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
+
+        State* state = &m_ftlState;
+        NodeOrigin origin = m_origin;
+        unsigned osrExitArgumentOffset = patchpoint->numChildren();
+        OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(jsValueValue(cell), m_node->child1().node());
+        patchpoint->appendColdAnys(buildExitArguments(exitDescriptor, origin.forExit, jsValueValue(cell)));
+
+        patchpoint->setGenerator(
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                Vector<GPRReg> gpScratch;
+                Vector<FPRReg> fpScratch;
+                Vector<DOMJIT::Reg> regs;
+
+                regs.append(params[0].gpr());
+
+                for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
+                    gpScratch.append(params.gpScratch(i));
+
+                for (unsigned i = 0; i < domJIT->numFPScratchRegisters; ++i)
+                    fpScratch.append(params.fpScratch(i));
+
+                RefPtr<OSRExitHandle> handle = exitDescriptor->emitOSRExitLater(*state, BadType, origin, params, osrExitArgumentOffset);
+
+                DOMJIT::PatchpointParams domJITParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+                CCallHelpers::JumpList failureCases = domJIT->generator()->run(jit, domJITParams);
+
+                jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+                    linkBuffer.link(failureCases, linkBuffer.locationOf(handle->label));
+                });
+            });
+        patchpoint->effects = Effects::forCheck();
+    }
+
+    void compileCallDOM()
+    {
+        LValue globalObject = lowCell(m_graph.varArgChild(m_node, 0));
+        LValue cell = lowCell(m_graph.varArgChild(m_node, 1));
+
+        RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->callDOM();
+        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));
+        RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
+        patchpoint->clobber(RegisterSet::macroScratchRegisters());
+        patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
+        patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
+
+        patchpoint->setGenerator(
+            [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                Vector<GPRReg> gpScratch;
+                Vector<FPRReg> fpScratch;
+                Vector<DOMJIT::Reg> regs;
+
+                // FIXME: patchpoint should have a way to tell this can reuse "base" register.
+                // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
+                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));
+
+                for (unsigned i = 0; i < domJIT->numFPScratchRegisters; ++i)
+                    fpScratch.append(params.fpScratch(i));
+
+                Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit);
+
+                DOMJIT::PatchpointParams domJITParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+                domJIT->generator()->run(jit, domJITParams);
+            });
+        patchpoint->effects = Effects::forCall();
+        setJSValue(patchpoint);
+    }
     
     void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
     {

Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (206845 => 206846)


--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -1209,9 +1209,9 @@
     
     enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
     enum ExceptionJumpWidth { NormalJumpWidth, FarJumpWidth };
-    Jump emitExceptionCheck(
+    JS_EXPORT_PRIVATE Jump emitExceptionCheck(
         ExceptionCheckKind = NormalExceptionCheck, ExceptionJumpWidth = NormalJumpWidth);
-    Jump emitNonPatchableExceptionCheck();
+    JS_EXPORT_PRIVATE Jump emitNonPatchableExceptionCheck();
 
 #if ENABLE(SAMPLING_COUNTERS)
     static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)

Modified: trunk/Source/_javascript_Core/jsc.cpp (206845 => 206846)


--- trunk/Source/_javascript_Core/jsc.cpp	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/jsc.cpp	2016-10-06 05:20:10 UTC (rev 206846)
@@ -28,6 +28,9 @@
 #include "ButterflyInlines.h"
 #include "CodeBlock.h"
 #include "Completion.h"
+#include "DOMJITGetterSetter.h"
+#include "DOMJITPatchpoint.h"
+#include "DOMJITPatchpointParams.h"
 #include "Disassembler.h"
 #include "Exception.h"
 #include "ExceptionHelpers.h"
@@ -72,6 +75,7 @@
 #include <type_traits>
 #include <wtf/CurrentTime.h>
 #include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/StringPrintStream.h>
 #include <wtf/text/StringBuilder.h>
 
@@ -537,12 +541,133 @@
     WriteBarrier<JSC::Unknown> m_hiddenValue;
 };
 
+class DOMJITNode : public JSNonFinalObject {
+public:
+    DOMJITNode(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
 
+    DECLARE_INFO;
+    typedef JSNonFinalObject Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
+    }
+
+    static DOMJITNode* create(VM& vm, Structure* structure)
+    {
+        DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
+        getter->finishCreation(vm);
+        return getter;
+    }
+
+    int32_t value() const
+    {
+        return m_value;
+    }
+
+    static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); }
+
+private:
+    int32_t m_value { 42 };
+};
+
+class DOMJITGetter : public DOMJITNode {
+public:
+    DOMJITGetter(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+
+    DECLARE_INFO;
+    typedef DOMJITNode Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
+    }
+
+    static DOMJITGetter* create(VM& vm, Structure* structure)
+    {
+        DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap, sizeof(DOMJITGetter))) DOMJITGetter(vm, structure);
+        getter->finishCreation(vm);
+        return getter;
+    }
+
+    class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
+    public:
+        DOMJITNodeDOMJIT()
+            : DOMJIT::GetterSetter(DOMJITGetter::customGetter, nullptr, DOMJITNode::info())
+        {
+        }
+
+        Ref<DOMJIT::Patchpoint> checkDOM() override
+        {
+            Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+            patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+                CCallHelpers::JumpList failureCases;
+                failureCases.append(jit.branch8(
+                    CCallHelpers::NotEqual,
+                    CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
+                    CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
+                return failureCases;
+            });
+            return patchpoint;
+        }
+
+        Ref<DOMJIT::Patchpoint> callDOM() override
+        {
+            Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+            patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+                JSValueRegs results = params[0].jsValueRegs();
+                GPRReg dom = params[2].gpr();
+
+                jit.load32(CCallHelpers::Address(dom, DOMJITNode::offsetOfValue()), results.payloadGPR());
+                jit.boxInt32(results.payloadGPR(), results);
+                return CCallHelpers::JumpList();
+            });
+            return patchpoint;
+        }
+    };
+
+    static DOMJIT::GetterSetter* domJITNodeGetterSetter()
+    {
+        static NeverDestroyed<DOMJITNodeDOMJIT> graph;
+        return &graph.get();
+    }
+
+private:
+    void finishCreation(VM& vm)
+    {
+        Base::finishCreation(vm);
+        DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
+        CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
+        putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
+    }
+
+    static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
+    {
+        VM& vm = exec->vm();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+
+        DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
+        if (!thisObject)
+            return throwVMTypeError(exec, scope);
+        return JSValue::encode(jsNumber(thisObject->value()));
+    }
+};
+
 const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
 const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
 const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
 const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
 const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
+const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITNode) };
+const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetter) };
 const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
 const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
 static bool test262AsyncPassed { false };
@@ -571,6 +696,8 @@
 static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
@@ -855,6 +982,8 @@
 
         addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
         addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
+        addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
+        addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
         addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
         addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
         addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
@@ -1359,6 +1488,22 @@
     return JSValue::encode(result);
 }
 
+EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
+{
+    JSLockHolder lock(exec);
+    Structure* structure = DOMJITNode::createStructure(exec->vm(), exec->lexicalGlobalObject(), DOMJITGetter::create(exec->vm(), DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull())));
+    DOMJITNode* result = DOMJITNode::create(exec->vm(), structure);
+    return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
+{
+    JSLockHolder lock(exec);
+    Structure* structure = DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
+    DOMJITGetter* result = DOMJITGetter::create(exec->vm(), structure);
+    return JSValue::encode(result);
+}
+
 EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
 {
     JSLockHolder lock(exec);

Modified: trunk/Source/WTF/ChangeLog (206845 => 206846)


--- trunk/Source/WTF/ChangeLog	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/WTF/ChangeLog	2016-10-06 05:20:10 UTC (rev 206846)
@@ -1,3 +1,13 @@
+2016-10-05  Yusuke Suzuki  <[email protected]>
+
+        [DOMJIT] Add initial CheckDOM and CallDOM implementations
+        https://bugs.webkit.org/show_bug.cgi?id=162941
+
+        Reviewed by Filip Pizlo.
+
+        * wtf/Box.h:
+        (WTF::Box::Box):
+
 2016-10-05  Zan Dobersek  <[email protected]>
 
         Rename ENABLE_ENCRYPTED_MEDIA_V2 to ENABLE_LEGACY_ENCRYPTED_MEDIA

Modified: trunk/Source/WTF/wtf/Box.h (206845 => 206846)


--- trunk/Source/WTF/wtf/Box.h	2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/WTF/wtf/Box.h	2016-10-06 05:20:10 UTC (rev 206846)
@@ -40,6 +40,10 @@
     {
     }
 
+    Box(std::nullptr_t)
+    {
+    }
+
     template<typename... Arguments>
     static Box create(Arguments&&... arguments)
     {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to