[DOMJIT] Add DOMJIT::Signature
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Nov 2016 03:20:53 +0000 (03:20 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Nov 2016 03:20:53 +0000 (03:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=162980

Reviewed by Saam Barati and Sam Weinig.

Source/JavaScriptCore:

This patch introduces a new mechanism called DOMJIT::Signature. We can annotate the function with DOMJIT::Signature.
DOMJIT::Signature has type information of that function. And it also maintains the effect of the function and the
pointer to the unsafe function. The unsafe function means the function without type and argument count checks.
By using these information, we can separate type and argument count checks from the function. And we can emit
these things as DFG checks and convert the function call itself to CallDOM node. CallDOM node can call the unsafe
function directly without any checks. Furthermore, this CallDOM node can represent its own clobberizing rules based
on DOMJIT::Effect maintained by DOMJIT::Signature. It allows us to make opaque Call node to a CallDOM node that
merely reads some part of heap. These changes (1) can drop duplicate type checks in DFG, (2) offer ability to move
CallDOM node to somewhere, and (3) track more detailed heap reads and writes of CallDOM nodes.

We first emit Call node with DOMJIT::Signature in DFGByteCodeParser. And in the fixup phase, we attempt to lower
Call node to CallDOM node with checks & edge filters. This is because we do not know the type predictions in
DFGByteCodeParser phase. If we always emit CallDOM node in DFGByteCodeParser, if we evaluate `div.getAttribute(true)`
thingy, the Uncountable OSR exits repeatedly happen because AI figures out the abstract value is cleared.

Currently, DOMJIT signature only allows the types that can reside in GPR. This is because the types of the unsafe
function arguments are represented as the sequence of void*. In the future, we will extend to accept other types like
float, double etc.

We annotate several functions in Element. In particular, we annotate Element::getAttribute. This allows us to perform
LICM in Dromaeo dom-attr test. In the Dromaeo dom-attr getAttribute test, we can see 32x improvement. (134974.8 v.s. 4203.4)

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CallVariant.h:
(JSC::CallVariant::functionExecutable):
(JSC::CallVariant::nativeExecutable):
(JSC::CallVariant::signatureFor):
* bytecode/SpeculatedType.h:
(JSC::isNotStringSpeculation):
(JSC::isNotInt32Speculation):
(JSC::isNotBooleanSpeculation):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::handleDOMJITCall):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::attemptToMakeCallDOM):
(JSC::DFG::FixupPhase::fixupCheckDOM):
(JSC::DFG::FixupPhase::fixupCallDOM):
* dfg/DFGNode.cpp:
(JSC::DFG::Node::convertToCallDOM):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::shouldSpeculateNotInt32):
(JSC::DFG::Node::shouldSpeculateNotBoolean):
(JSC::DFG::Node::shouldSpeculateNotString):
(JSC::DFG::Node::hasSignature):
(JSC::DFG::Node::signature):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCallDOM):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* domjit/DOMJITEffect.h:
(JSC::DOMJIT::Effect::Effect):
(JSC::DOMJIT::Effect::forWrite):
(JSC::DOMJIT::Effect::forRead):
(JSC::DOMJIT::Effect::forReadWrite):
(JSC::DOMJIT::Effect::forPure):
(JSC::DOMJIT::Effect::forDef):
(JSC::DOMJIT::Effect::mustGenerate):
In clang, we cannot make this Effect constructor constexpr if we use Optional<HeapRange>.
So we use HeapRange::top() for Nullopt def now.

* domjit/DOMJITHeapRange.h:
(JSC::DOMJIT::HeapRange::fromRaw):
(JSC::DOMJIT::HeapRange::operator bool):
(JSC::DOMJIT::HeapRange::operator==):
(JSC::DOMJIT::HeapRange::operator!=):
(JSC::DOMJIT::HeapRange::fromConstant):
* domjit/DOMJITSignature.h: Copied from Source/JavaScriptCore/domjit/DOMJITEffect.h.
(JSC::DOMJIT::Signature::Signature):
(JSC::DOMJIT::Signature::argumentCount):
(JSC::DOMJIT::Signature::checkDOM):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
* jit/JITOperations.h:
* jit/JITThunks.cpp:
(JSC::JITThunks::hostFunctionStub):
* jit/JITThunks.h:
* runtime/JSBoundFunction.cpp:
(JSC::JSBoundFunction::create):
* runtime/JSCell.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::create):
* runtime/JSFunction.h:
* runtime/JSNativeStdFunction.cpp:
(JSC::JSNativeStdFunction::create):
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectNativeFunction):
* runtime/JSObject.h:
* runtime/Lookup.h:
(JSC::HashTableValue::functionLength):
(JSC::HashTableValue::signature):
(JSC::reifyStaticProperty):
* runtime/NativeExecutable.cpp:
(JSC::NativeExecutable::create):
(JSC::NativeExecutable::NativeExecutable):
* runtime/NativeExecutable.h:
* runtime/PropertySlot.h:
* runtime/VM.cpp:
(JSC::VM::getHostFunction):
* runtime/VM.h:

Source/WebCore:

We introduce DOMJIT::Signature. This signature object is automatically generated by IDL code generator.
It holds (1) types, (2) pointer to the unsafe function (the function without checks), and (3) the effect
of the function. We use constexpr to initialize DOMJIT::Signature without invoking global constructors.
Thus the content is embedded into the binary as the constant values.

We also clean up the IDL code generator related to DOMJIT part. Instead of switching things inside IDL
code generator, we use C++ template to dispatch things at compile time. This template meta programming
is highly utilized in IDL these days.

To make DOMJIT::Signature constexpr, we also need to define DOMJIT abstract heap things in the build time.
To do so, we introduce a tiny Ruby script to calculate the range of abstract heaps. We can offer the abstract
heap tree as YAML format and the script will produce a C++ header holding the calculated abstract heap ranges

* CMakeLists.txt:
* DerivedSources.make:
* ForwardingHeaders/bytecode/SpeculatedType.h: Renamed from Source/WebCore/domjit/DOMJITAbstractHeapRepository.h.
* ForwardingHeaders/domjit/DOMJITSignature.h: Renamed from Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp.
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMGlobalObject.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GeneratePropertiesHashTable):
(GetUnsafeArgumentType):
(GetArgumentTypeFilter):
(GetResultTypeFilter):
(GenerateImplementation):
(UnsafeToNative):
(GenerateHashTableValueArray):
(ComputeFunctionSpecial):
* bindings/scripts/IDLAttributes.txt:
* bindings/scripts/test/JS/JSTestDOMJIT.cpp:
(WebCore::BindingCaller<JSTestDOMJIT>::castForOperation):
(WebCore::TestDOMJITAnyAttrDOMJIT::TestDOMJITAnyAttrDOMJIT):
(WebCore::TestDOMJITBooleanAttrDOMJIT::TestDOMJITBooleanAttrDOMJIT):
(WebCore::TestDOMJITByteAttrDOMJIT::TestDOMJITByteAttrDOMJIT):
(WebCore::TestDOMJITOctetAttrDOMJIT::TestDOMJITOctetAttrDOMJIT):
(WebCore::TestDOMJITShortAttrDOMJIT::TestDOMJITShortAttrDOMJIT):
(WebCore::TestDOMJITUnsignedShortAttrDOMJIT::TestDOMJITUnsignedShortAttrDOMJIT):
(WebCore::TestDOMJITLongAttrDOMJIT::TestDOMJITLongAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongAttrDOMJIT::TestDOMJITUnsignedLongAttrDOMJIT):
(WebCore::TestDOMJITLongLongAttrDOMJIT::TestDOMJITLongLongAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongLongAttrDOMJIT::TestDOMJITUnsignedLongLongAttrDOMJIT):
(WebCore::TestDOMJITFloatAttrDOMJIT::TestDOMJITFloatAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedFloatAttrDOMJIT::TestDOMJITUnrestrictedFloatAttrDOMJIT):
(WebCore::TestDOMJITDoubleAttrDOMJIT::TestDOMJITDoubleAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedDoubleAttrDOMJIT::TestDOMJITUnrestrictedDoubleAttrDOMJIT):
(WebCore::TestDOMJITDomStringAttrDOMJIT::TestDOMJITDomStringAttrDOMJIT):
(WebCore::TestDOMJITByteStringAttrDOMJIT::TestDOMJITByteStringAttrDOMJIT):
(WebCore::TestDOMJITUsvStringAttrDOMJIT::TestDOMJITUsvStringAttrDOMJIT):
(WebCore::TestDOMJITNodeAttrDOMJIT::TestDOMJITNodeAttrDOMJIT):
(WebCore::TestDOMJITBooleanNullableAttrDOMJIT::TestDOMJITBooleanNullableAttrDOMJIT):
(WebCore::TestDOMJITByteNullableAttrDOMJIT::TestDOMJITByteNullableAttrDOMJIT):
(WebCore::TestDOMJITOctetNullableAttrDOMJIT::TestDOMJITOctetNullableAttrDOMJIT):
(WebCore::TestDOMJITShortNullableAttrDOMJIT::TestDOMJITShortNullableAttrDOMJIT):
(WebCore::TestDOMJITUnsignedShortNullableAttrDOMJIT::TestDOMJITUnsignedShortNullableAttrDOMJIT):
(WebCore::TestDOMJITLongNullableAttrDOMJIT::TestDOMJITLongNullableAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongNullableAttrDOMJIT::TestDOMJITUnsignedLongNullableAttrDOMJIT):
(WebCore::TestDOMJITLongLongNullableAttrDOMJIT::TestDOMJITLongLongNullableAttrDOMJIT):
(WebCore::TestDOMJITUnsignedLongLongNullableAttrDOMJIT::TestDOMJITUnsignedLongLongNullableAttrDOMJIT):
(WebCore::TestDOMJITFloatNullableAttrDOMJIT::TestDOMJITFloatNullableAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT):
(WebCore::TestDOMJITDoubleNullableAttrDOMJIT::TestDOMJITDoubleNullableAttrDOMJIT):
(WebCore::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT):
(WebCore::TestDOMJITDomStringNullableAttrDOMJIT::TestDOMJITDomStringNullableAttrDOMJIT):
(WebCore::TestDOMJITByteStringNullableAttrDOMJIT::TestDOMJITByteStringNullableAttrDOMJIT):
(WebCore::TestDOMJITUsvStringNullableAttrDOMJIT::TestDOMJITUsvStringNullableAttrDOMJIT):
(WebCore::TestDOMJITNodeNullableAttrDOMJIT::TestDOMJITNodeNullableAttrDOMJIT):
(WebCore::jsTestDOMJITPrototypeFunctionGetAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionGetAttributeCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionGetAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionItem):
(WebCore::jsTestDOMJITPrototypeFunctionItemCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionItem):
(WebCore::jsTestDOMJITPrototypeFunctionHasAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionHasAttributeCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionHasAttribute):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementById):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementByIdCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionGetElementById):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementsByName):
(WebCore::jsTestDOMJITPrototypeFunctionGetElementsByNameCaller):
(WebCore::unsafeJsTestDOMJITPrototypeFunctionGetElementsByName):
* bindings/scripts/test/TestDOMJIT.idl:
* dom/Element.idl:
* domjit/DOMJITAbstractHeapRepository.yaml: Added.
* domjit/DOMJITIDLConvert.h: Added.
(WebCore::DOMJIT::DirectConverter<IDLDOMString>::directConvert<StringConversionConfiguration::Normal>):
* domjit/DOMJITIDLType.h: Added.
* domjit/DOMJITIDLTypeFilter.h: Added.
* domjit/JSDocumentDOMJIT.cpp:
(WebCore::DocumentDocumentElementDOMJIT::callDOMGetter):
* domjit/JSNodeDOMJIT.cpp:
(WebCore::NodeFirstChildDOMJIT::callDOMGetter):
(WebCore::NodeLastChildDOMJIT::callDOMGetter):
(WebCore::NodeNextSiblingDOMJIT::callDOMGetter):
(WebCore::NodePreviousSiblingDOMJIT::callDOMGetter):
(WebCore::NodeParentNodeDOMJIT::callDOMGetter):
(WebCore::NodeOwnerDocumentDOMJIT::callDOMGetter):
* domjit/generate-abstract-heap.rb: Added.

LayoutTests:

* js/dom/domjit-accessor-licm.html:
* js/dom/domjit-function-effect-should-overlap-with-call-expected.txt: Added.
* js/dom/domjit-function-effect-should-overlap-with-call.html: Added.
* js/dom/domjit-function-expected.txt: Added.
* js/dom/domjit-function-licm-expected.txt: Added.
* js/dom/domjit-function-licm.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
* js/dom/domjit-function-type-contradiction-expected.txt: Added.
* js/dom/domjit-function-type-contradiction.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
* js/dom/domjit-function-type-failure-expected.txt: Added.
* js/dom/domjit-function-type-failure.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
* js/dom/domjit-function.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208320 268f45cc-cd09-0410-ab3c-d52691b4dbfc

70 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/domjit-accessor-licm.html
LayoutTests/js/dom/domjit-function-effect-should-overlap-with-call-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-effect-should-overlap-with-call.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-licm-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-licm.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-type-contradiction-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-type-contradiction.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-type-failure-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/domjit-function-type-failure.html [new file with mode: 0644]
LayoutTests/js/dom/domjit-function.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CallVariant.h
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/domjit/DOMJITEffect.h
Source/JavaScriptCore/domjit/DOMJITHeapRange.h
Source/JavaScriptCore/domjit/DOMJITSignature.h [new file with mode: 0644]
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/jit/JITThunks.cpp
Source/JavaScriptCore/jit/JITThunks.h
Source/JavaScriptCore/runtime/JSBoundFunction.cpp
Source/JavaScriptCore/runtime/JSCell.h
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/Lookup.h
Source/JavaScriptCore/runtime/NativeExecutable.cpp
Source/JavaScriptCore/runtime/NativeExecutable.h
Source/JavaScriptCore/runtime/PropertySlot.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/ForwardingHeaders/bytecode/SpeculatedType.h [moved from Source/WebCore/domjit/DOMJITAbstractHeapRepository.h with 58% similarity]
Source/WebCore/ForwardingHeaders/domjit/DOMJITSignature.h [moved from Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp with 53% similarity]
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSDOMGlobalObject.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLAttributes.txt
Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.cpp
Source/WebCore/bindings/scripts/test/TestDOMJIT.idl
Source/WebCore/dom/Element.idl
Source/WebCore/domjit/DOMJITAbstractHeapRepository.yaml [new file with mode: 0644]
Source/WebCore/domjit/DOMJITIDLConvert.h [new file with mode: 0644]
Source/WebCore/domjit/DOMJITIDLType.h [new file with mode: 0644]
Source/WebCore/domjit/DOMJITIDLTypeFilter.h [new file with mode: 0644]
Source/WebCore/domjit/JSDocumentDOMJIT.cpp
Source/WebCore/domjit/JSNodeDOMJIT.cpp
Source/WebCore/domjit/generate-abstract-heap.rb [new file with mode: 0644]

index d9c52b8..90d4737 100644 (file)
@@ -1,3 +1,22 @@
+2016-11-02  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add DOMJIT::Signature
+        https://bugs.webkit.org/show_bug.cgi?id=162980
+
+        Reviewed by Saam Barati and Sam Weinig.
+
+        * js/dom/domjit-accessor-licm.html:
+        * js/dom/domjit-function-effect-should-overlap-with-call-expected.txt: Added.
+        * js/dom/domjit-function-effect-should-overlap-with-call.html: Added.
+        * js/dom/domjit-function-expected.txt: Added.
+        * js/dom/domjit-function-licm-expected.txt: Added.
+        * js/dom/domjit-function-licm.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
+        * js/dom/domjit-function-type-contradiction-expected.txt: Added.
+        * js/dom/domjit-function-type-contradiction.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
+        * js/dom/domjit-function-type-failure-expected.txt: Added.
+        * js/dom/domjit-function-type-failure.html: Copied from LayoutTests/js/dom/domjit-accessor-licm.html.
+        * js/dom/domjit-function.html: Added.
+
 2016-11-02  Ryan Haddad  <ryanhaddad@apple.com>
 
         Marking imported/mozilla/svg/paint-order-01.svg and imported/mozilla/svg/paint-order-02.svg as flaky.
index e563eba..40d5560 100644 (file)
@@ -1,14 +1,3 @@
-<!DOCTYPE HTML>
-<html lang="en">
-<head>
-<meta charset="UTF-8">
-</head>
-<body>
-<script>
-
-</script>
-</body>
-</html>
 <!DOCTYPE html>
 <html>
 <head>
diff --git a/LayoutTests/js/dom/domjit-function-effect-should-overlap-with-call-expected.txt b/LayoutTests/js/dom/domjit-function-effect-should-overlap-with-call-expected.txt
new file mode 100644 (file)
index 0000000..11dc196
--- /dev/null
@@ -0,0 +1,10 @@
+Test function calls should overlap with effects of DOMJIT functions.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS test() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-function-effect-should-overlap-with-call.html b/LayoutTests/js/dom/domjit-function-effect-should-overlap-with-call.html
new file mode 100644 (file)
index 0000000..28cb392
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="target"></div>
+</div>
+
+<script>
+description('Test function calls should overlap with effects of DOMJIT functions.');
+
+function test()
+{
+    var target = document.getElementById('target');
+    target.setAttribute("cocoa", "0");
+    for (var i = 0; i < 1e4; ++i) {
+        var ret = target.getAttribute("cocoa");
+        if (ret !== String(i))
+            return false;
+        target.setAttribute("cocoa", String(i + 1));
+        var ret = target.getAttribute("cocoa");
+        if (ret === String(i))
+            return false;
+    }
+    return true;
+}
+
+shouldBeTrue(`test()`);
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-function-expected.txt b/LayoutTests/js/dom/domjit-function-expected.txt
new file mode 100644 (file)
index 0000000..45e56eb
--- /dev/null
@@ -0,0 +1,10 @@
+Test DOMJIT functions work.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS All tests passed.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-function-licm-expected.txt b/LayoutTests/js/dom/domjit-function-licm-expected.txt
new file mode 100644 (file)
index 0000000..f13c033
--- /dev/null
@@ -0,0 +1,8 @@
+Test DOMJIT function will be LICM-ed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-function-licm.html b/LayoutTests/js/dom/domjit-function-licm.html
new file mode 100644 (file)
index 0000000..5f2e399
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test DOMJIT function will be LICM-ed.');
+
+function test() {
+    var div = document.createElement('div');
+    var ret = "invalid";
+    div.setAttribute("cocoa", "Cocoa");
+    for (var i = 0; i < 1e4; ++i)
+        ret = div.getAttribute("cocoa");
+    return ret;
+}
+var result;
+(function () {
+    for (var i = 0; i < 100; ++i) {
+        result = test();
+        shouldBe(`result`, `"Cocoa"`, true);
+    }
+}());
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-function-type-contradiction-expected.txt b/LayoutTests/js/dom/domjit-function-type-contradiction-expected.txt
new file mode 100644 (file)
index 0000000..3d6877d
--- /dev/null
@@ -0,0 +1,8 @@
+Test DOMJIT function will cause type contradiction giving up.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-function-type-contradiction.html b/LayoutTests/js/dom/domjit-function-type-contradiction.html
new file mode 100644 (file)
index 0000000..84dc5b6
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test DOMJIT function will cause type contradiction giving up.');
+
+var div = document.createElement('div');
+div.setAttribute("cocoa", "Cocoa");
+function test(div) {
+    var ret = "invalid";
+    for (var i = 0; i < 1e4; ++i)
+        ret = div.getAttribute(200);
+    return ret;
+}
+var result;
+(function () {
+    for (var i = 0; i < 100; ++i) {
+        result = test(div);
+        shouldBe(`result`, `null`, true);
+    }
+}());
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-function-type-failure-expected.txt b/LayoutTests/js/dom/domjit-function-type-failure-expected.txt
new file mode 100644 (file)
index 0000000..2c102b3
--- /dev/null
@@ -0,0 +1,8 @@
+Test DOMJIT function will cause BadType OSR exits.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/dom/domjit-function-type-failure.html b/LayoutTests/js/dom/domjit-function-type-failure.html
new file mode 100644 (file)
index 0000000..6b76614
--- /dev/null
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+
+<div id="parentNode">
+<div id="previousSibling"></div><div id="target"><div id="firstChild"></div><div id="lastChild"></div></div><div id="nextSibling"></div>
+</div>
+
+<script>
+description('Test DOMJIT function will cause BadType OSR exits.');
+
+var div = document.createElement('div');
+div.setAttribute("cocoa", "Cocoa");
+function test(div, name) {
+    var ret = "invalid";
+    for (var i = 0; i < 1e4; ++i)
+        ret = div.getAttribute(name);
+    return ret;
+}
+var result;
+(function () {
+    for (var i = 0; i < 100; ++i) {
+        result = test(div, 'cocoa');
+        shouldBe(`result`, `"Cocoa"`, true);
+    }
+    for (var i = 0; i < 100; ++i) {
+        result = test(div, 400);
+        shouldBe(`result`, `null`, true);
+    }
+}());
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/dom/domjit-function.html b/LayoutTests/js/dom/domjit-function.html
new file mode 100644 (file)
index 0000000..91ea8a5
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="target" cocoa="cocoa"><div id="firstChild"></div><div id="lastChild"></div></div>
+</div>
+
+<script>
+description('Test DOMJIT functions work.');
+var div;
+(function () {
+    div = document.getElementById('target');
+
+    function a()
+    {
+        return div.getAttribute('cocoa') === 'cocoa';
+    }
+
+    function b()
+    {
+        return div.getAttributeNode('cocoa').nodeType === Node.ATTRIBUTE_NODE;
+    }
+
+    function c()
+    {
+        return div.getElementsByTagName('div').length === 2;
+    }
+
+    function d()
+    {
+        return div.hasAttribute('cocoa') === true;
+    }
+
+    function main()
+    {
+        if (!a())
+            return false;
+        if (!b())
+            return false;
+        if (!c())
+            return false;
+        if (!d())
+            return false;
+        return true;
+    }
+
+    for (var i = 0; i < 1e4; ++i) {
+        if (!main())
+            throw new Error("error");
+    }
+    testPassed("All tests passed.");
+}());
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
index 6bf2347..73c98b2 100644 (file)
@@ -1,3 +1,134 @@
+2016-11-02  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add DOMJIT::Signature
+        https://bugs.webkit.org/show_bug.cgi?id=162980
+
+        Reviewed by Saam Barati and Sam Weinig.
+
+        This patch introduces a new mechanism called DOMJIT::Signature. We can annotate the function with DOMJIT::Signature.
+        DOMJIT::Signature has type information of that function. And it also maintains the effect of the function and the
+        pointer to the unsafe function. The unsafe function means the function without type and argument count checks.
+        By using these information, we can separate type and argument count checks from the function. And we can emit
+        these things as DFG checks and convert the function call itself to CallDOM node. CallDOM node can call the unsafe
+        function directly without any checks. Furthermore, this CallDOM node can represent its own clobberizing rules based
+        on DOMJIT::Effect maintained by DOMJIT::Signature. It allows us to make opaque Call node to a CallDOM node that
+        merely reads some part of heap. These changes (1) can drop duplicate type checks in DFG, (2) offer ability to move
+        CallDOM node to somewhere, and (3) track more detailed heap reads and writes of CallDOM nodes.
+
+        We first emit Call node with DOMJIT::Signature in DFGByteCodeParser. And in the fixup phase, we attempt to lower
+        Call node to CallDOM node with checks & edge filters. This is because we do not know the type predictions in
+        DFGByteCodeParser phase. If we always emit CallDOM node in DFGByteCodeParser, if we evaluate `div.getAttribute(true)`
+        thingy, the Uncountable OSR exits repeatedly happen because AI figures out the abstract value is cleared.
+
+        Currently, DOMJIT signature only allows the types that can reside in GPR. This is because the types of the unsafe
+        function arguments are represented as the sequence of void*. In the future, we will extend to accept other types like
+        float, double etc.
+
+        We annotate several functions in Element. In particular, we annotate Element::getAttribute. This allows us to perform
+        LICM in Dromaeo dom-attr test. In the Dromaeo dom-attr getAttribute test, we can see 32x improvement. (134974.8 v.s. 4203.4)
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CallVariant.h:
+        (JSC::CallVariant::functionExecutable):
+        (JSC::CallVariant::nativeExecutable):
+        (JSC::CallVariant::signatureFor):
+        * bytecode/SpeculatedType.h:
+        (JSC::isNotStringSpeculation):
+        (JSC::isNotInt32Speculation):
+        (JSC::isNotBooleanSpeculation):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addCall):
+        (JSC::DFG::ByteCodeParser::handleCall):
+        (JSC::DFG::ByteCodeParser::attemptToInlineCall):
+        (JSC::DFG::ByteCodeParser::handleInlining):
+        (JSC::DFG::ByteCodeParser::handleDOMJITCall):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::attemptToMakeCallDOM):
+        (JSC::DFG::FixupPhase::fixupCheckDOM):
+        (JSC::DFG::FixupPhase::fixupCallDOM):
+        * dfg/DFGNode.cpp:
+        (JSC::DFG::Node::convertToCallDOM):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        (JSC::DFG::Node::shouldSpeculateNotInt32):
+        (JSC::DFG::Node::shouldSpeculateNotBoolean):
+        (JSC::DFG::Node::shouldSpeculateNotString):
+        (JSC::DFG::Node::hasSignature):
+        (JSC::DFG::Node::signature):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCallDOM):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * domjit/DOMJITEffect.h:
+        (JSC::DOMJIT::Effect::Effect):
+        (JSC::DOMJIT::Effect::forWrite):
+        (JSC::DOMJIT::Effect::forRead):
+        (JSC::DOMJIT::Effect::forReadWrite):
+        (JSC::DOMJIT::Effect::forPure):
+        (JSC::DOMJIT::Effect::forDef):
+        (JSC::DOMJIT::Effect::mustGenerate):
+        In clang, we cannot make this Effect constructor constexpr if we use Optional<HeapRange>.
+        So we use HeapRange::top() for Nullopt def now.
+
+        * domjit/DOMJITHeapRange.h:
+        (JSC::DOMJIT::HeapRange::fromRaw):
+        (JSC::DOMJIT::HeapRange::operator bool):
+        (JSC::DOMJIT::HeapRange::operator==):
+        (JSC::DOMJIT::HeapRange::operator!=):
+        (JSC::DOMJIT::HeapRange::fromConstant):
+        * domjit/DOMJITSignature.h: Copied from Source/JavaScriptCore/domjit/DOMJITEffect.h.
+        (JSC::DOMJIT::Signature::Signature):
+        (JSC::DOMJIT::Signature::argumentCount):
+        (JSC::DOMJIT::Signature::checkDOM):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
+        * jit/JITOperations.h:
+        * jit/JITThunks.cpp:
+        (JSC::JITThunks::hostFunctionStub):
+        * jit/JITThunks.h:
+        * runtime/JSBoundFunction.cpp:
+        (JSC::JSBoundFunction::create):
+        * runtime/JSCell.h:
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::create):
+        * runtime/JSFunction.h:
+        * runtime/JSNativeStdFunction.cpp:
+        (JSC::JSNativeStdFunction::create):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::putDirectNativeFunction):
+        * runtime/JSObject.h:
+        * runtime/Lookup.h:
+        (JSC::HashTableValue::functionLength):
+        (JSC::HashTableValue::signature):
+        (JSC::reifyStaticProperty):
+        * runtime/NativeExecutable.cpp:
+        (JSC::NativeExecutable::create):
+        (JSC::NativeExecutable::NativeExecutable):
+        * runtime/NativeExecutable.h:
+        * runtime/PropertySlot.h:
+        * runtime/VM.cpp:
+        (JSC::VM::getHostFunction):
+        * runtime/VM.h:
+
 2016-11-02  Andreas Kling  <akling@apple.com>
 
         MarkedSpace should have specialized size classes for popular engine objects.
index 3b04a18..016e4f9 100644 (file)
                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 */; };
                E34EDBF71DB5FFC900DC87A5 /* FrameTracers.h in Headers */ = {isa = PBXBuildFile; fileRef = E34EDBF61DB5FFC100DC87A5 /* FrameTracers.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E350708A1DC49BBF0089BCD6 /* DOMJITSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = E35070891DC49BB60089BCD6 /* DOMJITSignature.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E354622B1B6065D100545386 /* ConstructAbility.h in Headers */ = {isa = PBXBuildFile; fileRef = E354622A1B6065D100545386 /* ConstructAbility.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3555B8A1DAE03A500F36921 /* DOMJITCallDOMGetterPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E355F3521B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */; };
                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>"; };
                E34EDBF61DB5FFC100DC87A5 /* FrameTracers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameTracers.h; sourceTree = "<group>"; };
+               E35070891DC49BB60089BCD6 /* DOMJITSignature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITSignature.h; sourceTree = "<group>"; };
                E354622A1B6065D100545386 /* ConstructAbility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstructAbility.h; sourceTree = "<group>"; };
                E3555B891DAE03A200F36921 /* DOMJITCallDOMGetterPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITCallDOMGetterPatchpoint.h; sourceTree = "<group>"; };
                E355F3501B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleLoaderPrototype.cpp; sourceTree = "<group>"; };
                                E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */,
                                E37AD83B1DA4928000F3D412 /* DOMJITReg.h */,
                                E3CB1E241DA7540A00FA1E56 /* DOMJITSlowPathCalls.h */,
+                               E35070891DC49BB60089BCD6 /* DOMJITSignature.h */,
                                E3FFC8521DAD7D1000DEA53E /* DOMJITValue.h */,
                        );
                        path = domjit;
                                43AB26C61C1A535900D82AE6 /* B3MathExtras.h in Headers */,
                                AD2FCBF31DB58DAD00B3E736 /* WebAssemblyInstancePrototype.h in Headers */,
                                BC18C4290E16F5CD00B34460 /* JSStringRefCF.h in Headers */,
+                               E350708A1DC49BBF0089BCD6 /* DOMJITSignature.h in Headers */,
                                1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */,
                                0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */,
                                70ECA6061AFDBEA200449739 /* JSTemplateRegistryKey.h in Headers */,
index de68800..cb288c6 100644 (file)
@@ -28,6 +28,7 @@
 #include "FunctionExecutable.h"
 #include "JSCell.h"
 #include "JSFunction.h"
+#include "NativeExecutable.h"
 
 namespace JSC {
 
@@ -120,6 +121,20 @@ public:
             return jsDynamicCast<FunctionExecutable*>(executable);
         return nullptr;
     }
+
+    NativeExecutable* nativeExecutable() const
+    {
+        if (ExecutableBase* executable = this->executable())
+            return jsDynamicCast<NativeExecutable*>(executable);
+        return nullptr;
+    }
+
+    const DOMJIT::Signature* signatureFor(CodeSpecializationKind kind) const
+    {
+        if (NativeExecutable* nativeExecutable = this->nativeExecutable())
+            return nativeExecutable->signatureFor(kind);
+        return nullptr;
+    }
     
     void dump(PrintStream& out) const;
     
index f43dfcd..e23fd2c 100644 (file)
@@ -151,6 +151,11 @@ inline bool isStringSpeculation(SpeculatedType value)
     return !!value && (value & SpecString) == value;
 }
 
+inline bool isNotStringSpeculation(SpeculatedType value)
+{
+    return value && !(value & SpecString);
+}
+
 inline bool isStringOrOtherSpeculation(SpeculatedType value)
 {
     return !!value && (value & (SpecString | SpecOther)) == value;
@@ -303,6 +308,11 @@ inline bool isInt32Speculation(SpeculatedType value)
     return value && !(value & ~SpecInt32Only);
 }
 
+inline bool isNotInt32Speculation(SpeculatedType value)
+{
+    return value && !(value & SpecInt32Only);
+}
+
 inline bool isInt32OrBooleanSpeculation(SpeculatedType value)
 {
     return value && !(value & ~(SpecBoolean | SpecInt32Only));
@@ -388,6 +398,11 @@ inline bool isBooleanSpeculation(SpeculatedType value)
     return value == SpecBoolean;
 }
 
+inline bool isNotBooleanSpeculation(SpeculatedType value)
+{
+    return value && !(value & SpecBoolean);
+}
+
 inline bool isOtherSpeculation(SpeculatedType value)
 {
     return value == SpecOther;
index 43b51a1..7adba71 100644 (file)
@@ -30,6 +30,7 @@
 #include "ArrayConstructor.h"
 #include "DFGAbstractInterpreter.h"
 #include "DOMJITGetterSetter.h"
+#include "DOMJITSignature.h"
 #include "GetByIdStatus.h"
 #include "GetterSetter.h"
 #include "HashMapImpl.h"
@@ -2303,6 +2304,13 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).setType(m_graph, callDOMGetterData->domJIT->resultType());
         break;
     }
+    case CallDOM: {
+        const DOMJIT::Signature* signature = node->signature();
+        if (signature->effect.writes)
+            clobberWorld(node->origin.semantic, clobberLimit);
+        forNode(node).setType(m_graph, signature->result);
+        break;
+    }
     case CheckArray: {
         if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
             m_state.setFoundConstants(true);
index e514ee1..7f21fa6 100644 (file)
@@ -213,6 +213,8 @@ private:
     template<typename ChecksFunctor>
     bool handleIntrinsicCall(Node* callee, int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
+    bool handleDOMJITCall(Node* callee, int resultOperand, const DOMJIT::Signature*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks);
+    template<typename ChecksFunctor>
     bool handleIntrinsicGetter(int resultOperand, const GetByIdVariant& intrinsicVariant, Node* thisNode, const ChecksFunctor& insertChecks);
     template<typename ChecksFunctor>
     bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks);
@@ -818,18 +820,18 @@ private:
     }
     
     Node* addCall(
-        int result, NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset,
+        int result, NodeType op, const DOMJIT::Signature* signature, Node* callee, int argCount, int registerOffset,
         SpeculatedType prediction)
     {
         if (op == TailCall) {
             if (allInlineFramesAreTailCalls())
-                return addCallWithoutSettingResult(op, OpInfo(), callee, argCount, registerOffset, OpInfo());
+                return addCallWithoutSettingResult(op, OpInfo(signature), callee, argCount, registerOffset, OpInfo());
             op = TailCallInlinedCaller;
         }
 
 
         Node* call = addCallWithoutSettingResult(
-            op, opInfo, callee, argCount, registerOffset, OpInfo(prediction));
+            op, OpInfo(signature), callee, argCount, registerOffset, OpInfo(prediction));
         VirtualRegister resultReg(result);
         if (resultReg.isValid())
             set(resultReg, call);
@@ -1284,7 +1286,7 @@ ByteCodeParser::Terminality ByteCodeParser::handleCall(
         // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically
         // that we cannot optimize them.
 
-        Node* callNode = addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction);
+        Node* callNode = addCall(result, op, nullptr, callTarget, argumentCountIncludingThis, registerOffset, prediction);
         if (callNode->op() == TailCall)
             return Terminal;
         ASSERT(callNode->op() != TailCallVarargs && callNode->op() != TailCallForwardVarargs);
@@ -1299,7 +1301,7 @@ ByteCodeParser::Terminality ByteCodeParser::handleCall(
         return NonTerminal;
     }
     
-    Node* callNode = addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction);
+    Node* callNode = addCall(result, op, nullptr, callTarget, argumentCountIncludingThis, registerOffset, prediction);
     if (callNode->op() == TailCall)
         return Terminal;
     ASSERT(callNode->op() != TailCallVarargs && callNode->op() != TailCallForwardVarargs);
@@ -1726,6 +1728,19 @@ bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand
             RELEASE_ASSERT(!didInsertChecks);
             // We might still try to inline the Intrinsic because it might be a builtin JS function.
         }
+
+        if (Options::useDOMJIT()) {
+            if (const DOMJIT::Signature* signature = callee.signatureFor(specializationKind)) {
+                if (handleDOMJITCall(callTargetNode, resultOperand, signature, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
+                    RELEASE_ASSERT(didInsertChecks);
+                    addToGraph(Phantom, callTargetNode);
+                    emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
+                    inliningBalance--;
+                    return true;
+                }
+                RELEASE_ASSERT(!didInsertChecks);
+            }
+        }
     }
     
     unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, InlineCallFrame::callModeFor(kind));
@@ -2051,7 +2066,7 @@ bool ByteCodeParser::handleInlining(
     Node* myCallTargetNode = getDirect(calleeReg);
     if (couldTakeSlowPath) {
         addCall(
-            resultOperand, callOp, OpInfo(), myCallTargetNode, argumentCountIncludingThis,
+            resultOperand, callOp, nullptr, myCallTargetNode, argumentCountIncludingThis,
             registerOffset, prediction);
     } else {
         addToGraph(CheckBadCell);
@@ -2601,6 +2616,25 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin
 }
 
 template<typename ChecksFunctor>
+bool ByteCodeParser::handleDOMJITCall(Node* callTarget, int resultOperand, const DOMJIT::Signature* signature, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, const ChecksFunctor& insertChecks)
+{
+    if (argumentCountIncludingThis != static_cast<int>(1 + signature->argumentCount))
+        return false;
+    if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
+        return false;
+
+    // FIXME: Currently, we only support functions which arguments are up to 2.
+    // Eventually, we should extend this. But possibly, 2 or 3 can cover typical use cases.
+    // https://bugs.webkit.org/show_bug.cgi?id=164346
+    ASSERT_WITH_MESSAGE(argumentCountIncludingThis <= JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS, "Currently CallDOM does not support an arbitrary length arguments.");
+
+    insertChecks();
+    addCall(resultOperand, Call, signature, callTarget, argumentCountIncludingThis, registerOffset, prediction);
+    return true;
+}
+
+
+template<typename ChecksFunctor>
 bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, const ChecksFunctor& insertChecks)
 {
     switch (variant.intrinsic()) {
@@ -4792,7 +4826,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             int callee = currentInstruction[2].u.operand;
             int argumentCountIncludingThis = currentInstruction[3].u.operand;
             int registerOffset = -currentInstruction[4].u.operand;
-            addCall(result, CallEval, OpInfo(), get(VirtualRegister(callee)), argumentCountIncludingThis, registerOffset, getPrediction());
+            addCall(result, CallEval, nullptr, get(VirtualRegister(callee)), argumentCountIncludingThis, registerOffset, getPrediction());
             NEXT_OPCODE(op_call_eval);
         }
             
index b621ef0..e5d2172 100644 (file)
@@ -34,6 +34,7 @@
 #include "DFGLazyNode.h"
 #include "DFGPureValue.h"
 #include "DOMJITCallDOMGetterPatchpoint.h"
+#include "DOMJITSignature.h"
 
 namespace JSC { namespace DFG {
 
@@ -958,20 +959,38 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
             else
                 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
         }
-        if (effect.def) {
-            DOMJIT::HeapRange range = effect.def.value();
+        if (effect.def != DOMJIT::HeapRange::top()) {
+            DOMJIT::HeapRange range = effect.def;
             if (range == DOMJIT::HeapRange::none())
                 def(PureValue(node, node->callDOMGetterData()->domJIT));
             else {
                 // Def with heap location. We do not include "GlobalObject" for that since this information is included in the base node.
-                // FIXME: When supporting the other nodes like getElementById("string"), we should include the base and the id string.
-                // Currently, we only see the DOMJIT getter here. So just including "base" is ok.
+                // We only see the DOMJIT getter here. So just including "base" is ok.
                 def(HeapLocation(DOMStateLoc, AbstractHeap(DOMState, range.rawRepresentation()), node->child1()), LazyNode(node));
             }
         }
         return;
     }
 
+    case CallDOM: {
+        const DOMJIT::Signature* signature = node->signature();
+        DOMJIT::Effect effect = signature->effect;
+        if (effect.reads) {
+            if (effect.reads == DOMJIT::HeapRange::top())
+                read(World);
+            else
+                read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
+        }
+        if (effect.writes) {
+            if (effect.writes == DOMJIT::HeapRange::top())
+                write(Heap);
+            else
+                write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
+        }
+        ASSERT_WITH_MESSAGE(effect.def == DOMJIT::HeapRange::top(), "Currently, we do not accept any def for CallDOM.");
+        return;
+    }
+
     case Arrayify:
     case ArrayifyToStructure:
         read(JSCell_structureID);
index 97cd848..9e6aa55 100644 (file)
@@ -301,6 +301,7 @@ bool doesGC(Graph& graph, Node* node)
     case CreateRest:
     case ToLowerCase:
     case CallDOMGetter:
+    case CallDOM:
         return true;
         
     case MultiPutByOffset:
index 1d4e907..c8dd562 100644 (file)
@@ -1708,9 +1708,10 @@ private:
             break;
         }
 
-        case CheckDOM:
-            fixEdge<CellUse>(node->child1());
+        case CheckDOM: {
+            fixupCheckDOM(node);
             break;
+        }
 
         case CallDOMGetter: {
             DOMJIT::CallDOMGetterPatchpoint* patchpoint = node->callDOMGetterData()->patchpoint;
@@ -1720,6 +1721,16 @@ private:
             break;
         }
 
+        case CallDOM: {
+            fixupCallDOM(node);
+            break;
+        }
+
+        case Call: {
+            attemptToMakeCallDOM(node);
+            break;
+        }
+
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:
@@ -1736,7 +1747,6 @@ private:
         case GetGlobalVar:
         case GetGlobalLexicalVariable:
         case NotifyWrite:
-        case Call:
         case DirectCall:
         case CheckTypeInfoFlags:
         case TailCallInlinedCaller:
@@ -2659,6 +2669,93 @@ private:
             OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
     }
     
+    bool attemptToMakeCallDOM(Node* node)
+    {
+        if (m_graph.hasExitSite(node->origin.semantic, BadType))
+            return false;
+
+        const DOMJIT::Signature* signature = node->signature();
+        if (!signature)
+            return false;
+
+        {
+            unsigned index = 0;
+            bool shouldConvertToCallDOM = true;
+            m_graph.doToChildren(node, [&](Edge& edge) {
+                // Callee. Ignore this. DFGByteCodeParser already emit appropriate checks.
+                if (!index)
+                    return;
+
+                if (index == 1) {
+                    // DOM node case.
+                    if (edge->shouldSpeculateNotCell())
+                        shouldConvertToCallDOM = false;
+                } else {
+                    switch (signature->arguments[index - 2]) {
+                    case SpecString:
+                        if (edge->shouldSpeculateNotString())
+                            shouldConvertToCallDOM = false;
+                        break;
+                    case SpecInt32Only:
+                        if (edge->shouldSpeculateNotInt32())
+                            shouldConvertToCallDOM = false;
+                        break;
+                    case SpecBoolean:
+                        if (edge->shouldSpeculateNotBoolean())
+                            shouldConvertToCallDOM = false;
+                        break;
+                    default:
+                        RELEASE_ASSERT_NOT_REACHED();
+                        break;
+                    }
+                }
+                ++index;
+            });
+            if (!shouldConvertToCallDOM)
+                return false;
+        }
+
+        Node* thisNode = m_graph.varArgChild(node, 1).node();
+        Ref<DOMJIT::Patchpoint> checkDOMPatchpoint = signature->checkDOM();
+        m_graph.m_domJITPatchpoints.append(checkDOMPatchpoint.ptr());
+        Node* checkDOM = m_insertionSet.insertNode(m_indexInBlock, SpecNone, CheckDOM, node->origin, OpInfo(checkDOMPatchpoint.ptr()), OpInfo(signature->classInfo), Edge(thisNode));
+        node->convertToCallDOM(m_graph);
+        fixupCheckDOM(checkDOM);
+        fixupCallDOM(node);
+        return true;
+    }
+
+    void fixupCheckDOM(Node* node)
+    {
+        fixEdge<CellUse>(node->child1());
+    }
+
+    void fixupCallDOM(Node* node)
+    {
+        const DOMJIT::Signature* signature = node->signature();
+        auto fixup = [&](Edge& edge, unsigned argumentIndex) {
+            if (!edge)
+                return;
+            switch (signature->arguments[argumentIndex]) {
+            case SpecString:
+                fixEdge<StringUse>(edge);
+                break;
+            case SpecInt32Only:
+                fixEdge<Int32Use>(edge);
+                break;
+            case SpecBoolean:
+                fixEdge<BooleanUse>(edge);
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+        };
+        fixEdge<CellUse>(node->child1()); // DOM.
+        fixup(node->child2(), 0);
+        fixup(node->child3(), 1);
+    }
+
     void fixupChecksInBlock(BasicBlock* block)
     {
         if (!block)
index f37117b..6a94b59 100644 (file)
@@ -220,6 +220,26 @@ void Node::convertToDirectCall(FrozenValue* executable)
     m_opInfo = executable;
 }
 
+void Node::convertToCallDOM(Graph& graph)
+{
+    ASSERT(op() == Call);
+    ASSERT(signature());
+
+    Edge edges[3];
+    // Skip the first one. This is callee.
+    RELEASE_ASSERT(numChildren() <= 4);
+    for (unsigned i = 1; i < numChildren(); ++i)
+        edges[i - 1] = graph.varArgChild(this, i);
+
+    setOpAndDefaultFlags(CallDOM);
+    children.setChild1(edges[0]);
+    children.setChild2(edges[1]);
+    children.setChild3(edges[2]);
+
+    if (!signature()->effect.mustGenerate())
+        clearFlags(NodeMustGenerate);
+}
+
 String Node::tryGetString(Graph& graph)
 {
     if (hasConstant())
index 88f8811..07d644f 100644 (file)
@@ -62,6 +62,7 @@ namespace DOMJIT {
 class GetterSetter;
 class Patchpoint;
 class CallDOMGetterPatchpoint;
+class Signature;
 }
 
 namespace Profiler {
@@ -652,6 +653,8 @@ public:
     }
     
     void convertToDirectCall(FrozenValue*);
+
+    void convertToCallDOM(Graph&);
     
     JSValue asJSValue()
     {
@@ -1464,6 +1467,7 @@ public:
         case ToNumber:
         case LoadFromJSMapBucket:
         case CallDOMGetter:
+        case CallDOM:
             return true;
         default:
             return false;
@@ -1981,6 +1985,11 @@ public:
     {
         return isInt32Speculation(prediction());
     }
+
+    bool shouldSpeculateNotInt32()
+    {
+        return isNotInt32Speculation(prediction());
+    }
     
     bool sawBooleans()
     {
@@ -2041,6 +2050,11 @@ public:
     {
         return isBooleanSpeculation(prediction());
     }
+
+    bool shouldSpeculateNotBoolean()
+    {
+        return isNotBooleanSpeculation(prediction());
+    }
     
     bool shouldSpeculateOther()
     {
@@ -2066,6 +2080,11 @@ public:
     {
         return isStringSpeculation(prediction());
     }
+
+    bool shouldSpeculateNotString()
+    {
+        return isNotStringSpeculation(prediction());
+    }
  
     bool shouldSpeculateStringOrOther()
     {
@@ -2368,6 +2387,18 @@ public:
         return m_opInfo2.as<const ClassInfo*>();
     }
 
+    bool hasSignature() const
+    {
+        // Note that this does not include TailCall node types intentionally.
+        // CallDOM node types are always converted from Call.
+        return op() == Call || op() == CallDOM;
+    }
+
+    const DOMJIT::Signature* signature()
+    {
+        return m_opInfo.as<const DOMJIT::Signature*>();
+    }
+
     Node* replacement() const
     {
         return m_misc.replacement;
index d975b76..f37423c 100644 (file)
@@ -407,6 +407,7 @@ namespace JSC { namespace DFG {
     /* Nodes for DOM JIT */\
     macro(CheckDOM, NodeMustGenerate) \
     macro(CallDOMGetter, NodeResultJS | NodeMustGenerate) \
+    macro(CallDOM, NodeResultJS | NodeMustGenerate) \
 
 // 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).
index 6ed729b..20531a0 100644 (file)
@@ -1020,7 +1020,8 @@ private:
         case GetRegExpObjectLastIndex:
         case SetRegExpObjectLastIndex:
         case RecordRegExpCachedResult:
-        case LazyJSConstant: {
+        case LazyJSConstant:
+        case CallDOM: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
             DFG_CRASH(m_graph, m_currentNode, "Unexpected node during prediction propagation");
index 2c99802..3fe9dc1 100644 (file)
@@ -220,6 +220,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case GetExecutable:
     case GetButterfly:
     case CallDOMGetter:
+    case CallDOM:
     case CheckDOM:
     case CheckArray:
     case Arrayify:
index 2732fe8..3419b70 100644 (file)
@@ -7260,6 +7260,88 @@ static void allocateTemporaryRegistersForPatchpoint(SpeculativeJIT* jit, Vector<
     }
 }
 
+void SpeculativeJIT::compileCallDOM(Node* node)
+{
+    const DOMJIT::Signature* signature = node->signature();
+
+    // FIXME: We should have a way to call functions with the vector of registers.
+    // https://bugs.webkit.org/show_bug.cgi?id=163099
+    Vector<Variant<SpeculateCellOperand, SpeculateInt32Operand, SpeculateBooleanOperand>, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> operands;
+    Vector<GPRReg, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> regs;
+
+    auto appendCell = [&](Edge& edge) {
+        SpeculateCellOperand operand(this, edge);
+        regs.append(operand.gpr());
+        operands.append(WTFMove(operand));
+    };
+
+    auto appendString = [&](Edge& edge) {
+        SpeculateCellOperand operand(this, edge);
+        GPRReg gpr = operand.gpr();
+        regs.append(gpr);
+        speculateString(edge, gpr);
+        operands.append(WTFMove(operand));
+    };
+
+    auto appendInt32 = [&](Edge& edge) {
+        SpeculateInt32Operand operand(this, edge);
+        regs.append(operand.gpr());
+        operands.append(WTFMove(operand));
+    };
+
+    auto appendBoolean = [&](Edge& edge) {
+        SpeculateBooleanOperand operand(this, edge);
+        regs.append(operand.gpr());
+        operands.append(WTFMove(operand));
+    };
+
+    unsigned index = 0;
+    m_jit.graph().doToChildren(node, [&](Edge edge) {
+        if (!index)
+            appendCell(edge);
+        else {
+            switch (signature->arguments[index - 1]) {
+            case SpecString:
+                appendString(edge);
+                break;
+            case SpecInt32Only:
+                appendInt32(edge);
+                break;
+            case SpecBoolean:
+                appendBoolean(edge);
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+        }
+        ++index;
+    });
+
+    JSValueRegsTemporary result(this);
+    JSValueRegs resultRegs = result.regs();
+
+    flushRegisters();
+    unsigned argumentCountIncludingThis = signature->argumentCount + 1;
+    switch (argumentCountIncludingThis) {
+    case 1:
+        callOperation(reinterpret_cast<J_JITOperation_EP>(signature->unsafeFunction), extractResult(resultRegs), regs[0]);
+        break;
+    case 2:
+        callOperation(reinterpret_cast<J_JITOperation_EPP>(signature->unsafeFunction), extractResult(resultRegs), regs[0], regs[1]);
+        break;
+    case 3:
+        callOperation(reinterpret_cast<J_JITOperation_EPPP>(signature->unsafeFunction), extractResult(resultRegs), regs[0], regs[1], regs[2]);
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+
+    m_jit.exceptionCheck();
+    jsValueResult(resultRegs, node);
+}
+
 void SpeculativeJIT::compileCallDOMGetter(Node* node)
 {
     DOMJIT::CallDOMGetterPatchpoint* patchpoint = node->callDOMGetterData()->patchpoint;
index 56538a2..796a8a3 100644 (file)
@@ -1651,6 +1651,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, arg2);
         return appendCallSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EPPP operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(J_JITOperation_EGP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -1915,6 +1920,16 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer));
         return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
     }
+    JITCompiler::Call callOperation(J_JITOperation_EPP operation, JSValueRegs result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
+    }
+    JITCompiler::Call callOperation(J_JITOperation_EPPP operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+        return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
+    }
     JITCompiler::Call callOperation(J_JITOperation_EGP operation, JSValueRegs result, GPRReg arg1, GPRReg arg2)
     {
         m_jit.setupArgumentsWithExecState(arg1, arg2);
@@ -2562,6 +2577,7 @@ public:
     void compileReallocatePropertyStorage(Node*);
     void compileGetButterfly(Node*);
     void compileCallDOMGetter(Node*);
+    void compileCallDOM(Node*);
     void compileCheckDOM(Node*);
     
 #if USE(JSVALUE32_64)
index cb04a5a..102429d 100644 (file)
@@ -5561,6 +5561,10 @@ void SpeculativeJIT::compile(Node* node)
         break;
     }
 
+    case CallDOM:
+        compileCallDOM(node);
+        break;
+
     case CallDOMGetter:
         compileCallDOMGetter(node);
         break;
index b41c6f3..830bfad 100644 (file)
@@ -5693,6 +5693,10 @@ void SpeculativeJIT::compile(Node* node)
         compileMaterializeNewObject(node);
         break;
 
+    case CallDOM:
+        compileCallDOM(node);
+        break;
+
     case CallDOMGetter:
         compileCallDOMGetter(node);
         break;
index 59e300c..61cf3b7 100644 (file)
 #include "DOMJITHeapRange.h"
 #include <wtf/Optional.h>
 
-#if ENABLE(JIT)
-
 namespace JSC { namespace DOMJIT {
 
-struct Effect {
+class Effect {
+public:
     HeapRange reads { HeapRange::top() };
     HeapRange writes { HeapRange::top() };
-    Optional<HeapRange> def;
+    HeapRange def { HeapRange::top() };
+
+    constexpr Effect() = default;
+    constexpr Effect(HeapRange reads, HeapRange writes)
+        : reads(reads)
+        , writes(writes)
+    {
+    }
+
+    constexpr Effect(HeapRange reads, HeapRange writes, HeapRange def)
+        : reads(reads)
+        , writes(writes)
+        , def(def)
+    {
+    }
 
-    static Effect forReadWrite(HeapRange readRange, HeapRange writeRange)
+    constexpr static Effect forWrite(HeapRange writeRange)
     {
-        Effect effect;
-        effect.reads = readRange;
-        effect.writes = writeRange;
-        return effect;
+        return Effect(HeapRange::none(), writeRange);
     }
 
-    static Effect forPure()
+    constexpr static Effect forRead(HeapRange readRange)
     {
-        Effect effect;
-        effect.reads = HeapRange::none();
-        effect.writes = HeapRange::none();
-        effect.def = HeapRange::none();
-        return effect;
+        return Effect(readRange, HeapRange::none());
     }
 
-    static Effect forDef(HeapRange def)
+    constexpr static Effect forReadWrite(HeapRange readRange, HeapRange writeRange)
     {
-        Effect effect;
-        effect.reads = def;
-        effect.writes = HeapRange::none();
-        effect.def = def;
-        return effect;
+        return Effect(readRange, writeRange);
     }
 
-    static Effect forDef(HeapRange def, HeapRange readRange, HeapRange writeRange)
+    constexpr static Effect forPure()
     {
-        Effect effect;
-        effect.reads = readRange;
-        effect.writes = writeRange;
-        effect.def = def;
-        return effect;
+        return Effect(HeapRange::none(), HeapRange::none(), HeapRange::none());
     }
 
-    bool mustGenerate() const
+    constexpr static Effect forDef(HeapRange def)
+    {
+        return Effect(def, HeapRange::none(), def);
+    }
+
+    constexpr static Effect forDef(HeapRange def, HeapRange readRange, HeapRange writeRange)
+    {
+        return Effect(readRange, writeRange, def);
+    }
+
+    constexpr bool mustGenerate() const
     {
         return !!writes;
     }
 };
 
 } }
-
-#endif
index fb93999..aab02bf 100644 (file)
@@ -28,8 +28,6 @@
 #include <wtf/MathExtras.h>
 #include <wtf/PrintStream.h>
 
-#if ENABLE(JIT)
-
 namespace JSC { namespace DOMJIT {
 
 class HeapRange {
@@ -47,7 +45,6 @@ public:
         ASSERT_WITH_MESSAGE(begin <= end, "begin <= end is the invariant of this HeapRange.");
     }
 
-private:
     enum ConstExprTag { ConstExpr };
     constexpr HeapRange(ConstExprTag, uint16_t begin, uint16_t end)
         : m_begin(begin)
@@ -55,21 +52,13 @@ private:
     {
     }
 
-    template<uint16_t begin, uint16_t end>
-    static constexpr HeapRange fromConstant()
-    {
-        static_assert(begin <= end, "begin <= end is the invariant of this HeapRange.");
-        return HeapRange(ConstExpr, begin, end);
-    }
-
-public:
     enum RawRepresentationTag { RawRepresentation };
     explicit constexpr HeapRange(RawRepresentationTag, uint32_t value)
         : m_raw(value)
     {
     }
 
-    static HeapRange fromRaw(uint32_t value)
+    constexpr static HeapRange fromRaw(uint32_t value)
     {
         return HeapRange(RawRepresentation, value);
     }
@@ -78,16 +67,28 @@ public:
     uint16_t end() const { return m_end; }
     uint32_t rawRepresentation() { return m_raw; }
 
-    explicit operator bool() const
+    constexpr explicit operator bool() const
     {
         return m_begin != m_end;
     }
 
-    bool operator==(const HeapRange& other) const
+    constexpr bool operator==(const HeapRange& other) const
     {
         return m_begin == other.m_begin && m_end == other.m_end;
     }
 
+    constexpr bool operator!=(const HeapRange& other) const
+    {
+        return !operator==(other);
+    }
+
+    template<uint16_t begin, uint16_t end>
+    static constexpr HeapRange fromConstant()
+    {
+        static_assert(begin < end || (begin == UINT16_MAX && end == UINT16_MAX), "begin < end or the both are UINT16_MAX is the invariant of this HeapRange.");
+        return HeapRange(ConstExpr, begin, end);
+    }
+
     static constexpr HeapRange top() { return fromConstant<0, UINT16_MAX>(); }
     static constexpr HeapRange none() { return fromConstant<UINT16_MAX, UINT16_MAX>(); } // Empty range.
 
@@ -127,5 +128,3 @@ private:
 };
 
 } }
-
-#endif
diff --git a/Source/JavaScriptCore/domjit/DOMJITSignature.h b/Source/JavaScriptCore/domjit/DOMJITSignature.h
new file mode 100644 (file)
index 0000000..6534278
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 "ClassInfo.h"
+#include "DOMJITEffect.h"
+#include "SpeculatedType.h"
+
+namespace JSC { namespace DOMJIT {
+
+// FIXME: Currently, we only support functions which arguments are up to 2.
+// Eventually, we should extend this. But possibly, 2 or 3 can cover typical use cases.
+// https://bugs.webkit.org/show_bug.cgi?id=164346
+#define JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS 2
+#define JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS (1 + JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS)
+
+class Patchpoint;
+
+typedef Ref<Patchpoint> CheckDOMGeneratorFunction(void);
+
+class Signature {
+public:
+    template<typename... Arguments>
+    constexpr Signature(uintptr_t unsafeFunction, CheckDOMGeneratorFunction* checkDOMGeneratorFunction, const ClassInfo* classInfo, Effect effect, SpeculatedType result, Arguments... arguments)
+        : unsafeFunction(unsafeFunction)
+        , checkDOMGeneratorFunction(checkDOMGeneratorFunction)
+        , classInfo(classInfo)
+        , effect(effect)
+        , result(result)
+        , arguments {static_cast<SpeculatedType>(arguments)...}
+        , argumentCount(sizeof...(Arguments))
+    {
+    }
+
+    Ref<Patchpoint> checkDOM() const
+    {
+        return checkDOMGeneratorFunction();
+    }
+
+    uintptr_t unsafeFunction;
+    CheckDOMGeneratorFunction* checkDOMGeneratorFunction;
+    const ClassInfo* const classInfo;
+    const Effect effect;
+    const SpeculatedType result;
+    const SpeculatedType arguments[JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS];
+    const unsigned argumentCount;
+};
+
+} }
index 54f4e72..3ba15e6 100644 (file)
@@ -273,6 +273,7 @@ inline CapabilityLevel canCompile(Node* node)
     case DefineAccessorProperty:
     case ToLowerCase:
     case CheckDOM:
+    case CallDOM:
     case CallDOMGetter:
         // These are OK.
         break;
index ad16157..79d97bb 100644 (file)
@@ -1060,6 +1060,9 @@ private:
         case CheckDOM:
             compileCheckDOM();
             break;
+        case CallDOM:
+            compileCallDOM();
+            break;
         case CallDOMGetter:
             compileCallDOMGetter();
             break;
@@ -9100,6 +9103,57 @@ private:
         patchpoint->effects = Effects::forCheck();
     }
 
+    void compileCallDOM()
+    {
+        const DOMJIT::Signature* signature = m_node->signature();
+
+        // FIXME: We should have a way to call functions with the vector of registers.
+        // https://bugs.webkit.org/show_bug.cgi?id=163099
+        Vector<LValue, JSC_DOMJIT_SIGNATURE_MAX_ARGUMENTS_INCLUDING_THIS> operands;
+
+        unsigned index = 0;
+        DFG_NODE_DO_TO_CHILDREN(m_graph, m_node, [&](Node*, Edge edge) {
+            if (!index)
+                operands.append(lowCell(edge));
+            else {
+                switch (signature->arguments[index - 1]) {
+                case SpecString:
+                    operands.append(lowString(edge));
+                    break;
+                case SpecInt32Only:
+                    operands.append(lowInt32(edge));
+                    break;
+                case SpecBoolean:
+                    operands.append(lowBoolean(edge));
+                    break;
+                default:
+                    RELEASE_ASSERT_NOT_REACHED();
+                    break;
+                }
+            }
+            ++index;
+        });
+
+        unsigned argumentCountIncludingThis = signature->argumentCount + 1;
+        LValue result;
+        switch (argumentCountIncludingThis) {
+        case 1:
+            result = vmCall(Int64, m_out.operation(reinterpret_cast<J_JITOperation_EP>(signature->unsafeFunction)), m_callFrame, operands[0]);
+            break;
+        case 2:
+            result = vmCall(Int64, m_out.operation(reinterpret_cast<J_JITOperation_EPP>(signature->unsafeFunction)), m_callFrame, operands[0], operands[1]);
+            break;
+        case 3:
+            result = vmCall(Int64, m_out.operation(reinterpret_cast<J_JITOperation_EPPP>(signature->unsafeFunction)), m_callFrame, operands[0], operands[1], operands[2]);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+
+        setJSValue(result);
+    }
+
     void compileCallDOMGetter()
     {
         DOMJIT::CallDOMGetterPatchpoint* domJIT = m_node->callDOMGetterData()->patchpoint;
index 8f6c697..20b71f4 100644 (file)
@@ -158,6 +158,7 @@ typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJP)(ExecState*, EncodedJS
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EGP)(ExecState*, JSGlobalObject*, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EP)(ExecState*, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EPP)(ExecState*, void*, void*);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EPPP)(ExecState*, void*, void*, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EPS)(ExecState*, void*, size_t);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EPc)(ExecState*, Instruction*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJscC)(ExecState*, JSScope*, JSCell*);
index bf0a7f9..40c12ce 100644 (file)
@@ -90,10 +90,10 @@ void JITThunks::finalize(Handle<Unknown> handle, void*)
 
 NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, const String& name)
 {
-    return hostFunctionStub(vm, function, constructor, nullptr, NoIntrinsic, name);
+    return hostFunctionStub(vm, function, constructor, nullptr, NoIntrinsic, nullptr, name);
 }
 
-NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
+NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, NativeFunction constructor, ThunkGenerator generator, Intrinsic intrinsic, const DOMJIT::Signature* signature, const String& name)
 {
     ASSERT(!isCompilationThread());    
     ASSERT(vm->canUseJIT());
@@ -110,14 +110,14 @@ NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, N
     
     RefPtr<JITCode> forConstruct = adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct(vm)), JITCode::HostCallThunk));
     
-    NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, constructor, intrinsic, name);
+    NativeExecutable* nativeExecutable = NativeExecutable::create(*vm, forCall, function, forConstruct, constructor, intrinsic, signature, name);
     weakAdd(*m_hostFunctionStubMap, std::make_tuple(function, constructor, name), Weak<NativeExecutable>(nativeExecutable, this));
     return nativeExecutable;
 }
 
 NativeExecutable* JITThunks::hostFunctionStub(VM* vm, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
 {
-    return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, intrinsic, name);
+    return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, intrinsic, nullptr, name);
 }
 
 void JITThunks::clearHostFunctionStubs()
index 3f8fe80..addcf23 100644 (file)
@@ -39,6 +39,9 @@
 #include <wtf/text/StringHash.h>
 
 namespace JSC {
+namespace DOMJIT {
+class Signature;
+}
 
 class VM;
 class NativeExecutable;
@@ -57,7 +60,7 @@ public:
     MacroAssemblerCodeRef ctiStub(VM*, ThunkGenerator);
 
     NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, const String& name);
-    NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, ThunkGenerator, Intrinsic, const String& name);
+    NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, ThunkGenerator, Intrinsic, const DOMJIT::Signature*, const String& name);
     NativeExecutable* hostFunctionStub(VM*, NativeFunction, ThunkGenerator, Intrinsic, const String& name);
 
     void clearHostFunctionStubs();
index 26f99d6..c4ce43e 100644 (file)
@@ -168,7 +168,7 @@ JSBoundFunction* JSBoundFunction::create(VM& vm, ExecState* exec, JSGlobalObject
     NativeExecutable* executable = vm.getHostFunction(
         slowCase ? boundFunctionCall : boundThisNoArgsFunctionCall,
         slowCase ? NoIntrinsic : BoundThisNoArgsFunctionCallIntrinsic,
-        canConstruct ? (slowCase ? boundFunctionConstruct : boundThisNoArgsFunctionConstruct) : callHostFunctionAsConstructor,
+        canConstruct ? (slowCase ? boundFunctionConstruct : boundThisNoArgsFunctionConstruct) : callHostFunctionAsConstructor, nullptr,
         name);
     Structure* structure = getBoundFunctionStructure(vm, exec, globalObject, targetFunction);
     RETURN_IF_EXCEPTION(scope, nullptr);
index c40f3e2..4efbf90 100644 (file)
@@ -56,17 +56,17 @@ template<typename T> void* allocateCell(Heap&, size_t);
 template<typename T> void* allocateCell(Heap&, GCDeferralContext*);
 template<typename T> void* allocateCell(Heap&, GCDeferralContext*, size_t);
 
-#define DECLARE_EXPORT_INFO                                             \
-    protected:                                                          \
-        static JS_EXPORTDATA const ::JSC::ClassInfo s_info;             \
-    public:                                                             \
-        static const ::JSC::ClassInfo* info() { return &s_info; }
-
-#define DECLARE_INFO                                                    \
-    protected:                                                          \
-        static const ::JSC::ClassInfo s_info;                           \
-    public:                                                             \
-        static const ::JSC::ClassInfo* info() { return &s_info; }
+#define DECLARE_EXPORT_INFO                                                  \
+    protected:                                                               \
+        static JS_EXPORTDATA const ::JSC::ClassInfo s_info;                  \
+    public:                                                                  \
+        static constexpr const ::JSC::ClassInfo* info() { return &s_info; }
+
+#define DECLARE_INFO                                                         \
+    protected:                                                               \
+        static const ::JSC::ClassInfo s_info;                                \
+    public:                                                                  \
+        static constexpr const ::JSC::ClassInfo* info() { return &s_info; }
 
 class JSCell : public HeapCell {
     friend class JSValue;
index 8584bc2..a31842b 100644 (file)
@@ -84,9 +84,9 @@ JSFunction* JSFunction::create(VM& vm, WebAssemblyExecutable* executable, JSScop
 }
 #endif
 
-JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
+JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor, const DOMJIT::Signature* signature)
 {
-    NativeExecutable* executable = vm.getHostFunction(nativeFunction, intrinsic, nativeConstructor, name);
+    NativeExecutable* executable = vm.getHostFunction(nativeFunction, intrinsic, nativeConstructor, signature, name);
     JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, globalObject, globalObject->functionStructure());
     // Can't do this during initialization because getHostFunction might do a GC allocation.
     function->finishCreation(vm, executable, length, name);
index 8df03a1..f11b12f 100644 (file)
@@ -46,6 +46,11 @@ class SpeculativeJIT;
 class JITCompiler;
 }
 
+namespace DOMJIT {
+class Signature;
+}
+
+
 JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
 
 JS_EXPORT_PRIVATE String getCalculatedDisplayName(VM&, JSObject*);
@@ -67,7 +72,7 @@ public:
         return sizeof(JSFunction);
     }
 
-    JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
+    JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor, const DOMJIT::Signature* = nullptr);
     
     static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
 
index 6dd849f..c1265b1 100644 (file)
@@ -66,7 +66,7 @@ static EncodedJSValue JSC_HOST_CALL runStdFunction(ExecState* state)
 
 JSNativeStdFunction* JSNativeStdFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeStdFunction&& nativeStdFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
 {
-    NativeExecutable* executable = vm.getHostFunction(runStdFunction, intrinsic, nativeConstructor, name);
+    NativeExecutable* executable = vm.getHostFunction(runStdFunction, intrinsic, nativeConstructor, nullptr, name);
     NativeStdFunctionCell* functionCell = NativeStdFunctionCell::create(vm, WTFMove(nativeStdFunction));
     Structure* structure = globalObject->nativeStdFunctionStructure();
     JSNativeStdFunction* function = new (NotNull, allocateCell<JSNativeStdFunction>(vm.heap)) JSNativeStdFunction(vm, globalObject, structure);
index f53db61..08ae792 100644 (file)
@@ -2549,6 +2549,17 @@ bool JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, con
     return putDirect(vm, propertyName, function, attributes);
 }
 
+bool JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, const DOMJIT::Signature* signature, unsigned attributes)
+{
+    StringImpl* name = propertyName.publicName();
+    if (!name)
+        name = vm.propertyNames->anonymous.impl();
+    ASSERT(name);
+
+    JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic, callHostFunctionAsConstructor, signature);
+    return putDirect(vm, propertyName, function, attributes);
+}
+
 JSFunction* JSObject::putDirectBuiltinFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
 {
     StringImpl* name = propertyName.publicName();
index 6220ec7..ebe485e 100644 (file)
@@ -47,6 +47,9 @@
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
+namespace DOMJIT {
+class Signature;
+}
 
 inline JSCell* getJSFunction(JSValue value)
 {
@@ -700,6 +703,7 @@ public:
 
     JS_EXPORT_PRIVATE bool putDirectNativeIntrinsicGetter(VM&, JSGlobalObject*, Identifier, NativeFunction, Intrinsic, unsigned attributes);
     JS_EXPORT_PRIVATE bool putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
+    JS_EXPORT_PRIVATE bool putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, const DOMJIT::Signature*, unsigned attributes);
     JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
     JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
     JS_EXPORT_PRIVATE void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
index e2d1795..d707686 100644 (file)
@@ -24,6 +24,7 @@
 #include "CallFrame.h"
 #include "CustomGetterSetter.h"
 #include "DOMJITGetterSetter.h"
+#include "DOMJITSignature.h"
 #include "Identifier.h"
 #include "IdentifierInlines.h"
 #include "Intrinsic.h"
@@ -75,12 +76,19 @@ struct HashTableValue {
     Intrinsic intrinsic() const { ASSERT(m_attributes & Function); return m_intrinsic; }
     BuiltinGenerator builtinGenerator() const { ASSERT(m_attributes & Builtin); return reinterpret_cast<BuiltinGenerator>(m_values.value1); }
     NativeFunction function() const { ASSERT(m_attributes & Function); return reinterpret_cast<NativeFunction>(m_values.value1); }
-    unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_values.value2); }
+    unsigned char functionLength() const
+    {
+        ASSERT(m_attributes & Function);
+        if (m_attributes & DOMJITFunction)
+            return signature()->argumentCount;
+        return static_cast<unsigned char>(m_values.value2);
+    }
 
     GetFunction propertyGetter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrLazyPropertyOrConstant)); return reinterpret_cast<GetFunction>(m_values.value1); }
     PutFunction propertyPutter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrLazyPropertyOrConstant)); return reinterpret_cast<PutFunction>(m_values.value2); }
 
     DOMJIT::GetterSetter* domJIT() const { ASSERT(m_attributes & DOMJITAttribute); return reinterpret_cast<DOMJITGetterSetterGenerator>(m_values.value1)(); }
+    const DOMJIT::Signature* signature() const { ASSERT(m_attributes & DOMJITFunction); return reinterpret_cast<const DOMJIT::Signature*>(m_values.value2); }
 
     NativeFunction accessorGetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_values.value1); }
     NativeFunction accessorSetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_values.value2); }
@@ -313,6 +321,12 @@ inline void reifyStaticProperty(VM& vm, const PropertyName& propertyName, const
     }
 
     if (value.attributes() & Function) {
+        if (value.attributes() & DOMJITFunction) {
+            thisObj.putDirectNativeFunction(
+                vm, thisObj.globalObject(), propertyName, value.functionLength(),
+                value.function(), value.intrinsic(), value.signature(), attributesForStructure(value.attributes()));
+            return;
+        }
         thisObj.putDirectNativeFunction(
             vm, thisObj.globalObject(), propertyName, value.functionLength(),
             value.function(), value.intrinsic(), attributesForStructure(value.attributes()));
index 1c2bec5..b7dad2a 100644 (file)
@@ -40,10 +40,10 @@ namespace JSC {
 
 const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) };
 
-NativeExecutable* NativeExecutable::create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name)
+NativeExecutable* NativeExecutable::create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const DOMJIT::Signature* signature, const String& name)
 {
     NativeExecutable* executable;
-    executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor, intrinsic);
+    executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor, intrinsic, signature);
     executable->finishCreation(vm, callThunk, constructThunk, name);
     return executable;
 }
@@ -68,10 +68,11 @@ void NativeExecutable::finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, Pas
     m_name = name;
 }
 
-NativeExecutable::NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor, Intrinsic intrinsic)
+NativeExecutable::NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor, Intrinsic intrinsic, const DOMJIT::Signature* signature)
     : ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST, intrinsic)
     , m_function(function)
     , m_constructor(constructor)
+    , m_signature(signature)
 {
 }
 
index 5bf2e10..e4d3e04 100644 (file)
@@ -28,6 +28,9 @@
 #include "ExecutableBase.h"
 
 namespace JSC {
+namespace DOMJIT {
+class Signature;
+}
 
 class NativeExecutable final : public ExecutableBase {
     friend class JIT;
@@ -36,7 +39,7 @@ public:
     typedef ExecutableBase Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name);
+    static NativeExecutable* create(VM&, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic, const DOMJIT::Signature*, const String& name);
 
     static void destroy(JSCell*);
 
@@ -66,6 +69,14 @@ public:
     DECLARE_INFO;
 
     const String& name() const { return m_name; }
+    const DOMJIT::Signature* signature() const { return m_signature; }
+
+    const DOMJIT::Signature* signatureFor(CodeSpecializationKind kind) const
+    {
+        if (isCall(kind))
+            return signature();
+        return nullptr;
+    }
 
 protected:
     void finishCreation(VM&, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, const String& name);
@@ -73,10 +84,11 @@ protected:
 private:
     friend class ExecutableBase;
 
-    NativeExecutable(VM&, NativeFunction function, NativeFunction constructor, Intrinsic);
+    NativeExecutable(VM&, NativeFunction function, NativeFunction constructor, Intrinsic, const DOMJIT::Signature*);
 
     NativeFunction m_function;
     NativeFunction m_constructor;
+    const DOMJIT::Signature* m_signature;
 
     String m_name;
 };
index 9de151a..387e31b 100644 (file)
@@ -51,6 +51,7 @@ enum Attribute {
     ClassStructure    = 1 << 12, // property is a lazy class structure - only used by static hashtables
     PropertyCallback  = 1 << 13, // property that is a lazy property callback - only used by static hashtables
     DOMJITAttribute   = 1 << 14, // property is a DOM JIT attribute - only used by static hashtables
+    DOMJITFunction    = 1 << 15, // property is a DOM JIT function - only used by static hashtables
     BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables
     BuiltinOrFunctionOrLazyProperty = Builtin | Function | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables
     BuiltinOrFunctionOrAccessorOrLazyProperty = Builtin | Function | Accessor | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables
index e6bd8df..7a2f0f2 100644 (file)
@@ -516,17 +516,17 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
 
 NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name)
 {
-    return getHostFunction(function, NoIntrinsic, constructor, name);
+    return getHostFunction(function, NoIntrinsic, constructor, nullptr, name);
 }
 
-NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, NativeFunction constructor, const String& name)
+NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, NativeFunction constructor, const DOMJIT::Signature* signature, const String& name)
 {
 #if ENABLE(JIT)
     if (canUseJIT()) {
         return jitStubs->hostFunctionStub(
             this, function, constructor,
             intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0,
-            intrinsic, name);
+            intrinsic, signature, name);
     }
 #else // ENABLE(JIT)
     UNUSED_PARAM(intrinsic);
@@ -534,7 +534,7 @@ NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrins
     return NativeExecutable::create(*this,
         adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), JITCode::HostCallThunk)), function,
         adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), JITCode::HostCallThunk)), constructor,
-        NoIntrinsic, name);
+        NoIntrinsic, signature, name);
 }
 
 VM::ClientData::~ClientData()
index 4fd7ec4..15a08c2 100644 (file)
@@ -429,7 +429,7 @@ public:
     std::unique_ptr<FTL::Thunks> ftlThunks;
 #endif
     NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor, const String& name);
-    NativeExecutable* getHostFunction(NativeFunction, Intrinsic intrinsic, NativeFunction constructor, const String& name);
+    NativeExecutable* getHostFunction(NativeFunction, Intrinsic, NativeFunction constructor, const DOMJIT::Signature*, const String& name);
 
     static ptrdiff_t exceptionOffset()
     {
index 42e2f21..78aa1f7 100644 (file)
@@ -1537,7 +1537,6 @@ set(WebCore_SOURCES
 
     dom/default/PlatformMessagePortChannel.cpp
 
-    domjit/DOMJITAbstractHeapRepository.cpp
     domjit/DOMJITHelpers.cpp
     domjit/JSDocumentDOMJIT.cpp
     domjit/JSNodeDOMJIT.cpp
@@ -3511,6 +3510,15 @@ MAKE_HASH_TOOLS(${WEBCORE_DIR}/platform/ColorData)
 list(APPEND WebCore_DERIVED_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/ColorData.cpp)
 
 
+# Generate DOMJITAbstractHeapRepository.h
+add_custom_command(
+    OUTPUT ${DERIVED_SOURCES_WEBCORE_DIR}/DOMJITAbstractHeapRepository.h
+    MAIN_DEPENDENCY domjit/DOMJITAbstractHeapRepository.yaml
+    DEPENDS ${WEBCORE_DIR}/domjit/generate-abstract-heap.rb
+    COMMAND ${RUBY_EXECUTABLE} ${WEBCORE_DIR}/domjit/generate-abstract-heap.rb ${WEBCORE_DIR}/domjit/DOMJITAbstractHeapRepository.yaml ${DERIVED_SOURCES_WEBCORE_DIR}/DOMJITAbstractHeapRepository.h
+    VERBATIM)
+list(APPEND WebCore_DERIVED_SOURCES ${DERIVED_SOURCES_WEBCORE_DIR}/DOMJITAbstractHeapRepository.h)
+
 # Generate XMLViewerCSS.h
 add_custom_command(
     OUTPUT ${DERIVED_SOURCES_WEBCORE_DIR}/XMLViewerCSS.h ${DERIVED_SOURCES_WEBCORE_DIR}/XMLViewer.min.css
index 28c2f7a..42073b1 100644 (file)
@@ -1,3 +1,110 @@
+2016-11-02  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DOMJIT] Add DOMJIT::Signature
+        https://bugs.webkit.org/show_bug.cgi?id=162980
+
+        Reviewed by Saam Barati and Sam Weinig.
+
+        We introduce DOMJIT::Signature. This signature object is automatically generated by IDL code generator.
+        It holds (1) types, (2) pointer to the unsafe function (the function without checks), and (3) the effect
+        of the function. We use constexpr to initialize DOMJIT::Signature without invoking global constructors.
+        Thus the content is embedded into the binary as the constant values.
+
+        We also clean up the IDL code generator related to DOMJIT part. Instead of switching things inside IDL
+        code generator, we use C++ template to dispatch things at compile time. This template meta programming
+        is highly utilized in IDL these days.
+
+        To make DOMJIT::Signature constexpr, we also need to define DOMJIT abstract heap things in the build time.
+        To do so, we introduce a tiny Ruby script to calculate the range of abstract heaps. We can offer the abstract
+        heap tree as YAML format and the script will produce a C++ header holding the calculated abstract heap ranges
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * ForwardingHeaders/bytecode/SpeculatedType.h: Renamed from Source/WebCore/domjit/DOMJITAbstractHeapRepository.h.
+        * ForwardingHeaders/domjit/DOMJITSignature.h: Renamed from Source/WebCore/domjit/DOMJITAbstractHeapRepository.cpp.
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMGlobalObject.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        (GeneratePropertiesHashTable):
+        (GetUnsafeArgumentType):
+        (GetArgumentTypeFilter):
+        (GetResultTypeFilter):
+        (GenerateImplementation):
+        (UnsafeToNative):
+        (GenerateHashTableValueArray):
+        (ComputeFunctionSpecial):
+        * bindings/scripts/IDLAttributes.txt:
+        * bindings/scripts/test/JS/JSTestDOMJIT.cpp:
+        (WebCore::BindingCaller<JSTestDOMJIT>::castForOperation):
+        (WebCore::TestDOMJITAnyAttrDOMJIT::TestDOMJITAnyAttrDOMJIT):
+        (WebCore::TestDOMJITBooleanAttrDOMJIT::TestDOMJITBooleanAttrDOMJIT):
+        (WebCore::TestDOMJITByteAttrDOMJIT::TestDOMJITByteAttrDOMJIT):
+        (WebCore::TestDOMJITOctetAttrDOMJIT::TestDOMJITOctetAttrDOMJIT):
+        (WebCore::TestDOMJITShortAttrDOMJIT::TestDOMJITShortAttrDOMJIT):
+        (WebCore::TestDOMJITUnsignedShortAttrDOMJIT::TestDOMJITUnsignedShortAttrDOMJIT):
+        (WebCore::TestDOMJITLongAttrDOMJIT::TestDOMJITLongAttrDOMJIT):
+        (WebCore::TestDOMJITUnsignedLongAttrDOMJIT::TestDOMJITUnsignedLongAttrDOMJIT):
+        (WebCore::TestDOMJITLongLongAttrDOMJIT::TestDOMJITLongLongAttrDOMJIT):
+        (WebCore::TestDOMJITUnsignedLongLongAttrDOMJIT::TestDOMJITUnsignedLongLongAttrDOMJIT):
+        (WebCore::TestDOMJITFloatAttrDOMJIT::TestDOMJITFloatAttrDOMJIT):
+        (WebCore::TestDOMJITUnrestrictedFloatAttrDOMJIT::TestDOMJITUnrestrictedFloatAttrDOMJIT):
+        (WebCore::TestDOMJITDoubleAttrDOMJIT::TestDOMJITDoubleAttrDOMJIT):
+        (WebCore::TestDOMJITUnrestrictedDoubleAttrDOMJIT::TestDOMJITUnrestrictedDoubleAttrDOMJIT):
+        (WebCore::TestDOMJITDomStringAttrDOMJIT::TestDOMJITDomStringAttrDOMJIT):
+        (WebCore::TestDOMJITByteStringAttrDOMJIT::TestDOMJITByteStringAttrDOMJIT):
+        (WebCore::TestDOMJITUsvStringAttrDOMJIT::TestDOMJITUsvStringAttrDOMJIT):
+        (WebCore::TestDOMJITNodeAttrDOMJIT::TestDOMJITNodeAttrDOMJIT):
+        (WebCore::TestDOMJITBooleanNullableAttrDOMJIT::TestDOMJITBooleanNullableAttrDOMJIT):
+        (WebCore::TestDOMJITByteNullableAttrDOMJIT::TestDOMJITByteNullableAttrDOMJIT):
+        (WebCore::TestDOMJITOctetNullableAttrDOMJIT::TestDOMJITOctetNullableAttrDOMJIT):
+        (WebCore::TestDOMJITShortNullableAttrDOMJIT::TestDOMJITShortNullableAttrDOMJIT):
+        (WebCore::TestDOMJITUnsignedShortNullableAttrDOMJIT::TestDOMJITUnsignedShortNullableAttrDOMJIT):
+        (WebCore::TestDOMJITLongNullableAttrDOMJIT::TestDOMJITLongNullableAttrDOMJIT):
+        (WebCore::TestDOMJITUnsignedLongNullableAttrDOMJIT::TestDOMJITUnsignedLongNullableAttrDOMJIT):
+        (WebCore::TestDOMJITLongLongNullableAttrDOMJIT::TestDOMJITLongLongNullableAttrDOMJIT):
+        (WebCore::TestDOMJITUnsignedLongLongNullableAttrDOMJIT::TestDOMJITUnsignedLongLongNullableAttrDOMJIT):
+        (WebCore::TestDOMJITFloatNullableAttrDOMJIT::TestDOMJITFloatNullableAttrDOMJIT):
+        (WebCore::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT):
+        (WebCore::TestDOMJITDoubleNullableAttrDOMJIT::TestDOMJITDoubleNullableAttrDOMJIT):
+        (WebCore::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT):
+        (WebCore::TestDOMJITDomStringNullableAttrDOMJIT::TestDOMJITDomStringNullableAttrDOMJIT):
+        (WebCore::TestDOMJITByteStringNullableAttrDOMJIT::TestDOMJITByteStringNullableAttrDOMJIT):
+        (WebCore::TestDOMJITUsvStringNullableAttrDOMJIT::TestDOMJITUsvStringNullableAttrDOMJIT):
+        (WebCore::TestDOMJITNodeNullableAttrDOMJIT::TestDOMJITNodeNullableAttrDOMJIT):
+        (WebCore::jsTestDOMJITPrototypeFunctionGetAttribute):
+        (WebCore::jsTestDOMJITPrototypeFunctionGetAttributeCaller):
+        (WebCore::unsafeJsTestDOMJITPrototypeFunctionGetAttribute):
+        (WebCore::jsTestDOMJITPrototypeFunctionItem):
+        (WebCore::jsTestDOMJITPrototypeFunctionItemCaller):
+        (WebCore::unsafeJsTestDOMJITPrototypeFunctionItem):
+        (WebCore::jsTestDOMJITPrototypeFunctionHasAttribute):
+        (WebCore::jsTestDOMJITPrototypeFunctionHasAttributeCaller):
+        (WebCore::unsafeJsTestDOMJITPrototypeFunctionHasAttribute):
+        (WebCore::jsTestDOMJITPrototypeFunctionGetElementById):
+        (WebCore::jsTestDOMJITPrototypeFunctionGetElementByIdCaller):
+        (WebCore::unsafeJsTestDOMJITPrototypeFunctionGetElementById):
+        (WebCore::jsTestDOMJITPrototypeFunctionGetElementsByName):
+        (WebCore::jsTestDOMJITPrototypeFunctionGetElementsByNameCaller):
+        (WebCore::unsafeJsTestDOMJITPrototypeFunctionGetElementsByName):
+        * bindings/scripts/test/TestDOMJIT.idl:
+        * dom/Element.idl:
+        * domjit/DOMJITAbstractHeapRepository.yaml: Added.
+        * domjit/DOMJITIDLConvert.h: Added.
+        (WebCore::DOMJIT::DirectConverter<IDLDOMString>::directConvert<StringConversionConfiguration::Normal>):
+        * domjit/DOMJITIDLType.h: Added.
+        * domjit/DOMJITIDLTypeFilter.h: Added.
+        * domjit/JSDocumentDOMJIT.cpp:
+        (WebCore::DocumentDocumentElementDOMJIT::callDOMGetter):
+        * domjit/JSNodeDOMJIT.cpp:
+        (WebCore::NodeFirstChildDOMJIT::callDOMGetter):
+        (WebCore::NodeLastChildDOMJIT::callDOMGetter):
+        (WebCore::NodeNextSiblingDOMJIT::callDOMGetter):
+        (WebCore::NodePreviousSiblingDOMJIT::callDOMGetter):
+        (WebCore::NodeParentNodeDOMJIT::callDOMGetter):
+        (WebCore::NodeOwnerDocumentDOMJIT::callDOMGetter):
+        * domjit/generate-abstract-heap.rb: Added.
+
 2016-11-02  Simon Fraser  <simon.fraser@apple.com>
 
         Followup after r208314.
index 565e2d9..cfc2276 100644 (file)
@@ -747,6 +747,7 @@ JS_BINDING_IDLS = \
 
 PYTHON = python
 PERL = perl
+RUBY = ruby
 
 ifeq ($(OS),Windows_NT)
     DELETE = cmd //C del
@@ -853,6 +854,7 @@ all : \
     CSSValueKeywords.cpp \
     CSSValueKeywords.h \
     ColorData.cpp \
+    DOMJITAbstractHeapRepository.h \
     EventInterfaces.h \
     EventTargetInterfaces.h \
     ExceptionCodeDescription.cpp \
@@ -942,6 +944,15 @@ SelectorPseudoElementTypeMap.cpp : $(WebCore)/css/makeSelectorPseudoElementsMap.
 
 # --------
 
+# DOMJIT Abstract Heap
+
+all : DOMJITAbstractHeapRepository.h
+
+DOMJITAbstractHeapRepository.h : $(WebCore)/domjit/generate-abstract-heap.rb $(WebCore)/domjit/DOMJITAbstractHeapRepository.yaml
+       $(RUBY) "$(WebCore)/domjit/generate-abstract-heap.rb" $(WebCore)/domjit/DOMJITAbstractHeapRepository.yaml ./DOMJITAbstractHeapRepository.h
+
+# --------
+
 # XMLViewer CSS
 
 all : XMLViewerCSS.h
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#pragma once
-
-#include <domjit/DOMJITHeapRange.h>
-#include <wtf/NeverDestroyed.h>
-#include <wtf/Noncopyable.h>
-
-#if ENABLE(JIT)
-
-namespace WebCore { namespace DOMJIT {
-
-// Describe your abstract heap hierarchy here.
-// V(AbstractHeapName, Parent)
-#define DOMJIT_ABSTRACT_HEAP_LIST(V) \
-    V(Node, DOM) \
-    V(Node_firstChild, Node) \
-    V(Node_lastChild, Node) \
-    V(Node_parentNode, Node) \
-    V(Node_nextSibling, Node) \
-    V(Node_previousSibling, Node) \
-    V(Node_ownerDocument, Node) \
-    V(Document, DOM) \
-    V(Document_documentElement, Document) \
-
-
-class AbstractHeapRepository {
-    WTF_MAKE_NONCOPYABLE(AbstractHeapRepository);
-public:
-    static const AbstractHeapRepository& shared();
-
-    JSC::DOMJIT::HeapRange DOM;
-
-#define DOMJIT_DEFINE_MEMBER(name, parent) JSC::DOMJIT::HeapRange name;
-    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_DEFINE_MEMBER)
-#undef DOMJIT_DEFINE_MEMBER
-
-    AbstractHeapRepository();
-};
-
-} }
-
+#ifndef WebCore_FWD_SpeculatedType_h
+#define WebCore_FWD_SpeculatedType_h
+#include <JavaScriptCore/SpeculatedType.h>
 #endif
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "config.h"
-#include "DOMJITAbstractHeapRepository.h"
-
-#include <domjit/DOMJITAbstractHeap.h>
-#include <wtf/DataLog.h>
-#include <wtf/NeverDestroyed.h>
-
-#if ENABLE(JIT)
-
-namespace WebCore { namespace DOMJIT {
-
-static const bool verbose = false;
-
-AbstractHeapRepository::AbstractHeapRepository()
-{
-    JSC::DOMJIT::AbstractHeap DOMHeap("DOM");
-#define DOMJIT_DEFINE_HEAP(name, parent) JSC::DOMJIT::AbstractHeap name##Heap(#name);
-    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_DEFINE_HEAP)
-#undef DOMJIT_DEFINE_HEAP
-
-#define DOMJIT_INITIALIZE_HEAP(name, parent) name##Heap.setParent(&parent##Heap);
-    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_INITIALIZE_HEAP)
-#undef DOMJIT_INITIALIZE_HEAP
-
-    DOMHeap.compute(0);
-
-#define DOMJIT_INITIALIZE_MEMBER(name, parent) name = name##Heap.range();
-    DOMJIT_ABSTRACT_HEAP_LIST(DOMJIT_INITIALIZE_MEMBER)
-#undef DOMJIT_INITIALIZE_MEMBER
-
-    if (verbose) {
-        dataLog("DOMJIT Heap Repository:\n");
-        DOMHeap.deepDump(WTF::dataFile());
-    }
-}
-
-const AbstractHeapRepository& AbstractHeapRepository::shared()
-{
-    static NeverDestroyed<AbstractHeapRepository> repository;
-    return repository.get();
-}
-
-} }
-
+#ifndef WebCore_FWD_DOMJITSignature_h
+#define WebCore_FWD_DOMJITSignature_h
+#include <JavaScriptCore/DOMJITSignature.h>
 #endif
index 3e0937a..8780ef5 100644 (file)
                E3150EA71DA7219300194012 /* DOMJITHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = E3150EA51DA7218D00194012 /* DOMJITHelpers.h */; };
                E318039D1DC40099009932C2 /* JSDynamicDowncast.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A5872E1DC3F52600F607A6 /* JSDynamicDowncast.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3565B7B1DC2D6C900217DBD /* JSEventCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = E34EE49F1DC2D57500EAA9D3 /* JSEventCustom.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               E35CA14D1DBC3A3F00F83516 /* DOMJITAbstractHeapRepository.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E35CA14B1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.cpp */; };
-               E35CA14E1DBC3A4200F83516 /* DOMJITAbstractHeapRepository.h in Headers */ = {isa = PBXBuildFile; fileRef = E35CA14C1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.h */; };
+               E35802B61DC8435D00A9773C /* DOMJITIDLTypeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = E35802B51DC8435800A9773C /* DOMJITIDLTypeFilter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                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 */; };
                E398FC241DC32A20003C4684 /* DOMJITHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E398FC231DC32A1B003C4684 /* DOMJITHelpers.cpp */; };
+               E3A776671DC85D2800B690D8 /* DOMJITIDLConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A776651DC85D2200B690D8 /* DOMJITIDLConvert.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E3A776681DC85D2800B690D8 /* DOMJITIDLType.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A776661DC85D2200B690D8 /* DOMJITIDLType.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3B2F0EB1D7F4C9D00B0C9D1 /* LoadableClassicScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3B2F0E31D7F35EC00B0C9D1 /* LoadableClassicScript.cpp */; };
                E3B2F0EC1D7F4CA100B0C9D1 /* LoadableScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3B2F0E91D7F3D3C00B0C9D1 /* LoadableScript.cpp */; };
                E3B2F0ED1D7F4CA300B0C9D1 /* LoadableScript.h in Headers */ = {isa = PBXBuildFile; fileRef = E3B2F0E71D7F35EC00B0C9D1 /* LoadableScript.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E1FF8F6A180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmRegistry.cpp; sourceTree = "<group>"; };
                E1FF8F6B180DB5BE00132674 /* CryptoAlgorithmRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmRegistry.h; sourceTree = "<group>"; };
                E3150EA51DA7218D00194012 /* DOMJITHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITHelpers.h; sourceTree = "<group>"; };
+               E334825E1DC93AA0009C9544 /* DOMJITAbstractHeapRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAbstractHeapRepository.h; sourceTree = "<group>"; };
                E34EE49F1DC2D57500EAA9D3 /* JSEventCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSEventCustom.h; sourceTree = "<group>"; };
-               E35CA14B1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAbstractHeapRepository.cpp; sourceTree = "<group>"; };
-               E35CA14C1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAbstractHeapRepository.h; sourceTree = "<group>"; };
+               E35802B51DC8435800A9773C /* DOMJITIDLTypeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITIDLTypeFilter.h; sourceTree = "<group>"; };
                E38838941BAD145F00D62EE3 /* ScriptModuleLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptModuleLoader.cpp; sourceTree = "<group>"; };
                E38838951BAD145F00D62EE3 /* ScriptModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptModuleLoader.h; sourceTree = "<group>"; };
                E398FC231DC32A1B003C4684 /* DOMJITHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITHelpers.cpp; sourceTree = "<group>"; };
                E3A5872E1DC3F52600F607A6 /* JSDynamicDowncast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDynamicDowncast.h; sourceTree = "<group>"; };
+               E3A776651DC85D2200B690D8 /* DOMJITIDLConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITIDLConvert.h; sourceTree = "<group>"; };
+               E3A776661DC85D2200B690D8 /* DOMJITIDLType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITIDLType.h; sourceTree = "<group>"; };
                E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSNodeDOMJIT.cpp; sourceTree = "<group>"; };
                E3B2F0E31D7F35EC00B0C9D1 /* LoadableClassicScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadableClassicScript.cpp; sourceTree = "<group>"; };
                E3B2F0E41D7F35EC00B0C9D1 /* LoadableClassicScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableClassicScript.h; sourceTree = "<group>"; };
                                6565814709D13043000E61D7 /* CSSValueKeywords.gperf */,
                                6565814809D13043000E61D7 /* CSSValueKeywords.h */,
                                9B3A8871145632F9003AE8F5 /* DOMDOMSettableTokenList.h */,
+                               E334825E1DC93AA0009C9544 /* DOMJITAbstractHeapRepository.h */,
                                E1C6CFC21746D293007B87A1 /* DOMWindowConstructors.idl */,
                                970B72A5145008EB00F00A37 /* EventHeaders.h */,
                                970B7289144FFAC600F00A37 /* EventInterfaces.h */,
                E3AFA9631DA6E8AF002861BD /* domjit */ = {
                        isa = PBXGroup;
                        children = (
-                               E35CA14B1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.cpp */,
-                               E35CA14C1DBC3A3C00F83516 /* DOMJITAbstractHeapRepository.h */,
                                E3C99A081DC3D41700794AD3 /* DOMJITCheckDOM.h */,
                                E398FC231DC32A1B003C4684 /* DOMJITHelpers.cpp */,
                                E3150EA51DA7218D00194012 /* DOMJITHelpers.h */,
+                               E3A776651DC85D2200B690D8 /* DOMJITIDLConvert.h */,
+                               E3A776661DC85D2200B690D8 /* DOMJITIDLType.h */,
+                               E35802B51DC8435800A9773C /* DOMJITIDLTypeFilter.h */,
                                E3B7C0621DC3415A001FB0B8 /* JSDocumentDOMJIT.cpp */,
                                E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */,
                        );
                                460CBF361D4BCD0E0092E88E /* JSDOMWindowProperties.h in Headers */,
                                BCBFB53D0DCD29CF0019B3E5 /* JSDOMWindowShell.h in Headers */,
                                65E0E9441133C89F00B4CB10 /* JSDOMWrapper.h in Headers */,
+                               E3A776671DC85D2800B690D8 /* DOMJITIDLConvert.h in Headers */,
                                FD7868BA136B999200D403DF /* JSDynamicsCompressorNode.h in Headers */,
                                65DF31FA09D1CC60000BE325 /* JSElement.h in Headers */,
                                ADEC78F818EE5308001315C2 /* JSElementCustom.h in Headers */,
                                08525E631278C00100A84778 /* SVGAnimatedStaticPropertyTearOff.h in Headers */,
                                084DB59B128008CC002A6D64 /* SVGAnimatedString.h in Headers */,
                                08250939128BD4D800E2ED8E /* SVGAnimatedTransformList.h in Headers */,
+                               E3A776681DC85D2800B690D8 /* DOMJITIDLType.h in Headers */,
                                085A15931289A8DD002710E3 /* SVGAnimatedTransformListPropertyTearOff.h in Headers */,
                                439D334313A6911C00C20F4F /* SVGAnimatedType.h in Headers */,
                                439D334413A6911C00C20F4F /* SVGAnimatedTypeAnimator.h in Headers */,
                                97AABD2314FA09D5007457AE /* WebSocketExtensionDispatcher.h in Headers */,
                                4A5A2ADC161E7E00005889DD /* WebSocketExtensionParser.h in Headers */,
                                97AABD2414FA09D5007457AE /* WebSocketExtensionProcessor.h in Headers */,
+                               E35802B61DC8435D00A9773C /* DOMJITIDLTypeFilter.h in Headers */,
                                97AABD2514FA09D5007457AE /* WebSocketFrame.h in Headers */,
                                97AABD2714FA09D5007457AE /* WebSocketHandshake.h in Headers */,
                                31DEA4561B39F4D900F77178 /* WebSystemBackdropLayer.h in Headers */,
index c181f9a..5dc1ee4 100644 (file)
@@ -81,7 +81,7 @@ namespace WebCore {
     public:
         ~JSDOMGlobalObject();
 
-        static const JSC::ClassInfo* info() { return &s_info; }
+        static constexpr const JSC::ClassInfo* info() { return &s_info; }
 
         static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSValue prototype)
         {
index f0e4287..04df9b8 100644 (file)
@@ -1471,7 +1471,7 @@ sub GenerateHeader
         push(@headerContent, "protected:\n");
         push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
         push(@headerContent, "public:\n");
-        push(@headerContent, "    static const JSC::ClassInfo* info() { return &s_info; }\n\n");
+        push(@headerContent, "    static constexpr const JSC::ClassInfo* info() { return &s_info; }\n\n");
     } else {
         push(@headerContent, "\n");
         push(@headerContent, "    DECLARE_INFO;\n\n");
@@ -1925,7 +1925,11 @@ sub GeneratePropertiesHashTable
         # FIXME: Remove this once we can get rid of the quirk introduced in https://bugs.webkit.org/show_bug.cgi?id=163967.
         $functionLength = 3 if $interfaceName eq "Event" and $function->name eq "initEvent";
 
-        push(@$hashValue2, $functionLength);
+        if ($function->extendedAttributes->{DOMJIT}) {
+            push(@$hashValue2, "&DOMJITSignatureFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name));
+        } else {
+            push(@$hashValue2, $functionLength);
+        }
 
         push(@$hashSpecials, ComputeFunctionSpecial($interface, $function));
 
@@ -2541,39 +2545,28 @@ sub addUnscopableProperties
     push(@implContent, "    putDirectWithoutTransition(vm, vm.propertyNames->unscopablesSymbol, &unscopables, DontEnum | ReadOnly);\n");
 }
 
-sub GetResultTypeFilter
+sub GetUnsafeArgumentType
 {
-    my ($type) = @_;
+    my ($interface, $type) = @_;
 
-    my %TypeFilters = (
-        "any" => "SpecHeapTop",
-        "boolean" => "SpecBoolean",
-        "byte" => "SpecInt32Only",
-        "octet" => "SpecInt32Only",
-        "short" => "SpecInt32Only",
-        "unsigned short" => "SpecInt32Only",
-        "long" => "SpecInt32Only",
-        "unsigned long" => "SpecBytecodeNumber",
-        "long long" => "SpecBytecodeNumber",
-        "unsigned long long" => "SpecBytecodeNumber",
-        "float" => "SpecBytecodeNumber",
-        "unrestricted float" => "SpecBytecodeNumber",
-        "double" => "SpecBytecodeNumber",
-        "unrestricted double" => "SpecBytecodeNumber",
-        "DOMString" => "SpecString",
-        "ByteString" => "SpecString",
-        "USVString" => "SpecString",
-    );
+    my $IDLType = GetIDLType($interface, $type);
+    return "DOMJIT::IDLJSArgumentType<${IDLType}>";
+}
 
-    if (exists $TypeFilters{$type->name}) {
-        my $resultType = "JSC::$TypeFilters{$type->name}";
-        if ($type->isNullable) {
-            die "\"any\" type must not become nullable." if $type->name eq "any";
-            $resultType = "($resultType | JSC::SpecOther)";
-        }
-        return $resultType;
-    }
-    return "SpecHeapTop";
+sub GetArgumentTypeFilter
+{
+    my ($interface, $type) = @_;
+
+    my $IDLType = GetIDLType($interface, $type);
+    return "DOMJIT::IDLArgumentTypeFilter<${IDLType}>::value";
+}
+
+sub GetResultTypeFilter
+{
+    my ($interface, $type) = @_;
+
+    my $IDLType = GetIDLType($interface, $type);
+    return "DOMJIT::IDLResultTypeFilter<${IDLType}>::value";
 }
 
 sub GenerateImplementation
@@ -2644,6 +2637,17 @@ sub GenerateImplementation
             push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
             my $functionName = GetFunctionName($interface, $className, $function);
             push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
+            if ($function->extendedAttributes->{DOMJIT}) {
+                $implIncludes{"DOMJITIDLType.h"} = 1;
+                my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
+                my $functionSignature = "JSC::EncodedJSValue JSC_HOST_CALL ${unsafeFunctionName}(JSC::ExecState*, $className*";
+                foreach my $argument (@{$function->arguments}) {
+                    my $type = $argument->type;
+                    my $argumentType = GetUnsafeArgumentType($interface, $type);
+                    $functionSignature .= ", ${argumentType}";
+                }
+                push(@implContent, $functionSignature . ");\n");
+            }
             push(@implContent, "#endif\n") if $conditionalString;
         }
 
@@ -2680,6 +2684,37 @@ sub GenerateImplementation
         push(@implContent, "\n");
     }
 
+    if ($numFunctions > 0) {
+        foreach my $function (@functions) {
+            next unless $function->extendedAttributes->{DOMJIT};
+            $implIncludes{"DOMJITIDLTypeFilter.h"} = 1;
+            $implIncludes{"DOMJITCheckDOM.h"} = 1;
+            $implIncludes{"DOMJITAbstractHeapRepository.h"} = 1;
+
+            my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
+            die "Overloads is not supported in DOMJIT" if $isOverloaded;
+            die "Currently ReadDOM value is only allowed" unless $codeGenerator->ExtendedAttributeContains($function->extendedAttributes->{DOMJIT}, "ReadDOM");
+
+            my $interfaceName = $interface->type->name;
+            my $functionName = GetFunctionName($interface, $className, $function);
+            my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
+            my $domJITSignatureName = "DOMJITSignatureFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name);
+            my $classInfo = "JS" . $interface->type->name . "::info()";
+            my $resultType = GetResultTypeFilter($interface, $function->type);
+            my $domJITSignature = "static const JSC::DOMJIT::Signature ${domJITSignatureName}((uintptr_t)${unsafeFunctionName}, DOMJIT::checkDOM<$interfaceName>, $classInfo, JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), ${resultType}";
+            foreach my $argument (@{$function->arguments}) {
+                my $type = $argument->type;
+                my $argumentType = GetArgumentTypeFilter($interface, $type);
+                $domJITSignature .= ", ${argumentType}";
+            }
+            my $conditionalString = $codeGenerator->GenerateConditionalString($function);
+            push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+            push(@implContent, $domJITSignature . ");\n");
+            push(@implContent, "#endif\n") if $conditionalString;
+            push(@implContent, "\n");
+        }
+    }
+
     GeneratePrototypeDeclaration(\@implContent, $className, $interface) if !HeaderNeedsPrototypeDeclaration($interface);
 
     GenerateConstructorDeclaration(\@implContent, $className, $interface) if NeedsConstructorProperty($interface);
@@ -2776,7 +2811,11 @@ sub GenerateImplementation
             push(@hashValue1, $functionName);
 
             my $functionLength = GetFunctionLength($function);
-            push(@hashValue2, $functionLength);
+            if ($function->extendedAttributes->{DOMJIT}) {
+                push(@hashValue2, "DOMJITFunctionFor" . $interface->type->name . $codeGenerator->WK_ucfirst($function->name));
+            } else {
+                push(@hashValue2, $functionLength);
+            }
 
             push(@hashSpecials, ComputeFunctionSpecial($interface, $function));
 
@@ -3338,13 +3377,14 @@ sub GenerateImplementation
 
             if ($attribute->extendedAttributes->{"DOMJIT"}) {
                 $implIncludes{"<wtf/NeverDestroyed.h>"} = 1;
+                $implIncludes{"DOMJITIDLTypeFilter.h"} = 1;
                 my $interfaceName = $interface->type->name;
                 my $attributeName = $attribute->name;
                 my $generatorName = $interfaceName . $codeGenerator->WK_ucfirst($attribute->name);
                 my $domJITClassName = $generatorName . "DOMJIT";
                 my $getter = GetAttributeGetterName($interface, $generatorName, $attribute);
                 my $setter = IsReadonly($attribute) ? "nullptr" : GetAttributeSetterName($interface, $generatorName, $attribute);
-                my $resultType = GetResultTypeFilter($attribute->type);
+                my $resultType = GetResultTypeFilter($interface, $attribute->type);
                 push(@implContent, "$domJITClassName::$domJITClassName()\n");
                 push(@implContent, "    : JSC::DOMJIT::GetterSetter($getter, $setter, ${className}::info(), $resultType)\n");
                 push(@implContent, "{\n");
@@ -3838,6 +3878,78 @@ END
             }
 
             push(@implContent, "}\n\n");
+
+            if ($function->extendedAttributes->{DOMJIT}) {
+                $implIncludes{"<interpreter/FrameTracers.h>"} = 1;
+                my $unsafeFunctionName = "unsafe" . $codeGenerator->WK_ucfirst($functionName);
+                push(@implContent, "JSC::EncodedJSValue JSC_HOST_CALL ${unsafeFunctionName}(JSC::ExecState* state, $className* castedThis");
+                foreach my $argument (@{$function->arguments}) {
+                    my $type = $argument->type;
+                    my $argumentType = GetUnsafeArgumentType($interface, $type);
+                    my $name = $argument->name;
+                    my $encodedName = "encoded" . $codeGenerator->WK_ucfirst($name);
+                    push(@implContent, ", ${argumentType} ${encodedName}");
+                }
+                push(@implContent, ")\n");
+                push(@implContent, "{\n");
+                push(@implContent, "    UNUSED_PARAM(state);\n");
+                push(@implContent, "    VM& vm = state->vm();\n");
+                push(@implContent, "    JSC::NativeCallFrameTracer tracer(&vm, state);\n");
+                push(@implContent, "    auto throwScope = DECLARE_THROW_SCOPE(vm);\n");
+                push(@implContent, "    UNUSED_PARAM(throwScope);\n");
+                push(@implContent, "    auto& impl = castedThis->wrapped();\n");
+                my @arguments;
+                my $implFunctionName;
+                my $implementedBy = $function->extendedAttributes->{ImplementedBy};
+
+                if ($implementedBy) {
+                    AddToImplIncludes("${implementedBy}.h", $function->extendedAttributes->{Conditional});
+                    unshift(@arguments, "impl") if !$function->isStatic;
+                    $implFunctionName = "WebCore::${implementedBy}::${functionImplementationName}";
+                } elsif ($function->isStatic) {
+                    $implFunctionName = "${interfaceName}::${functionImplementationName}";
+                } elsif ($svgPropertyOrListPropertyType and !$svgListPropertyType) {
+                    $implFunctionName = "podImpl.${functionImplementationName}";
+                } else {
+                    $implFunctionName = "impl.${functionImplementationName}";
+                }
+
+                foreach my $argument (@{$function->arguments}) {
+                    my $value = "";
+                    my $type = $argument->type;
+                    my $name = $argument->name;
+                    my $encodedName = "encoded" . $codeGenerator->WK_ucfirst($name);
+                    my $nativeType = GetNativeType($interface, $argument->type);
+                    my $isTearOff = $codeGenerator->IsSVGTypeNeedingTearOff($type) && $interfaceName !~ /List$/;
+                    die "TearOff type is not allowed" if $isTearOff;
+                    my $shouldPassByReference = ShouldPassWrapperByReference($argument, $interface);
+
+                    if (!$shouldPassByReference && ($codeGenerator->IsWrapperType($type) || $codeGenerator->IsTypedArrayType($type))) {
+                        $implIncludes{"<runtime/Error.h>"} = 1;
+                        my ($nativeValue, $mayThrowException) = UnsafeToNative($interface, $argument, $encodedName, $function->extendedAttributes->{Conditional});
+                        push(@implContent, "    $nativeType $name = nullptr;\n");
+                        push(@implContent, "    $name = $nativeValue;\n");
+                        push(@implContent, "    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n") if $mayThrowException;
+                        $value = "WTFMove($name)";
+                    } else {
+                        my ($nativeValue, $mayThrowException) = UnsafeToNative($interface, $argument, $encodedName, $function->extendedAttributes->{Conditional});
+                        push(@implContent, "    auto $name = ${nativeValue};\n");
+                        $value = "WTFMove($name)";
+                        push(@implContent, "    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());\n") if $mayThrowException;
+                    }
+
+                    if ($shouldPassByReference) {
+                        $value = "*$name";
+                    }
+                    push(@arguments, $value);
+                }
+                my $functionString = "$implFunctionName(" . join(", ", @arguments) . ")";
+                $functionString = "propagateException(*state, throwScope, $functionString)" if NeedsExplicitPropagateExceptionCall($function);
+                push(@implContent, "    JSValue result = " . NativeToJSValueUsingPointers($function, 1, $interface, $functionString, "castedThis") . ";\n");
+                push(@implContent, "    return JSValue::encode(result);\n");
+                push(@implContent, "}\n\n");
+            }
+
             push(@implContent, "#endif\n\n") if $conditional;
 
             # Generate a function dispatching call to the rest of the overloads.
@@ -5324,6 +5436,46 @@ sub JSValueToNative
     return ("convert<$IDLType>(" . join(", ", @conversionArguments) . ")", 1);
 }
 
+sub UnsafeToNative
+{
+    my ($interface, $context, $value, $conditional, $statePointer, $stateReference, $thisObjectReference) = @_;
+
+    assert("Invalid context type") if !IsValidContextForJSValueToNative($context);
+
+    my $type = $context->type;
+
+    # FIXME: Remove these 3 variables when all JSValueToNative use references.
+    $statePointer = "state" unless $statePointer;
+    $stateReference = "*state" unless $stateReference;
+    $thisObjectReference = "*castedThis" unless $thisObjectReference;
+
+    AddToImplIncludesForIDLType($type, $conditional);
+
+    # FIXME: Support more types.
+
+    if ($type->name eq "DOMString") {
+        return ("AtomicString($value->toExistingAtomicString($statePointer))", 1) if $context->extendedAttributes->{RequiresExistingAtomicString};
+        return ("$value->toAtomicString($statePointer)", 1) if $context->extendedAttributes->{AtomicString};
+    }
+
+    AddToImplIncludes("DOMJITIDLConvert.h");
+
+    my $IDLType = GetIDLType($interface, $type);
+
+    my @conversionArguments = ();
+    push(@conversionArguments, "$stateReference");
+    push(@conversionArguments, "$value");
+
+    my @conversionStaticArguments = ();
+    push(@conversionStaticArguments, GetIntegerConversionConfiguration($context)) if $codeGenerator->IsIntegerType($type);
+    push(@conversionStaticArguments, GetStringConversionConfiguration($context)) if $codeGenerator->IsStringType($type);
+
+    if (scalar(@conversionStaticArguments) > 0) {
+        return ("DOMJIT::DirectConverter<$IDLType>::directConvert<" . join(", ", @conversionStaticArguments) . ">(" . join(", ", @conversionArguments) . ")", 1);
+    }
+    return ("DOMJIT::DirectConverter<$IDLType>::directConvert(" . join(", ", @conversionArguments) . ")", 1);
+}
+
 sub NativeToJSValueDOMConvertNeedsState
 {
     my ($type) = @_;
@@ -5508,7 +5660,10 @@ sub GenerateHashTableValueArray
             push(@implContent, "#if ${conditionalString}\n");
         }
 
-        if ("@$specials[$i]" =~ m/Function/) {
+        if ("@$specials[$i]" =~ m/DOMJITFunction/) {
+            $firstTargetType = "static_cast<NativeFunction>";
+            $secondTargetType = "static_cast<const JSC::DOMJIT::Signature*>";
+        } elsif ("@$specials[$i]" =~ m/Function/) {
             $firstTargetType = "static_cast<NativeFunction>";
         } elsif ("@$specials[$i]" =~ m/Builtin/) {
             $firstTargetType = "static_cast<BuiltinGenerator>";
@@ -6106,6 +6261,9 @@ sub ComputeFunctionSpecial
     else {
         push(@specials, "JSC::Function");
     }
+    if ($function->extendedAttributes->{"DOMJIT"}) {
+        push(@specials, "DOMJITFunction") if $function->extendedAttributes->{DOMJIT};
+    }
     return (@specials > 0) ? join(" | ", @specials) : "0";
 }
 
index a2e7541..1398d94 100644 (file)
@@ -52,7 +52,7 @@ CustomPutFunction
 CustomSetPrototype
 CustomSetter
 CustomToJSObject
-DOMJIT
+DOMJIT=|ReadDOM
 DoNotCheckConstants
 DoNotCheckSecurity
 DoNotCheckSecurityOnGetter
index 1787e35..054070a 100644 (file)
 #include "config.h"
 #include "JSTestDOMJIT.h"
 
+#include "DOMJITAbstractHeapRepository.h"
+#include "DOMJITCheckDOM.h"
+#include "DOMJITIDLConvert.h"
+#include "DOMJITIDLType.h"
+#include "DOMJITIDLTypeFilter.h"
+#include "ExceptionCode.h"
 #include "JSByteString.h"
 #include "JSDOMBinding.h"
 #include "JSDOMConstructor.h"
 #include "JSDOMConvert.h"
+#include "JSElement.h"
+#include "JSNodeList.h"
+#include <interpreter/FrameTracers.h>
+#include <runtime/Error.h>
 #include <wtf/GetPtr.h>
 #include <wtf/NeverDestroyed.h>
 
@@ -32,6 +42,19 @@ using namespace JSC;
 
 namespace WebCore {
 
+// Functions
+
+JSC::EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionGetAttribute(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionGetAttribute(JSC::ExecState*, JSTestDOMJIT*, DOMJIT::IDLJSArgumentType<IDLDOMString>);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionItem(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionItem(JSC::ExecState*, JSTestDOMJIT*, DOMJIT::IDLJSArgumentType<IDLUnsignedShort>, DOMJIT::IDLJSArgumentType<IDLUnsignedShort>);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionHasAttribute(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionHasAttribute(JSC::ExecState*, JSTestDOMJIT*);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionGetElementById(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionGetElementById(JSC::ExecState*, JSTestDOMJIT*, DOMJIT::IDLJSArgumentType<IDLDOMString>);
+JSC::EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionGetElementsByName(JSC::ExecState*);
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionGetElementsByName(JSC::ExecState*, JSTestDOMJIT*, DOMJIT::IDLJSArgumentType<IDLDOMString>);
+
 // Attributes
 
 JSC::EncodedJSValue jsTestDOMJITAnyAttr(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
@@ -72,6 +95,16 @@ JSC::EncodedJSValue jsTestDOMJITNodeNullableAttr(JSC::ExecState*, JSC::EncodedJS
 JSC::EncodedJSValue jsTestDOMJITConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
 bool setJSTestDOMJITConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
 
+static const JSC::DOMJIT::Signature DOMJITSignatureForTestDOMJITGetAttribute((uintptr_t)unsafeJsTestDOMJITPrototypeFunctionGetAttribute, DOMJIT::checkDOM<TestDOMJIT>, JSTestDOMJIT::info(), JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLDOMString>>::value, DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value);
+
+static const JSC::DOMJIT::Signature DOMJITSignatureForTestDOMJITItem((uintptr_t)unsafeJsTestDOMJITPrototypeFunctionItem, DOMJIT::checkDOM<TestDOMJIT>, JSTestDOMJIT::info(), JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), DOMJIT::IDLResultTypeFilter<IDLDOMString>::value, DOMJIT::IDLArgumentTypeFilter<IDLUnsignedShort>::value, DOMJIT::IDLArgumentTypeFilter<IDLUnsignedShort>::value);
+
+static const JSC::DOMJIT::Signature DOMJITSignatureForTestDOMJITHasAttribute((uintptr_t)unsafeJsTestDOMJITPrototypeFunctionHasAttribute, DOMJIT::checkDOM<TestDOMJIT>, JSTestDOMJIT::info(), JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), DOMJIT::IDLResultTypeFilter<IDLBoolean>::value);
+
+static const JSC::DOMJIT::Signature DOMJITSignatureForTestDOMJITGetElementById((uintptr_t)unsafeJsTestDOMJITPrototypeFunctionGetElementById, DOMJIT::checkDOM<TestDOMJIT>, JSTestDOMJIT::info(), JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), DOMJIT::IDLResultTypeFilter<IDLInterface<Element>>::value, DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value);
+
+static const JSC::DOMJIT::Signature DOMJITSignatureForTestDOMJITGetElementsByName((uintptr_t)unsafeJsTestDOMJITPrototypeFunctionGetElementsByName, DOMJIT::checkDOM<TestDOMJIT>, JSTestDOMJIT::info(), JSC::DOMJIT::Effect::forRead(DOMJIT::AbstractHeapRepository::DOM), DOMJIT::IDLResultTypeFilter<IDLInterface<NodeList>>::value, DOMJIT::IDLArgumentTypeFilter<IDLDOMString>::value);
+
 class JSTestDOMJITPrototype : public JSC::JSNonFinalObject {
 public:
     using Base = JSC::JSNonFinalObject;
@@ -153,6 +186,11 @@ static const HashTableValue JSTestDOMJITPrototypeTableValues[] =
     { "byteStringNullableAttr", ReadOnly | CustomAccessor | DOMJITAttribute, NoIntrinsic, { (intptr_t)static_cast<DOMJITGetterSetterGenerator>(domJITGetterSetterForTestDOMJITByteStringNullableAttr), (intptr_t) (0) } },
     { "usvStringNullableAttr", ReadOnly | CustomAccessor | DOMJITAttribute, NoIntrinsic, { (intptr_t)static_cast<DOMJITGetterSetterGenerator>(domJITGetterSetterForTestDOMJITUsvStringNullableAttr), (intptr_t) (0) } },
     { "nodeNullableAttr", ReadOnly | CustomAccessor | DOMJITAttribute, NoIntrinsic, { (intptr_t)static_cast<DOMJITGetterSetterGenerator>(domJITGetterSetterForTestDOMJITNodeNullableAttr), (intptr_t) (0) } },
+    { "getAttribute", JSC::Function | DOMJITFunction, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestDOMJITPrototypeFunctionGetAttribute), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForTestDOMJITGetAttribute) } },
+    { "item", JSC::Function | DOMJITFunction, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestDOMJITPrototypeFunctionItem), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForTestDOMJITItem) } },
+    { "hasAttribute", JSC::Function | DOMJITFunction, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestDOMJITPrototypeFunctionHasAttribute), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForTestDOMJITHasAttribute) } },
+    { "getElementById", JSC::Function | DOMJITFunction, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestDOMJITPrototypeFunctionGetElementById), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForTestDOMJITGetElementById) } },
+    { "getElementsByName", JSC::Function | DOMJITFunction, NoIntrinsic, { (intptr_t)static_cast<NativeFunction>(jsTestDOMJITPrototypeFunctionGetElementsByName), (intptr_t) static_cast<const JSC::DOMJIT::Signature*>(&DOMJITSignatureForTestDOMJITGetElementsByName) } },
 };
 
 const ClassInfo JSTestDOMJITPrototype::s_info = { "TestDOMJITPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSTestDOMJITPrototype) };
@@ -185,6 +223,11 @@ template<> inline JSTestDOMJIT* BindingCaller<JSTestDOMJIT>::castForAttribute(Ex
     return jsDynamicDowncast<JSTestDOMJIT*>(JSValue::decode(thisValue));
 }
 
+template<> inline JSTestDOMJIT* BindingCaller<JSTestDOMJIT>::castForOperation(ExecState& state)
+{
+    return jsDynamicDowncast<JSTestDOMJIT*>(state.thisValue());
+}
+
 static inline JSValue jsTestDOMJITAnyAttrGetter(ExecState&, JSTestDOMJIT&, ThrowScope& throwScope);
 
 EncodedJSValue jsTestDOMJITAnyAttr(ExecState* state, EncodedJSValue thisValue, PropertyName)
@@ -202,7 +245,7 @@ static inline JSValue jsTestDOMJITAnyAttrGetter(ExecState& state, JSTestDOMJIT&
 }
 
 TestDOMJITAnyAttrDOMJIT::TestDOMJITAnyAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITAnyAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecHeapTop)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITAnyAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLAny>::value)
 {
 }
 
@@ -229,7 +272,7 @@ static inline JSValue jsTestDOMJITBooleanAttrGetter(ExecState& state, JSTestDOMJ
 }
 
 TestDOMJITBooleanAttrDOMJIT::TestDOMJITBooleanAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITBooleanAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBoolean)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITBooleanAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLBoolean>::value)
 {
 }
 
@@ -256,7 +299,7 @@ static inline JSValue jsTestDOMJITByteAttrGetter(ExecState& state, JSTestDOMJIT&
 }
 
 TestDOMJITByteAttrDOMJIT::TestDOMJITByteAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecInt32Only)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLByte>::value)
 {
 }
 
@@ -283,7 +326,7 @@ static inline JSValue jsTestDOMJITOctetAttrGetter(ExecState& state, JSTestDOMJIT
 }
 
 TestDOMJITOctetAttrDOMJIT::TestDOMJITOctetAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITOctetAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecInt32Only)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITOctetAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLOctet>::value)
 {
 }
 
@@ -310,7 +353,7 @@ static inline JSValue jsTestDOMJITShortAttrGetter(ExecState& state, JSTestDOMJIT
 }
 
 TestDOMJITShortAttrDOMJIT::TestDOMJITShortAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITShortAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecInt32Only)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITShortAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLShort>::value)
 {
 }
 
@@ -337,7 +380,7 @@ static inline JSValue jsTestDOMJITUnsignedShortAttrGetter(ExecState& state, JSTe
 }
 
 TestDOMJITUnsignedShortAttrDOMJIT::TestDOMJITUnsignedShortAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedShortAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecInt32Only)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedShortAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLUnsignedShort>::value)
 {
 }
 
@@ -364,7 +407,7 @@ static inline JSValue jsTestDOMJITLongAttrGetter(ExecState& state, JSTestDOMJIT&
 }
 
 TestDOMJITLongAttrDOMJIT::TestDOMJITLongAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecInt32Only)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLLong>::value)
 {
 }
 
@@ -391,7 +434,7 @@ static inline JSValue jsTestDOMJITUnsignedLongAttrGetter(ExecState& state, JSTes
 }
 
 TestDOMJITUnsignedLongAttrDOMJIT::TestDOMJITUnsignedLongAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLUnsignedLong>::value)
 {
 }
 
@@ -418,7 +461,7 @@ static inline JSValue jsTestDOMJITLongLongAttrGetter(ExecState& state, JSTestDOM
 }
 
 TestDOMJITLongLongAttrDOMJIT::TestDOMJITLongLongAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongLongAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongLongAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLLongLong>::value)
 {
 }
 
@@ -445,7 +488,7 @@ static inline JSValue jsTestDOMJITUnsignedLongLongAttrGetter(ExecState& state, J
 }
 
 TestDOMJITUnsignedLongLongAttrDOMJIT::TestDOMJITUnsignedLongLongAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongLongAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongLongAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLUnsignedLongLong>::value)
 {
 }
 
@@ -472,7 +515,7 @@ static inline JSValue jsTestDOMJITFloatAttrGetter(ExecState& state, JSTestDOMJIT
 }
 
 TestDOMJITFloatAttrDOMJIT::TestDOMJITFloatAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITFloatAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITFloatAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLFloat>::value)
 {
 }
 
@@ -499,7 +542,7 @@ static inline JSValue jsTestDOMJITUnrestrictedFloatAttrGetter(ExecState& state,
 }
 
 TestDOMJITUnrestrictedFloatAttrDOMJIT::TestDOMJITUnrestrictedFloatAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedFloatAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedFloatAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLUnrestrictedFloat>::value)
 {
 }
 
@@ -526,7 +569,7 @@ static inline JSValue jsTestDOMJITDoubleAttrGetter(ExecState& state, JSTestDOMJI
 }
 
 TestDOMJITDoubleAttrDOMJIT::TestDOMJITDoubleAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDoubleAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDoubleAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLDouble>::value)
 {
 }
 
@@ -553,7 +596,7 @@ static inline JSValue jsTestDOMJITUnrestrictedDoubleAttrGetter(ExecState& state,
 }
 
 TestDOMJITUnrestrictedDoubleAttrDOMJIT::TestDOMJITUnrestrictedDoubleAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedDoubleAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecBytecodeNumber)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedDoubleAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLUnrestrictedDouble>::value)
 {
 }
 
@@ -580,7 +623,7 @@ static inline JSValue jsTestDOMJITDomStringAttrGetter(ExecState& state, JSTestDO
 }
 
 TestDOMJITDomStringAttrDOMJIT::TestDOMJITDomStringAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDomStringAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecString)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDomStringAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLDOMString>::value)
 {
 }
 
@@ -607,7 +650,7 @@ static inline JSValue jsTestDOMJITByteStringAttrGetter(ExecState& state, JSTestD
 }
 
 TestDOMJITByteStringAttrDOMJIT::TestDOMJITByteStringAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteStringAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecString)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteStringAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLByteString>::value)
 {
 }
 
@@ -634,7 +677,7 @@ static inline JSValue jsTestDOMJITUsvStringAttrGetter(ExecState& state, JSTestDO
 }
 
 TestDOMJITUsvStringAttrDOMJIT::TestDOMJITUsvStringAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUsvStringAttr, nullptr, JSTestDOMJIT::info(), JSC::SpecString)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUsvStringAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLUSVString>::value)
 {
 }
 
@@ -661,7 +704,7 @@ static inline JSValue jsTestDOMJITNodeAttrGetter(ExecState& state, JSTestDOMJIT&
 }
 
 TestDOMJITNodeAttrDOMJIT::TestDOMJITNodeAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITNodeAttr, nullptr, JSTestDOMJIT::info(), SpecHeapTop)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITNodeAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLInterface<Node>>::value)
 {
 }
 
@@ -688,7 +731,7 @@ static inline JSValue jsTestDOMJITBooleanNullableAttrGetter(ExecState& state, JS
 }
 
 TestDOMJITBooleanNullableAttrDOMJIT::TestDOMJITBooleanNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITBooleanNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBoolean | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITBooleanNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLBoolean>>::value)
 {
 }
 
@@ -715,7 +758,7 @@ static inline JSValue jsTestDOMJITByteNullableAttrGetter(ExecState& state, JSTes
 }
 
 TestDOMJITByteNullableAttrDOMJIT::TestDOMJITByteNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecInt32Only | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLByte>>::value)
 {
 }
 
@@ -742,7 +785,7 @@ static inline JSValue jsTestDOMJITOctetNullableAttrGetter(ExecState& state, JSTe
 }
 
 TestDOMJITOctetNullableAttrDOMJIT::TestDOMJITOctetNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITOctetNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecInt32Only | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITOctetNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLOctet>>::value)
 {
 }
 
@@ -769,7 +812,7 @@ static inline JSValue jsTestDOMJITShortNullableAttrGetter(ExecState& state, JSTe
 }
 
 TestDOMJITShortNullableAttrDOMJIT::TestDOMJITShortNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITShortNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecInt32Only | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITShortNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLShort>>::value)
 {
 }
 
@@ -796,7 +839,7 @@ static inline JSValue jsTestDOMJITUnsignedShortNullableAttrGetter(ExecState& sta
 }
 
 TestDOMJITUnsignedShortNullableAttrDOMJIT::TestDOMJITUnsignedShortNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedShortNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecInt32Only | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedShortNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLUnsignedShort>>::value)
 {
 }
 
@@ -823,7 +866,7 @@ static inline JSValue jsTestDOMJITLongNullableAttrGetter(ExecState& state, JSTes
 }
 
 TestDOMJITLongNullableAttrDOMJIT::TestDOMJITLongNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecInt32Only | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLLong>>::value)
 {
 }
 
@@ -850,7 +893,7 @@ static inline JSValue jsTestDOMJITUnsignedLongNullableAttrGetter(ExecState& stat
 }
 
 TestDOMJITUnsignedLongNullableAttrDOMJIT::TestDOMJITUnsignedLongNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLUnsignedLong>>::value)
 {
 }
 
@@ -877,7 +920,7 @@ static inline JSValue jsTestDOMJITLongLongNullableAttrGetter(ExecState& state, J
 }
 
 TestDOMJITLongLongNullableAttrDOMJIT::TestDOMJITLongLongNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongLongNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITLongLongNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLLongLong>>::value)
 {
 }
 
@@ -904,7 +947,7 @@ static inline JSValue jsTestDOMJITUnsignedLongLongNullableAttrGetter(ExecState&
 }
 
 TestDOMJITUnsignedLongLongNullableAttrDOMJIT::TestDOMJITUnsignedLongLongNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongLongNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnsignedLongLongNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLUnsignedLongLong>>::value)
 {
 }
 
@@ -931,7 +974,7 @@ static inline JSValue jsTestDOMJITFloatNullableAttrGetter(ExecState& state, JSTe
 }
 
 TestDOMJITFloatNullableAttrDOMJIT::TestDOMJITFloatNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITFloatNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITFloatNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLFloat>>::value)
 {
 }
 
@@ -958,7 +1001,7 @@ static inline JSValue jsTestDOMJITUnrestrictedFloatNullableAttrGetter(ExecState&
 }
 
 TestDOMJITUnrestrictedFloatNullableAttrDOMJIT::TestDOMJITUnrestrictedFloatNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedFloatNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedFloatNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLUnrestrictedFloat>>::value)
 {
 }
 
@@ -985,7 +1028,7 @@ static inline JSValue jsTestDOMJITDoubleNullableAttrGetter(ExecState& state, JST
 }
 
 TestDOMJITDoubleNullableAttrDOMJIT::TestDOMJITDoubleNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDoubleNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDoubleNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLDouble>>::value)
 {
 }
 
@@ -1012,7 +1055,7 @@ static inline JSValue jsTestDOMJITUnrestrictedDoubleNullableAttrGetter(ExecState
 }
 
 TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT::TestDOMJITUnrestrictedDoubleNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedDoubleNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecBytecodeNumber | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUnrestrictedDoubleNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLUnrestrictedDouble>>::value)
 {
 }
 
@@ -1039,7 +1082,7 @@ static inline JSValue jsTestDOMJITDomStringNullableAttrGetter(ExecState& state,
 }
 
 TestDOMJITDomStringNullableAttrDOMJIT::TestDOMJITDomStringNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDomStringNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecString | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITDomStringNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLDOMString>>::value)
 {
 }
 
@@ -1066,7 +1109,7 @@ static inline JSValue jsTestDOMJITByteStringNullableAttrGetter(ExecState& state,
 }
 
 TestDOMJITByteStringNullableAttrDOMJIT::TestDOMJITByteStringNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteStringNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecString | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITByteStringNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLByteString>>::value)
 {
 }
 
@@ -1093,7 +1136,7 @@ static inline JSValue jsTestDOMJITUsvStringNullableAttrGetter(ExecState& state,
 }
 
 TestDOMJITUsvStringNullableAttrDOMJIT::TestDOMJITUsvStringNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUsvStringNullableAttr, nullptr, JSTestDOMJIT::info(), (JSC::SpecString | JSC::SpecOther))
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITUsvStringNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLUSVString>>::value)
 {
 }
 
@@ -1120,7 +1163,7 @@ static inline JSValue jsTestDOMJITNodeNullableAttrGetter(ExecState& state, JSTes
 }
 
 TestDOMJITNodeNullableAttrDOMJIT::TestDOMJITNodeNullableAttrDOMJIT()
-    : JSC::DOMJIT::GetterSetter(jsTestDOMJITNodeNullableAttr, nullptr, JSTestDOMJIT::info(), SpecHeapTop)
+    : JSC::DOMJIT::GetterSetter(jsTestDOMJITNodeNullableAttr, nullptr, JSTestDOMJIT::info(), DOMJIT::IDLResultTypeFilter<IDLNullable<IDLInterface<Node>>>::value)
 {
 }
 
@@ -1159,6 +1202,174 @@ JSValue JSTestDOMJIT::getConstructor(VM& vm, const JSGlobalObject* globalObject)
     return getDOMConstructor<JSTestDOMJITConstructor>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
 }
 
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionGetAttributeCaller(JSC::ExecState*, JSTestDOMJIT*, JSC::ThrowScope&);
+
+EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionGetAttribute(ExecState* state)
+{
+    return BindingCaller<JSTestDOMJIT>::callOperation<jsTestDOMJITPrototypeFunctionGetAttributeCaller>(state, "getAttribute");
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionGetAttributeCaller(JSC::ExecState* state, JSTestDOMJIT* castedThis, JSC::ThrowScope& throwScope)
+{
+    UNUSED_PARAM(state);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    if (UNLIKELY(state->argumentCount() < 1))
+        return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
+    auto name = convert<IDLDOMString>(*state, state->uncheckedArgument(0), StringConversionConfiguration::Normal);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(*state, impl.getAttribute(WTFMove(name)));
+    return JSValue::encode(result);
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionGetAttribute(JSC::ExecState* state, JSTestDOMJIT* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> encodedName)
+{
+    UNUSED_PARAM(state);
+    VM& vm = state->vm();
+    JSC::NativeCallFrameTracer tracer(&vm, state);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    auto name = DOMJIT::DirectConverter<IDLDOMString>::directConvert<StringConversionConfiguration::Normal>(*state, encodedName);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLNullable<IDLDOMString>>(*state, impl.getAttribute(WTFMove(name)));
+    return JSValue::encode(result);
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionItemCaller(JSC::ExecState*, JSTestDOMJIT*, JSC::ThrowScope&);
+
+EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionItem(ExecState* state)
+{
+    return BindingCaller<JSTestDOMJIT>::callOperation<jsTestDOMJITPrototypeFunctionItemCaller>(state, "item");
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionItemCaller(JSC::ExecState* state, JSTestDOMJIT* castedThis, JSC::ThrowScope& throwScope)
+{
+    UNUSED_PARAM(state);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    if (UNLIKELY(state->argumentCount() < 2))
+        return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
+    auto x = convert<IDLUnsignedShort>(*state, state->uncheckedArgument(0), IntegerConversionConfiguration::Normal);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    auto y = convert<IDLUnsignedShort>(*state, state->uncheckedArgument(1), IntegerConversionConfiguration::Normal);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLDOMString>(*state, impl.item(WTFMove(x), WTFMove(y)));
+    return JSValue::encode(result);
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionItem(JSC::ExecState* state, JSTestDOMJIT* castedThis, DOMJIT::IDLJSArgumentType<IDLUnsignedShort> encodedX, DOMJIT::IDLJSArgumentType<IDLUnsignedShort> encodedY)
+{
+    UNUSED_PARAM(state);
+    VM& vm = state->vm();
+    JSC::NativeCallFrameTracer tracer(&vm, state);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    auto x = DOMJIT::DirectConverter<IDLUnsignedShort>::directConvert<IntegerConversionConfiguration::Normal>(*state, encodedX);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    auto y = DOMJIT::DirectConverter<IDLUnsignedShort>::directConvert<IntegerConversionConfiguration::Normal>(*state, encodedY);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLDOMString>(*state, impl.item(WTFMove(x), WTFMove(y)));
+    return JSValue::encode(result);
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionHasAttributeCaller(JSC::ExecState*, JSTestDOMJIT*, JSC::ThrowScope&);
+
+EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionHasAttribute(ExecState* state)
+{
+    return BindingCaller<JSTestDOMJIT>::callOperation<jsTestDOMJITPrototypeFunctionHasAttributeCaller>(state, "hasAttribute");
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionHasAttributeCaller(JSC::ExecState* state, JSTestDOMJIT* castedThis, JSC::ThrowScope& throwScope)
+{
+    UNUSED_PARAM(state);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    JSValue result = toJS<IDLBoolean>(impl.hasAttribute());
+    return JSValue::encode(result);
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionHasAttribute(JSC::ExecState* state, JSTestDOMJIT* castedThis)
+{
+    UNUSED_PARAM(state);
+    VM& vm = state->vm();
+    JSC::NativeCallFrameTracer tracer(&vm, state);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    JSValue result = toJS<IDLBoolean>(impl.hasAttribute());
+    return JSValue::encode(result);
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionGetElementByIdCaller(JSC::ExecState*, JSTestDOMJIT*, JSC::ThrowScope&);
+
+EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionGetElementById(ExecState* state)
+{
+    return BindingCaller<JSTestDOMJIT>::callOperation<jsTestDOMJITPrototypeFunctionGetElementByIdCaller>(state, "getElementById");
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionGetElementByIdCaller(JSC::ExecState* state, JSTestDOMJIT* castedThis, JSC::ThrowScope& throwScope)
+{
+    UNUSED_PARAM(state);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    if (UNLIKELY(state->argumentCount() < 1))
+        return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
+    auto elementId = AtomicString(state->uncheckedArgument(0).toString(state)->toExistingAtomicString(state));
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLInterface<Element>>(*state, *castedThis->globalObject(), impl.getElementById(WTFMove(elementId)));
+    return JSValue::encode(result);
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionGetElementById(JSC::ExecState* state, JSTestDOMJIT* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> encodedElementId)
+{
+    UNUSED_PARAM(state);
+    VM& vm = state->vm();
+    JSC::NativeCallFrameTracer tracer(&vm, state);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    auto elementId = AtomicString(encodedElementId->toExistingAtomicString(state));
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLInterface<Element>>(*state, *castedThis->globalObject(), impl.getElementById(WTFMove(elementId)));
+    return JSValue::encode(result);
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionGetElementsByNameCaller(JSC::ExecState*, JSTestDOMJIT*, JSC::ThrowScope&);
+
+EncodedJSValue JSC_HOST_CALL jsTestDOMJITPrototypeFunctionGetElementsByName(ExecState* state)
+{
+    return BindingCaller<JSTestDOMJIT>::callOperation<jsTestDOMJITPrototypeFunctionGetElementsByNameCaller>(state, "getElementsByName");
+}
+
+static inline JSC::EncodedJSValue jsTestDOMJITPrototypeFunctionGetElementsByNameCaller(JSC::ExecState* state, JSTestDOMJIT* castedThis, JSC::ThrowScope& throwScope)
+{
+    UNUSED_PARAM(state);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    if (UNLIKELY(state->argumentCount() < 1))
+        return throwVMError(state, throwScope, createNotEnoughArgumentsError(state));
+    auto elementName = state->uncheckedArgument(0).toString(state)->toAtomicString(state);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLInterface<NodeList>>(*state, *castedThis->globalObject(), impl.getElementsByName(WTFMove(elementName)));
+    return JSValue::encode(result);
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL unsafeJsTestDOMJITPrototypeFunctionGetElementsByName(JSC::ExecState* state, JSTestDOMJIT* castedThis, DOMJIT::IDLJSArgumentType<IDLDOMString> encodedElementName)
+{
+    UNUSED_PARAM(state);
+    VM& vm = state->vm();
+    JSC::NativeCallFrameTracer tracer(&vm, state);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    UNUSED_PARAM(throwScope);
+    auto& impl = castedThis->wrapped();
+    auto elementName = encodedElementName->toAtomicString(state);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+    JSValue result = toJS<IDLInterface<NodeList>>(*state, *castedThis->globalObject(), impl.getElementsByName(WTFMove(elementName)));
+    return JSValue::encode(result);
+}
+
 void JSTestDOMJIT::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
     auto* thisObject = jsCast<JSTestDOMJIT*>(cell);
index be7ed04..b33366b 100644 (file)
@@ -63,4 +63,10 @@ interface TestDOMJIT : Node {
     [DOMJIT] readonly attribute ByteString? byteStringNullableAttr;
     [DOMJIT] readonly attribute USVString? usvStringNullableAttr;
     [DOMJIT] readonly attribute Node? nodeNullableAttr;
+
+    [DOMJIT=ReadDOM] DOMString? getAttribute(DOMString name);
+    [DOMJIT=ReadDOM] DOMString item(unsigned short x, unsigned short y);
+    [DOMJIT=ReadDOM] boolean hasAttribute();
+    [DOMJIT=ReadDOM] Element getElementById([RequiresExistingAtomicString] DOMString elementId);
+    [DOMJIT=ReadDOM] NodeList getElementsByName([AtomicString] DOMString elementName);
 };
index 7056173..8197515 100644 (file)
 ] interface Element : Node {
     readonly attribute DOMString? tagName;
 
-    DOMString? getAttribute(DOMString name);
+    [DOMJIT=ReadDOM] DOMString? getAttribute(DOMString name);
 
     [CEReactions, MayThrowException] void setAttribute(DOMString name, DOMString value);
 
     [CEReactions] void removeAttribute(DOMString name);
-    Attr? getAttributeNode(DOMString name);
+    [DOMJIT=ReadDOM] Attr? getAttributeNode(DOMString name);
 
     [CEReactions, MayThrowException] Attr? setAttributeNode(Attr newAttr);
     [CEReactions, MayThrowException] Attr removeAttributeNode(Attr oldAttr);
 
-    HTMLCollection getElementsByTagName(DOMString name);
+    [DOMJIT=ReadDOM] HTMLCollection getElementsByTagName(DOMString name);
 
     readonly attribute NamedNodeMap attributes;
-    boolean hasAttributes();
+    [DOMJIT=ReadDOM] boolean hasAttributes();
 
     DOMString? getAttributeNS(DOMString? namespaceURI, DOMString localName);
 
diff --git a/Source/WebCore/domjit/DOMJITAbstractHeapRepository.yaml b/Source/WebCore/domjit/DOMJITAbstractHeapRepository.yaml
new file mode 100644 (file)
index 0000000..52c5845
--- /dev/null
@@ -0,0 +1,11 @@
+DOM:
+    Tree:
+        Node:
+            - Node_firstChild
+            - Node_lastChild
+            - Node_parentNode
+            - Node_nextSibling
+            - Node_previousSibling
+            - Node_ownerDocument
+        Document:
+            - Document_documentElement
diff --git a/Source/WebCore/domjit/DOMJITIDLConvert.h b/Source/WebCore/domjit/DOMJITIDLConvert.h
new file mode 100644 (file)
index 0000000..5e00abf
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 "IDLTypes.h"
+#include <bytecode/SpeculatedType.h>
+#include <domjit/DOMJITSignature.h>
+
+namespace WebCore { namespace DOMJIT {
+
+template<typename IDLType>
+struct DirectConverter;
+
+template<>
+struct DirectConverter<IDLDOMString> {
+    template<StringConversionConfiguration>
+    static String directConvert(JSC::ExecState&, JSC::JSString*);
+};
+
+template<>
+inline String DirectConverter<IDLDOMString>::directConvert<StringConversionConfiguration::Normal>(JSC::ExecState& state, JSC::JSString* string)
+{
+    return string->value(&state);
+}
+
+} }
diff --git a/Source/WebCore/domjit/DOMJITIDLType.h b/Source/WebCore/domjit/DOMJITIDLType.h
new file mode 100644 (file)
index 0000000..6891fbc
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 "IDLTypes.h"
+#include <bytecode/SpeculatedType.h>
+
+namespace WebCore { namespace DOMJIT {
+
+template<typename IDLType>
+struct IDLJSArgumentTypeSelect;
+
+template<> struct IDLJSArgumentTypeSelect<IDLBoolean> { typedef bool type; };
+template<> struct IDLJSArgumentTypeSelect<IDLByte> { typedef int32_t type; };
+template<> struct IDLJSArgumentTypeSelect<IDLOctet> { typedef int32_t type; };
+template<> struct IDLJSArgumentTypeSelect<IDLShort> { typedef int32_t type; };
+template<> struct IDLJSArgumentTypeSelect<IDLUnsignedShort> { typedef int32_t type; };
+template<> struct IDLJSArgumentTypeSelect<IDLLong> { typedef int32_t type; };
+template<> struct IDLJSArgumentTypeSelect<IDLDOMString> { typedef JSC::JSString* type; };
+
+template<typename IDLType>
+using IDLJSArgumentType = typename IDLJSArgumentTypeSelect<IDLType>::type;
+
+} }
diff --git a/Source/WebCore/domjit/DOMJITIDLTypeFilter.h b/Source/WebCore/domjit/DOMJITIDLTypeFilter.h
new file mode 100644 (file)
index 0000000..d52d996
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 <bytecode/SpeculatedType.h>
+
+namespace WebCore { namespace DOMJIT {
+
+template<typename IDLType>
+struct IDLArgumentTypeFilter;
+
+template<> struct IDLArgumentTypeFilter<IDLBoolean> { static const constexpr JSC::SpeculatedType value = JSC::SpecBoolean; };
+template<> struct IDLArgumentTypeFilter<IDLByte> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLArgumentTypeFilter<IDLOctet> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLArgumentTypeFilter<IDLShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLArgumentTypeFilter<IDLUnsignedShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLArgumentTypeFilter<IDLLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLArgumentTypeFilter<IDLDOMString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; };
+
+template<typename IDLType>
+struct IDLResultTypeFilter {
+    static const constexpr JSC::SpeculatedType value = JSC::SpecHeapTop;
+};
+
+template<> struct IDLResultTypeFilter<IDLAny> { static const constexpr JSC::SpeculatedType value = JSC::SpecHeapTop; };
+template<> struct IDLResultTypeFilter<IDLBoolean> { static const constexpr JSC::SpeculatedType value = JSC::SpecBoolean; };
+template<> struct IDLResultTypeFilter<IDLByte> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLResultTypeFilter<IDLOctet> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLResultTypeFilter<IDLShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLResultTypeFilter<IDLUnsignedShort> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLResultTypeFilter<IDLLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecInt32Only; };
+template<> struct IDLResultTypeFilter<IDLUnsignedLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLLongLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLUnsignedLongLong> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLFloat> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLUnrestrictedFloat> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLDouble> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLUnrestrictedDouble> { static const constexpr JSC::SpeculatedType value = JSC::SpecBytecodeNumber; };
+template<> struct IDLResultTypeFilter<IDLDOMString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; };
+template<> struct IDLResultTypeFilter<IDLByteString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; };
+template<> struct IDLResultTypeFilter<IDLUSVString> { static const constexpr JSC::SpeculatedType value = JSC::SpecString; };
+
+template<typename T>
+struct IDLResultTypeFilter<IDLNullable<T>> {
+    static const constexpr JSC::SpeculatedType value = JSC::SpecOther | IDLResultTypeFilter<T>::value;
+};
+
+} }
index 9b48d9f..bbfee7d 100644 (file)
@@ -48,7 +48,6 @@ Ref<JSC::DOMJIT::Patchpoint> DocumentDocumentElementDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> DocumentDocumentElementDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> patchpoint = JSC::DOMJIT::CallDOMGetterPatchpoint::create();
     patchpoint->numGPScratchRegisters = 1;
     patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
@@ -70,7 +69,7 @@ Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> DocumentDocumentElementDOMJIT::callDOM
 
         return CCallHelpers::JumpList();
     });
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Document_documentElement);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Document_documentElement);
     return patchpoint;
 }
 
index 1d7901e..db310ea 100644 (file)
@@ -83,9 +83,8 @@ Ref<JSC::DOMJIT::Patchpoint> NodeFirstChildDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodeFirstChildDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     auto patchpoint = createCallDOMGetterForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_firstChild);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_firstChild);
     return patchpoint;
 }
 
@@ -96,9 +95,8 @@ Ref<JSC::DOMJIT::Patchpoint> NodeLastChildDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodeLastChildDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     auto patchpoint = createCallDOMGetterForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_lastChild);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_lastChild);
     return patchpoint;
 }
 
@@ -109,9 +107,8 @@ Ref<JSC::DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodeNextSiblingDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     auto patchpoint = createCallDOMGetterForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_nextSibling);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_nextSibling);
     return patchpoint;
 }
 
@@ -122,9 +119,8 @@ Ref<JSC::DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodePreviousSiblingDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     auto patchpoint = createCallDOMGetterForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_previousSibling);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_previousSibling);
     return patchpoint;
 }
 
@@ -135,9 +131,8 @@ Ref<JSC::DOMJIT::Patchpoint> NodeParentNodeDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodeParentNodeDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     auto patchpoint = createCallDOMGetterForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_parentNode);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_parentNode);
     return patchpoint;
 }
 
@@ -169,7 +164,6 @@ Ref<JSC::DOMJIT::Patchpoint> NodeOwnerDocumentDOMJIT::checkDOM()
 
 Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodeOwnerDocumentDOMJIT::callDOMGetter()
 {
-    const auto& heap = DOMJIT::AbstractHeapRepository::shared();
     Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> patchpoint = JSC::DOMJIT::CallDOMGetterPatchpoint::create();
     patchpoint->numGPScratchRegisters = 1;
     patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
@@ -191,7 +185,7 @@ Ref<JSC::DOMJIT::CallDOMGetterPatchpoint> NodeOwnerDocumentDOMJIT::callDOMGetter
         done.link(&jit);
         return CCallHelpers::JumpList();
     });
-    patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_ownerDocument);
+    patchpoint->effect = JSC::DOMJIT::Effect::forDef(DOMJIT::AbstractHeapRepository::Node_ownerDocument);
     return patchpoint;
 }
 
diff --git a/Source/WebCore/domjit/generate-abstract-heap.rb b/Source/WebCore/domjit/generate-abstract-heap.rb
new file mode 100644 (file)
index 0000000..b7412e8
--- /dev/null
@@ -0,0 +1,165 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+# 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+
+require "yaml"
+
+class HeapRange
+    attr_reader :first, :last
+    def initialize(first, last)
+        @first = first
+        @last = last
+    end
+end
+
+class AbstractHeap
+    attr_reader :range, :name, :parent
+    def initialize(name, tree)
+        @name = name
+        @parent = nil
+        if tree.nil?
+            @children = []
+        else
+            @children = tree.map {|key, value| AbstractHeap.new(key, value) }
+        end
+        @range = nil
+    end
+
+    def setParent(parent)
+        parent.children.push(self)
+        @parent = parent
+    end
+
+    def compute(start)
+        current = start
+        if @children.empty?
+            @range = HeapRange.new(start, current + 1)
+            return
+        end
+
+        @children.each {|child|
+            child.compute(current)
+            current = child.range.last
+        }
+
+        @range = HeapRange.new(start, current)
+    end
+
+    def dump output
+        shallowDump(output)
+        if @parent
+            output.print "-> "
+            @parent.dump(output)
+        end
+    end
+
+    def shallowDump(output)
+        output.print "#{@name}<#{@range.first},#{@range.last}>"
+    end
+
+    def deepDump output, indent
+        printIndent(output, indent)
+        shallowDump(output)
+        if @children.empty?
+            output.print "\n"
+            return
+        end
+
+        output.print ":\n"
+        @children.each {|child|
+            child.deepDump(output, indent + 1)
+        }
+    end
+
+    def generate output
+        output.puts "constexpr JSC::DOMJIT::HeapRange #{@name}(JSC::DOMJIT::HeapRange::ConstExpr, #{@range.first}, #{@range.last});"
+        @children.each {|child|
+            child.generate(output)
+        }
+    end
+
+private
+    def printIndent output, indent
+        indent.times {
+            output.print "    "
+        }
+    end
+end
+
+header = <<-EOS
+/*
+ * 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.
+ */
+// Auto-generated file. Do not modify.
+
+#pragma once
+
+#include <domjit/DOMJITHeapRange.h>
+
+namespace WebCore { namespace DOMJIT { namespace AbstractHeapRepository {
+EOS
+
+footer = <<-EOS
+} } }
+EOS
+
+$inputFileName = ARGV.shift
+$outputFileName = ARGV.shift
+File.open($outputFileName, "w") {|output|
+    File.open($inputFileName, "rb") {|file|
+        tree = YAML::load(file.read())
+        heap = tree.map {|key, value|
+            AbstractHeap.new(key, value)
+        }.first
+        heap.compute(0)
+
+        output.print(header)
+        output.puts("/* DOMJIT Abstract Heap Tree.")
+        heap.deepDump(output, 0)
+        output.puts("*/")
+        heap.generate(output)
+        output.print(footer)
+    }
+}