Title: [207427] trunk
Revision
207427
Author
utatane....@gmail.com
Date
2016-10-17 13:43:43 -0700 (Mon, 17 Oct 2016)

Log Message

[DOMJIT] Use DOMJIT::Patchpoint in IC
https://bugs.webkit.org/show_bug.cgi?id=163223

Reviewed by Saam Barati.

JSTests:

* stress/domjit-exception-ic.js: Added.
(shouldBe):
(access):
* stress/domjit-exception.js: Added.
(shouldBe):
(access):
* stress/domjit-getter-complex-with-incorrect-object.js: Added.
(shouldThrow):
(access):
(i.shouldThrow):
* stress/domjit-getter-complex.js: Added.
(shouldBe):
(access):
* stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js: Added.
(assert):
(bar):
(foo):

Source/_javascript_Core:

This patch uses DOMJIT::Patchpoint to inline DOM accesses even in IC!
It is useful for Baseline JIT cases and GetById cases in DFG and FTL.
In AccessCase, we construct the environment that allows DOMJIT::Patchpoint
to emit code and make DOMJIT accessors inlined in IC.

To allow DOMJIT::Patchpoint to emit code, we create a mechanism to emit calls
required in DOMJIT::Patchpoint. This system is useful when we create the super-
polymorphic support[1] later. And inlining mechanism is useful even after
introducing super-polymorphic support since it can work even after we fire the
watchpoint for super-polymorphic handling.

This patch improves Dromaeo dom-traverse 8% (263.95 runs/s v.s. 244.07 runs/s).

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

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* bytecode/DOMJITAccessCasePatchpointParams.cpp: Added.
(JSC::SlowPathCallGeneratorWithArguments::SlowPathCallGeneratorWithArguments):
(JSC::SlowPathCallGeneratorWithArguments::generateImpl):
(JSC::DOMJITAccessCasePatchpointParams::emitSlowPathCalls):
* bytecode/DOMJITAccessCasePatchpointParams.h: Copied from Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.h.
(JSC::DOMJITAccessCasePatchpointParams::DOMJITAccessCasePatchpointParams):
(JSC::DOMJITAccessCasePatchpointParams::SlowPathCallGenerator::~SlowPathCallGenerator):
* bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationState::liveRegistersForCall):
(JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
(JSC::calleeSaveRegisters):
(JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
(JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
(JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
(JSC::AccessGenerationState::originalExceptionHandler):
(JSC::AccessCase::generateImpl):
(JSC::AccessCase::emitDOMJITGetter):
(JSC::PolymorphicAccess::regenerate):
(JSC::AccessGenerationState::preserveLiveRegistersToStackForCall): Deleted.
* bytecode/PolymorphicAccess.h:
(JSC::AccessGenerationState::SpillState::isEmpty):
(JSC::AccessGenerationState::setSpillStateForJSGetterSetter):
(JSC::AccessGenerationState::spillStateForJSGetterSetter):
(JSC::AccessGenerationState::liveRegistersForCall): Deleted.
(JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation): Deleted.
(JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite): Deleted.
* dfg/DFGDOMJITPatchpointParams.cpp:
* dfg/DFGDOMJITPatchpointParams.h:
* domjit/DOMJITPatchpoint.h:
* domjit/DOMJITPatchpointParams.h:
(JSC::DOMJIT::PatchpointParams::addSlowPathCall):
* ftl/FTLDOMJITPatchpointParams.cpp:
* ftl/FTLDOMJITPatchpointParams.h:
* jsc.cpp:
(WTF::DOMJITNode::checkDOMJITNode):
(WTF::DOMJITGetterComplex::DOMJITGetterComplex):
(WTF::DOMJITGetterComplex::createStructure):
(WTF::DOMJITGetterComplex::create):
(WTF::DOMJITGetterComplex::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
(WTF::DOMJITGetterComplex::domJITNodeGetterSetter):
(WTF::DOMJITGetterComplex::finishCreation):
(WTF::DOMJITGetterComplex::functionEnableException):
(WTF::DOMJITGetterComplex::customGetter):
(GlobalObject::finishCreation):
(functionCreateDOMJITGetterComplexObject):

Source/WebCore:

Make DOMJITPatchpointParams non-const.

* domjit/DOMJITHelpers.h:
(WebCore::DOMJITHelpers::toWrapper):
* domjit/JSNodeDOMJIT.cpp:
(WebCore::createCallDOMForOffsetAccess):
(WebCore::checkNode):
(WebCore::NodeNodeTypeDOMJIT::callDOM):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (207426 => 207427)


--- trunk/JSTests/ChangeLog	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/JSTests/ChangeLog	2016-10-17 20:43:43 UTC (rev 207427)
@@ -1,3 +1,28 @@
+2016-10-17  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DOMJIT] Use DOMJIT::Patchpoint in IC
+        https://bugs.webkit.org/show_bug.cgi?id=163223
+
+        Reviewed by Saam Barati.
+
+        * stress/domjit-exception-ic.js: Added.
+        (shouldBe):
+        (access):
+        * stress/domjit-exception.js: Added.
+        (shouldBe):
+        (access):
+        * stress/domjit-getter-complex-with-incorrect-object.js: Added.
+        (shouldThrow):
+        (access):
+        (i.shouldThrow):
+        * stress/domjit-getter-complex.js: Added.
+        (shouldBe):
+        (access):
+        * stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js: Added.
+        (assert):
+        (bar):
+        (foo):
+
 2016-10-15  Saam Barati  <sbar...@apple.com>
 
         Assertion failed under operationToLowerCase with a rope with zero length

Added: trunk/JSTests/stress/domjit-exception-ic.js (0 => 207427)


--- trunk/JSTests/stress/domjit-exception-ic.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-exception-ic.js	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,37 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    let normal = {
+        customGetter: 42
+    };
+    for (let i = 0; i < 1e4; ++i) {
+        shouldBe(access(domjit), 42);
+        shouldBe(access(normal), 42);
+    }
+    domjit.enableException();
+    shouldThrow(() => access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());

Added: trunk/JSTests/stress/domjit-exception.js (0 => 207427)


--- trunk/JSTests/stress/domjit-exception.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-exception.js	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,67 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (var i = 0; i < 1e4; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() => access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (let i = 0; i < 1e2; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() => access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (let i = 0; i < 50; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() => access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (let i = 0; i < 10; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() => access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());

Added: trunk/JSTests/stress/domjit-getter-complex-with-incorrect-object.js (0 => 207427)


--- trunk/JSTests/stress/domjit-getter-complex-with-incorrect-object.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter-complex-with-incorrect-object.js	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,28 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+var complex = createDOMJITGetterComplexObject();
+var object = {};
+object.__proto__ = complex;
+function access(object)
+{
+    return object.customGetter;
+}
+noInline(access);
+for (var i = 0; i < 1e4; ++i) {
+    shouldThrow(() => {
+        access(object);
+    }, `TypeError: Type error`);
+}

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


--- trunk/JSTests/stress/domjit-getter-complex.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter-complex.js	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,14 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+var complex = createDOMJITGetterComplexObject();
+function access(complex)
+{
+    return complex.customGetter;
+}
+noInline(access);
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(access(complex), 42);
+}

Added: trunk/JSTests/stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js (0 => 207427)


--- trunk/JSTests/stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js	                        (rev 0)
+++ trunk/JSTests/stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,52 @@
+function assert(b) {
+    if (!b) throw new Error("bad value");
+}
+noInline(assert);
+
+let i;
+var o1 = createDOMJITGetterComplexObject();
+o1.x = "x";
+
+var o2 = {
+    customGetter: 40
+}
+
+var o3 = {
+    x: 100,
+    customGetter: "f"
+}
+
+function bar(i) {
+    if (i === -1000)
+        return o1;
+
+    if (i % 2)
+        return o3;
+    else
+        return o2;
+}
+noInline(bar);
+
+function foo(i) {
+    var o = bar(i);
+    let v;
+    let v2;
+    let v3;
+    try {
+        v2 = o.x;
+        v = o.customGetter + v2;
+    } catch(e) {
+        assert(v2 === "x");
+        assert(o === o1);
+    }
+}
+noInline(foo);
+
+foo(i);
+for (i = 0; i < 1000; i++)
+    foo(i);
+
+o1.enableException();
+i = -1000;
+for (let j = 0; j < 1000; j++)
+    foo(i);

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (207426 => 207427)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2016-10-17 20:43:43 UTC (rev 207427)
@@ -204,6 +204,7 @@
     bytecode/ComplexGetStatus.cpp
     bytecode/DataFormat.cpp
     bytecode/DFGExitProfile.cpp
+    bytecode/DOMJITAccessCasePatchpointParams.cpp
     bytecode/DeferredCompilationCallback.cpp
     bytecode/DeferredSourceDump.cpp
     bytecode/ExecutionCounter.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (207426 => 207427)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-17 20:43:43 UTC (rev 207427)
@@ -1,3 +1,74 @@
+2016-10-17  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DOMJIT] Use DOMJIT::Patchpoint in IC
+        https://bugs.webkit.org/show_bug.cgi?id=163223
+
+        Reviewed by Saam Barati.
+
+        This patch uses DOMJIT::Patchpoint to inline DOM accesses even in IC!
+        It is useful for Baseline JIT cases and GetById cases in DFG and FTL.
+        In AccessCase, we construct the environment that allows DOMJIT::Patchpoint
+        to emit code and make DOMJIT accessors inlined in IC.
+
+        To allow DOMJIT::Patchpoint to emit code, we create a mechanism to emit calls
+        required in DOMJIT::Patchpoint. This system is useful when we create the super-
+        polymorphic support[1] later. And inlining mechanism is useful even after
+        introducing super-polymorphic support since it can work even after we fire the
+        watchpoint for super-polymorphic handling.
+
+        This patch improves Dromaeo dom-traverse 8% (263.95 runs/s v.s. 244.07 runs/s).
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=163226
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * bytecode/DOMJITAccessCasePatchpointParams.cpp: Added.
+        (JSC::SlowPathCallGeneratorWithArguments::SlowPathCallGeneratorWithArguments):
+        (JSC::SlowPathCallGeneratorWithArguments::generateImpl):
+        (JSC::DOMJITAccessCasePatchpointParams::emitSlowPathCalls):
+        * bytecode/DOMJITAccessCasePatchpointParams.h: Copied from Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.h.
+        (JSC::DOMJITAccessCasePatchpointParams::DOMJITAccessCasePatchpointParams):
+        (JSC::DOMJITAccessCasePatchpointParams::SlowPathCallGenerator::~SlowPathCallGenerator):
+        * bytecode/PolymorphicAccess.cpp:
+        (JSC::AccessGenerationState::liveRegistersForCall):
+        (JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite):
+        (JSC::calleeSaveRegisters):
+        (JSC::AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling):
+        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException):
+        (JSC::AccessGenerationState::restoreLiveRegistersFromStackForCall):
+        (JSC::AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal):
+        (JSC::AccessGenerationState::originalExceptionHandler):
+        (JSC::AccessCase::generateImpl):
+        (JSC::AccessCase::emitDOMJITGetter):
+        (JSC::PolymorphicAccess::regenerate):
+        (JSC::AccessGenerationState::preserveLiveRegistersToStackForCall): Deleted.
+        * bytecode/PolymorphicAccess.h:
+        (JSC::AccessGenerationState::SpillState::isEmpty):
+        (JSC::AccessGenerationState::setSpillStateForJSGetterSetter):
+        (JSC::AccessGenerationState::spillStateForJSGetterSetter):
+        (JSC::AccessGenerationState::liveRegistersForCall): Deleted.
+        (JSC::AccessGenerationState::numberOfStackBytesUsedForRegisterPreservation): Deleted.
+        (JSC::AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite): Deleted.
+        * dfg/DFGDOMJITPatchpointParams.cpp:
+        * dfg/DFGDOMJITPatchpointParams.h:
+        * domjit/DOMJITPatchpoint.h:
+        * domjit/DOMJITPatchpointParams.h:
+        (JSC::DOMJIT::PatchpointParams::addSlowPathCall):
+        * ftl/FTLDOMJITPatchpointParams.cpp:
+        * ftl/FTLDOMJITPatchpointParams.h:
+        * jsc.cpp:
+        (WTF::DOMJITNode::checkDOMJITNode):
+        (WTF::DOMJITGetterComplex::DOMJITGetterComplex):
+        (WTF::DOMJITGetterComplex::createStructure):
+        (WTF::DOMJITGetterComplex::create):
+        (WTF::DOMJITGetterComplex::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
+        (WTF::DOMJITGetterComplex::domJITNodeGetterSetter):
+        (WTF::DOMJITGetterComplex::finishCreation):
+        (WTF::DOMJITGetterComplex::functionEnableException):
+        (WTF::DOMJITGetterComplex::customGetter):
+        (GlobalObject::finishCreation):
+        (functionCreateDOMJITGetterComplexObject):
+
 2016-10-17  Saam Barati  <sbar...@apple.com>
 
         Build fix for HasOwnPropertyCache::Entry caused slowdown by introducing a constructor that doesn't use move semantics for the RefPtr<UniquedStringImpl> parameter

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (207426 => 207427)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-10-17 20:43:43 UTC (rev 207427)
@@ -2114,6 +2114,8 @@
 		E39DA4A61B7E8B7C0084F33A /* JSModuleRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */; };
 		E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E3A421431D6F58930007C617 /* PreciseJumpTargetsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */; };
+		E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */; };
 		E3C08E3C1DA41B810039478F /* DOMJITPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E3D239C81B829C1C00BBEF67 /* JSModuleEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */; };
 		E3D239C91B829C1C00BBEF67 /* JSModuleEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D239C71B829C1C00BBEF67 /* JSModuleEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -4423,6 +4425,8 @@
 		E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; };
 		E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = "<group>"; };
 		E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreciseJumpTargetsInlines.h; sourceTree = "<group>"; };
+		E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAccessCasePatchpointParams.cpp; sourceTree = "<group>"; };
+		E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAccessCasePatchpointParams.h; sourceTree = "<group>"; };
 		E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpoint.h; sourceTree = "<group>"; };
 		E3CB1E241DA7540A00FA1E56 /* DOMJITSlowPathCalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITSlowPathCalls.h; sourceTree = "<group>"; };
 		E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleEnvironment.cpp; sourceTree = "<group>"; };
@@ -6824,6 +6828,8 @@
 				0F0B83A514BCF50400885B4F /* CodeType.h */,
 				0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */,
 				0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */,
+				E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */,
+				E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */,
 				62E3D5EF1B8D0B7300B868BB /* DataFormat.cpp */,
 				0F426A4A1460CD6B00131F8F /* DataFormat.h */,
 				0FC712DC17CD8778008CC93C /* DeferredCompilationCallback.cpp */,
@@ -7526,6 +7532,7 @@
 				0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */,
 				86EC9DC51328DF82002B2AD7 /* DFGByteCodeParser.h in Headers */,
 				0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */,
+				E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */,
 				0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */,
 				0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */,
 				0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */,
@@ -9422,6 +9429,7 @@
 				E35E035F1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp in Sources */,
 				A532438B18568335002ED692 /* InspectorProtocolObjects.cpp in Sources */,
 				A50E4B6118809DD50068A46D /* InspectorRuntimeAgent.cpp in Sources */,
+				E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */,
 				A593CF821840377100BFCE27 /* InspectorValues.cpp in Sources */,
 				147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */,
 				1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */,

Added: trunk/Source/_javascript_Core/bytecode/DOMJITAccessCasePatchpointParams.cpp (0 => 207427)


--- trunk/Source/_javascript_Core/bytecode/DOMJITAccessCasePatchpointParams.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/bytecode/DOMJITAccessCasePatchpointParams.cpp	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DOMJITAccessCasePatchpointParams.h"
+
+#include "LinkBuffer.h"
+#include "PolymorphicAccess.h"
+#include "StructureStubInfo.h"
+
+#if ENABLE(JIT)
+
+namespace JSC {
+
+template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
+class SlowPathCallGeneratorWithArguments : public DOMJITAccessCasePatchpointParams::SlowPathCallGenerator {
+public:
+    SlowPathCallGeneratorWithArguments(JumpType from, CCallHelpers::Label to, FunctionType function, ResultType result, std::tuple<Arguments...> arguments)
+        : m_from(from)
+        , m_to(to)
+        , m_function(function)
+        , m_result(result)
+        , m_arguments(arguments)
+    {
+    }
+
+    template<size_t... ArgumentsIndex>
+    CCallHelpers::JumpList generateImpl(VM& vm, AccessGenerationState& state, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers& jit, std::index_sequence<ArgumentsIndex...>)
+    {
+        CCallHelpers::JumpList exceptions;
+        // We spill (1) the used registers by IC and (2) the used registers by DOMJIT::Patchpoint.
+        AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall(usedRegistersByPatchpoint);
+
+        jit.store32(
+            CCallHelpers::TrustedImm32(state.callSiteIndexForExceptionHandlingOrOriginal().bits()),
+            CCallHelpers::tagFor(static_cast<VirtualRegister>(CallFrameSlot::argumentCount)));
+
+        jit.makeSpaceOnStackForCCall();
+
+        jit.storePtr(GPRInfo::callFrameRegister, &vm.topCallFrame);
+
+        // FIXME: Currently, we do not check any ARM EABI / SH4 things here.
+        // But it is OK because a compile error happens when you pass JSValueRegs as an argument.
+        // https://bugs.webkit.org/show_bug.cgi?id=163099
+        jit.setupArgumentsWithExecState(std::get<ArgumentsIndex>(m_arguments)...);
+
+        CCallHelpers::Call operationCall = jit.call();
+        auto function = m_function;
+        jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+            linkBuffer.link(operationCall, FunctionPtr(function));
+        });
+
+        jit.setupResults(m_result);
+        jit.reclaimSpaceOnStackForCCall();
+
+        CCallHelpers::Jump noException = jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
+
+        state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
+        exceptions.append(jit.jump());
+
+        noException.link(&jit);
+        RegisterSet dontRestore;
+        dontRestore.set(m_result);
+        state.restoreLiveRegistersFromStackForCall(spillState, dontRestore);
+
+        return exceptions;
+    }
+
+    CCallHelpers::JumpList generate(VM& vm, AccessGenerationState& state, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers& jit) override
+    {
+        m_from.link(&jit);
+        CCallHelpers::JumpList exceptions = generateImpl(vm, state, usedRegistersByPatchpoint, jit, std::make_index_sequence<std::tuple_size<std::tuple<Arguments...>>::value>());
+        jit.jump().linkTo(m_to, &jit);
+        return exceptions;
+    }
+
+protected:
+    JumpType m_from;
+    CCallHelpers::Label m_to;
+    FunctionType m_function;
+    ResultType m_result;
+    std::tuple<Arguments...> m_arguments;
+};
+
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
+    void DOMJITAccessCasePatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \
+    { \
+        CCallHelpers::Label to = jit.label(); \
+        m_generators.append(std::make_unique<SlowPathCallGeneratorWithArguments<CCallHelpers::JumpList, OperationType, ResultType, __VA_ARGS__>>(from, to, operation, result, args)); \
+    } \
+
+DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
+#undef JSC_DEFINE_CALL_OPERATIONS
+
+CCallHelpers::JumpList DOMJITAccessCasePatchpointParams::emitSlowPathCalls(VM& vm, AccessGenerationState& state, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers& jit)
+{
+    CCallHelpers::JumpList exceptions;
+    for (auto& generator : m_generators)
+        exceptions.append(generator->generate(vm, state, usedRegistersByPatchpoint, jit));
+    return exceptions;
+}
+
+}
+
+#endif

Copied: trunk/Source/_javascript_Core/bytecode/DOMJITAccessCasePatchpointParams.h (from rev 207426, trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.h) (0 => 207427)


--- trunk/Source/_javascript_Core/bytecode/DOMJITAccessCasePatchpointParams.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/bytecode/DOMJITAccessCasePatchpointParams.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(JIT)
+
+#include "DOMJITPatchpointParams.h"
+
+namespace JSC {
+
+struct AccessGenerationState;
+
+class DOMJITAccessCasePatchpointParams : public DOMJIT::PatchpointParams {
+public:
+    DOMJITAccessCasePatchpointParams(Vector<DOMJIT::Value>&& regs, Vector<GPRReg>&& gpScratch, Vector<FPRReg>&& fpScratch)
+        : DOMJIT::PatchpointParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch))
+    {
+    }
+
+    class SlowPathCallGenerator {
+    public:
+        virtual ~SlowPathCallGenerator() { }
+        virtual CCallHelpers::JumpList generate(VM&, AccessGenerationState&, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers&) = 0;
+    };
+
+    CCallHelpers::JumpList emitSlowPathCalls(VM&, AccessGenerationState&, const RegisterSet& usedRegistersByPatchpoint, CCallHelpers&);
+
+private:
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) override;
+    DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
+#undef JSC_DEFINE_CALL_OPERATIONS
+    Vector<std::unique_ptr<SlowPathCallGenerator>> m_generators;
+};
+
+}
+
+#endif

Modified: trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp (207426 => 207427)


--- trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.cpp	2016-10-17 20:43:43 UTC (rev 207427)
@@ -31,6 +31,8 @@
 #include "BinarySwitch.h"
 #include "CCallHelpers.h"
 #include "CodeBlock.h"
+#include "DOMJITAccessCasePatchpointParams.h"
+#include "DOMJITCallDOMPatchpoint.h"
 #include "DirectArguments.h"
 #include "GetterSetter.h"
 #include "Heap.h"
@@ -72,8 +74,29 @@
     success.append(jit->jump());
 }
 
-void AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra)
+const RegisterSet& AccessGenerationState::liveRegistersForCall()
 {
+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
+    return m_liveRegistersForCall;
+}
+
+const RegisterSet& AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite()
+{
+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
+    return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
+}
+
+static RegisterSet calleeSaveRegisters()
+{
+    RegisterSet result = RegisterSet::registersToNotSaveForJSCall();
+    result.filter(RegisterSet::registersToNotSaveForCCall());
+    return result;
+}
+
+const RegisterSet& AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling()
+{
     if (!m_calculatedRegistersForCallAndExceptionHandling) {
         m_calculatedRegistersForCallAndExceptionHandling = true;
 
@@ -83,36 +106,26 @@
             RELEASE_ASSERT(JITCode::isOptimizingJIT(jit->codeBlock()->jitType()));
 
         m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator->usedRegisters());
-        m_liveRegistersForCall.merge(extra);
-        m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForJSCall());
-        m_liveRegistersForCall.merge(extra);
+        m_liveRegistersForCall.exclude(calleeSaveRegisters());
     }
+    return m_liveRegistersForCall;
 }
 
-void AccessGenerationState::preserveLiveRegistersToStackForCall(const RegisterSet& extra)
+auto AccessGenerationState::preserveLiveRegistersToStackForCall(const RegisterSet& extra) -> SpillState
 {
-    calculateLiveRegistersForCallAndExceptionHandling(extra);
+    RegisterSet liveRegisters = liveRegistersForCall();
+    liveRegisters.merge(extra);
     
     unsigned extraStackPadding = 0;
-    unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegistersForCall(), extraStackPadding);
-    if (m_numberOfStackBytesUsedForRegisterPreservation != std::numeric_limits<unsigned>::max())
-        RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == m_numberOfStackBytesUsedForRegisterPreservation);
-    m_numberOfStackBytesUsedForRegisterPreservation = numberOfStackBytesUsedForRegisterPreservation;
+    unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegisters, extraStackPadding);
+    return SpillState {
+        liveRegisters,
+        numberOfStackBytesUsedForRegisterPreservation
+    };
 }
 
-void AccessGenerationState::restoreLiveRegistersFromStackForCall(bool isGetter)
+void AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException(const SpillState& spillState)
 {
-    RegisterSet dontRestore;
-    if (isGetter) {
-        // This is the result value. We don't want to overwrite the result with what we stored to the stack.
-        // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
-        dontRestore.set(valueRegs);
-    }
-    restoreLiveRegistersFromStackForCall(dontRestore);
-}
-
-void AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException()
-{
     // Even if we're a getter, we don't want to ignore the result value like we normally do
     // because the getter threw, and therefore, didn't return a value that means anything.
     // Instead, we want to restore that register to what it was upon entering the getter
@@ -119,7 +132,7 @@
     // inline cache. The subtlety here is if the base and the result are the same register,
     // and the getter threw, we want OSR exit to see the original base value, not the result
     // of the getter call.
-    RegisterSet dontRestore = liveRegistersForCall();
+    RegisterSet dontRestore = spillState.spilledRegisters;
     // As an optimization here, we only need to restore what is live for exception handling.
     // We can construct the dontRestore set to accomplish this goal by having it contain only
     // what is live for call but not live for exception handling. By ignoring things that are
@@ -126,18 +139,19 @@
     // only live at the call but not the exception handler, we will only restore things live
     // at the exception handler.
     dontRestore.exclude(liveRegistersToPreserveAtExceptionHandlingCallSite());
-    restoreLiveRegistersFromStackForCall(dontRestore);
+    restoreLiveRegistersFromStackForCall(spillState, dontRestore);
 }
 
-void AccessGenerationState::restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore)
+void AccessGenerationState::restoreLiveRegistersFromStackForCall(const SpillState& spillState, const RegisterSet& dontRestore)
 {
     unsigned extraStackPadding = 0;
-    ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, liveRegistersForCall(), dontRestore, m_numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
+    ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, spillState.spilledRegisters, dontRestore, spillState.numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
 }
 
 CallSiteIndex AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal()
 {
-    RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
 
     if (!m_calculatedCallSiteIndex) {
         m_calculatedCallSiteIndex = true;
@@ -151,8 +165,11 @@
     return m_callSiteIndex;
 }
 
-const HandlerInfo& AccessGenerationState::originalExceptionHandler() const
+const HandlerInfo& AccessGenerationState::originalExceptionHandler()
 {
+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
+
     RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
     HandlerInfo* exceptionHandler = jit->codeBlock()->handlerForIndex(stubInfo->callSiteIndex.bits());
     RELEASE_ASSERT(exceptionHandler);
@@ -932,6 +949,16 @@
             return;
         }
 
+        if (m_type == CustomAccessorGetter && m_rareData->domJIT) {
+            // We do not need to emit CheckDOM operation since structure check ensures
+            // that the structure of the given base value is structure()! So all we should
+            // do is performing the CheckDOM thingy in IC compiling time here.
+            if (structure()->classInfo()->isSubClassOf(m_rareData->domJIT->thisClassInfo())) {
+                emitDOMJITGetter(state, baseForGetGPR);
+                return;
+            }
+        }
+
         // Stuff for custom getters/setters.
         CCallHelpers::Call operationCall;
 
@@ -940,13 +967,20 @@
         CCallHelpers::Call fastPathCall;
         CCallHelpers::Call slowPathCall;
 
-        CCallHelpers::Jump success;
-        CCallHelpers::Jump fail;
-
         // This also does the necessary calculations of whether or not we're an
         // exception handling call site.
-        state.preserveLiveRegistersToStackForCall();
+        AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall();
 
+        auto restoreLiveRegistersFromStackForCall = [&](AccessGenerationState::SpillState& spillState, bool callHasReturnValue) {
+            RegisterSet dontRestore;
+            if (callHasReturnValue) {
+                // This is the result value. We don't want to overwrite the result with what we stored to the stack.
+                // We sometimes have to store it to the stack just in case we throw an exception and need the original value.
+                dontRestore.set(valueRegs);
+            }
+            state.restoreLiveRegistersFromStackForCall(spillState, dontRestore);
+        };
+
         jit.store32(
             CCallHelpers::TrustedImm32(state.callSiteIndexForExceptionHandlingOrOriginal().bits()),
             CCallHelpers::tagFor(static_cast<VirtualRegister>(CallFrameSlot::argumentCount)));
@@ -966,6 +1000,8 @@
             // Therefore, we temporarily grow the stack for the purpose of the call and then
             // shrink it after.
 
+            state.setSpillStateForJSGetterSetter(spillState);
+
             RELEASE_ASSERT(!m_rareData->callLinkInfo);
             m_rareData->callLinkInfo = std::make_unique<CallLinkInfo>();
             
@@ -1065,9 +1101,10 @@
 
             done.link(&jit);
 
-            jit.addPtr(CCallHelpers::TrustedImm32((codeBlock->stackPointerOffset() * sizeof(Register)) - state.preservedReusedRegisterState.numberOfBytesPreserved - state.numberOfStackBytesUsedForRegisterPreservation()),
+            jit.addPtr(CCallHelpers::TrustedImm32((codeBlock->stackPointerOffset() * sizeof(Register)) - state.preservedReusedRegisterState.numberOfBytesPreserved - spillState.numberOfStackBytesUsedForRegisterPreservation),
                 GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
-            state.restoreLiveRegistersFromStackForCall(isGetter());
+            bool callHasReturnValue = isGetter();
+            restoreLiveRegistersFromStackForCall(spillState, callHasReturnValue);
 
             jit.addLinkTask(
                 [=, &vm] (LinkBuffer& linkBuffer) {
@@ -1127,11 +1164,12 @@
             CCallHelpers::Jump noException =
                 jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
 
-            state.restoreLiveRegistersFromStackForCallWithThrownException();
+            state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
             state.emitExplicitExceptionHandler();
         
             noException.link(&jit);
-            state.restoreLiveRegistersFromStackForCall(isGetter());
+            bool callHasReturnValue = isGetter();
+            restoreLiveRegistersFromStackForCall(spillState, callHasReturnValue);
         }
         state.succeed();
         return;
@@ -1248,7 +1286,7 @@
                 RegisterSet extraRegistersToPreserve;
                 extraRegistersToPreserve.set(baseGPR);
                 extraRegistersToPreserve.set(valueRegs);
-                state.preserveLiveRegistersToStackForCall(extraRegistersToPreserve);
+                AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall(extraRegistersToPreserve);
                 
                 jit.store32(
                     CCallHelpers::TrustedImm32(
@@ -1288,11 +1326,11 @@
                 CCallHelpers::Jump noException =
                     jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
                 
-                state.restoreLiveRegistersFromStackForCallWithThrownException();
+                state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
                 state.emitExplicitExceptionHandler();
                 
                 noException.link(&jit);
-                state.restoreLiveRegistersFromStackForCall();
+                state.restoreLiveRegistersFromStackForCall(spillState);
             }
         }
 
@@ -1385,6 +1423,124 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+void AccessCase::emitDOMJITGetter(AccessGenerationState& state, GPRReg baseForGetGPR)
+{
+    CCallHelpers& jit = *state.jit;
+    VM& vm = *jit.vm();
+    StructureStubInfo& stubInfo = *state.stubInfo;
+    JSValueRegs valueRegs = state.valueRegs;
+    GPRReg baseGPR = state.baseGPR;
+    GPRReg scratchGPR = state.scratchGPR;
+
+    // We construct the environment that can execute the DOMJIT::Patchpoint here.
+    Ref<DOMJIT::CallDOMPatchpoint> patchpoint = m_rareData->domJIT->callDOM();
+
+    Vector<GPRReg> gpScratch;
+    Vector<FPRReg> fpScratch;
+    Vector<DOMJIT::Value> regs;
+
+    ScratchRegisterAllocator allocator(stubInfo.patch.usedRegisters);
+    allocator.lock(baseGPR);
+#if USE(JSVALUE32_64)
+    allocator.lock(static_cast<GPRReg>(stubInfo.patch.baseTagGPR));
+#endif
+    allocator.lock(valueRegs);
+    allocator.lock(scratchGPR);
+
+    GPRReg paramBaseGPR = InvalidGPRReg;
+    GPRReg paramGlobalObjectGPR = InvalidGPRReg;
+    JSValueRegs paramValueRegs = valueRegs;
+    GPRReg remainingScratchGPR = InvalidGPRReg;
+
+    // valueRegs and baseForGetGPR may be the same. For example, in Baseline JIT, we pass the same regT0 for baseGPR and valueRegs.
+    // In FTL, there is no constraint that the baseForGetGPR interferes with the result. To make implementation simple in
+    // DOMJIT::Patchpoint, DOMJIT::Patchpoint assumes that result registers always early interfere with input registers, in this case,
+    // baseForGetGPR. So we move baseForGetGPR to the other register if baseForGetGPR == valueRegs.
+    if (baseForGetGPR != valueRegs.payloadGPR()) {
+        paramBaseGPR = baseForGetGPR;
+        if (!patchpoint->requireGlobalObject)
+            remainingScratchGPR = scratchGPR;
+        else
+            paramGlobalObjectGPR = scratchGPR;
+    } else {
+        jit.move(valueRegs.payloadGPR(), scratchGPR);
+        paramBaseGPR = scratchGPR;
+        if (patchpoint->requireGlobalObject)
+            paramGlobalObjectGPR = allocator.allocateScratchGPR();
+    }
+
+    JSGlobalObject* globalObjectForDOMJIT = structure()->globalObject();
+
+    regs.append(paramValueRegs);
+    if (patchpoint->requireGlobalObject) {
+        ASSERT(paramGlobalObjectGPR != InvalidGPRReg);
+        regs.append(DOMJIT::Value(paramGlobalObjectGPR, globalObjectForDOMJIT));
+    }
+    regs.append(paramBaseGPR);
+
+    if (patchpoint->numGPScratchRegisters) {
+        unsigned i = 0;
+        if (remainingScratchGPR != InvalidGPRReg) {
+            gpScratch.append(remainingScratchGPR);
+            ++i;
+        }
+        for (; i < patchpoint->numGPScratchRegisters; ++i)
+            gpScratch.append(allocator.allocateScratchGPR());
+    }
+
+    for (unsigned i = 0; i < patchpoint->numFPScratchRegisters; ++i)
+        fpScratch.append(allocator.allocateScratchFPR());
+
+    // Let's store the reused registers to the stack. After that, we can use allocated scratch registers.
+    ScratchRegisterAllocator::PreservedState preservedState =
+        allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
+
+    if (verbose) {
+        dataLog("baseGPR = ", baseGPR, "\n");
+        dataLog("valueRegs = ", valueRegs, "\n");
+        dataLog("scratchGPR = ", scratchGPR, "\n");
+        dataLog("paramBaseGPR = ", paramBaseGPR, "\n");
+        if (paramGlobalObjectGPR != InvalidGPRReg)
+            dataLog("paramGlobalObjectGPR = ", paramGlobalObjectGPR, "\n");
+        dataLog("paramValueRegs = ", paramValueRegs, "\n");
+        for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
+            dataLog("gpScratch[", i, "] = ", gpScratch[i], "\n");
+    }
+
+    if (patchpoint->requireGlobalObject)
+        jit.move(CCallHelpers::TrustedImmPtr(globalObjectForDOMJIT), paramGlobalObjectGPR);
+
+    // We just spill the registers used in DOMJIT::Patchpoint here. For not spilled registers here explicitly,
+    // they must be in the used register set passed by the callers (Baseline, DFG, and FTL) if they need to be kept.
+    // Some registers can be locked, but not in the used register set. For example, the caller could make baseGPR
+    // same to valueRegs, and not include it in the used registers since it will be changed.
+    RegisterSet registersToSpillForCCall;
+    for (auto& value : regs) {
+        DOMJIT::Reg reg = value.reg();
+        if (reg.isJSValueRegs())
+            registersToSpillForCCall.set(reg.jsValueRegs());
+        else if (reg.isGPR())
+            registersToSpillForCCall.set(reg.gpr());
+        else
+            registersToSpillForCCall.set(reg.fpr());
+    }
+    for (GPRReg reg : gpScratch)
+        registersToSpillForCCall.set(reg);
+    for (FPRReg reg : fpScratch)
+        registersToSpillForCCall.set(reg);
+    registersToSpillForCCall.exclude(RegisterSet::registersToNotSaveForCCall());
+
+    DOMJITAccessCasePatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+    patchpoint->generator()->run(jit, params);
+    allocator.restoreReusedRegistersByPopping(jit, preservedState);
+    state.succeed();
+
+    CCallHelpers::JumpList exceptions = params.emitSlowPathCalls(vm, state, registersToSpillForCCall, jit);
+    exceptions.link(&jit);
+    allocator.restoreReusedRegistersByPopping(jit, preservedState);
+    state.emitExplicitExceptionHandler();
+}
+
 PolymorphicAccess::PolymorphicAccess() { }
 PolymorphicAccess::~PolymorphicAccess() { }
 
@@ -1684,13 +1840,15 @@
         MacroAssembler::Label makeshiftCatchHandler = jit.label();
 
         int stackPointerOffset = codeBlock->stackPointerOffset() * sizeof(EncodedJSValue);
+        AccessGenerationState::SpillState spillStateForJSGetterSetter = state.spillStateForJSGetterSetter();
+        ASSERT(!spillStateForJSGetterSetter.isEmpty());
         stackPointerOffset -= state.preservedReusedRegisterState.numberOfBytesPreserved;
-        stackPointerOffset -= state.numberOfStackBytesUsedForRegisterPreservation();
+        stackPointerOffset -= spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation;
 
         jit.loadPtr(vm.addressOfCallFrameForCatch(), GPRInfo::callFrameRegister);
         jit.addPtr(CCallHelpers::TrustedImm32(stackPointerOffset), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
 
-        state.restoreLiveRegistersFromStackForCallWithThrownException();
+        state.restoreLiveRegistersFromStackForCallWithThrownException(spillStateForJSGetterSetter);
         state.restoreScratch();
         CCallHelpers::Jump jumpToOSRExitExceptionHandler = jit.jump();
 

Modified: trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h (207426 => 207427)


--- trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/bytecode/PolymorphicAccess.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -277,6 +277,7 @@
     
     void generateImpl(AccessGenerationState&);
     void emitIntrinsicGetter(AccessGenerationState&);
+    void emitDOMJITGetter(AccessGenerationState&, GPRReg baseForGetGPR);
     
     AccessType m_type { Load };
     State m_state { Primordial };
@@ -472,20 +473,22 @@
     void restoreScratch();
     void succeed();
 
-    void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra = RegisterSet());
+    struct SpillState {
+        RegisterSet spilledRegisters { };
+        unsigned numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
 
-    void preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
+        bool isEmpty() const { return numberOfStackBytesUsedForRegisterPreservation == std::numeric_limits<unsigned>::max(); }
+    };
 
-    void restoreLiveRegistersFromStackForCall(bool isGetter = false);
-    void restoreLiveRegistersFromStackForCallWithThrownException();
-    void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
+    const RegisterSet& calculateLiveRegistersForCallAndExceptionHandling();
 
-    const RegisterSet& liveRegistersForCall()
-    {
-        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
-        return m_liveRegistersForCall;
-    }
+    SpillState preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
 
+    void restoreLiveRegistersFromStackForCallWithThrownException(const SpillState&);
+    void restoreLiveRegistersFromStackForCall(const SpillState&, const RegisterSet& dontRestore = RegisterSet());
+
+    const RegisterSet& liveRegistersForCall();
+
     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
     CallSiteIndex callSiteIndexForExceptionHandling()
     {
@@ -495,29 +498,30 @@
         return m_callSiteIndex;
     }
 
-    const HandlerInfo& originalExceptionHandler() const;
-    unsigned numberOfStackBytesUsedForRegisterPreservation() const
-    {
-        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
-        return m_numberOfStackBytesUsedForRegisterPreservation;
-    }
+    const HandlerInfo& originalExceptionHandler();
 
     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
     CallSiteIndex originalCallSiteIndex() const;
     
     void emitExplicitExceptionHandler();
-    
-private:
-    const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
+
+    void setSpillStateForJSGetterSetter(SpillState& spillState)
     {
-        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
-        return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
+        if (!m_spillStateForJSGetterSetter.isEmpty()) {
+            ASSERT(m_spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation == spillState.numberOfStackBytesUsedForRegisterPreservation);
+            ASSERT(m_spillStateForJSGetterSetter.spilledRegisters == spillState.spilledRegisters);
+        }
+        m_spillStateForJSGetterSetter = spillState;
     }
+    SpillState spillStateForJSGetterSetter() const { return m_spillStateForJSGetterSetter; }
     
+private:
+    const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite();
+    
     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
     RegisterSet m_liveRegistersForCall;
     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
-    unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
+    SpillState m_spillStateForJSGetterSetter;
     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
     bool m_needsToRestoreRegistersIfException : 1;
     bool m_calculatedCallSiteIndex : 1;

Modified: trunk/Source/_javascript_Core/dfg/DFGDOMJITPatchpointParams.cpp (207426 => 207427)


--- trunk/Source/_javascript_Core/dfg/DFGDOMJITPatchpointParams.cpp	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/dfg/DFGDOMJITPatchpointParams.cpp	2016-10-17 20:43:43 UTC (rev 207427)
@@ -40,7 +40,7 @@
 }
 
 #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
-    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) const \
+    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \
     { \
         dispatch(m_jit, from, operation, result, args, std::make_index_sequence<std::tuple_size<decltype(args)>::value>()); \
     } \

Modified: trunk/Source/_javascript_Core/dfg/DFGDOMJITPatchpointParams.h (207426 => 207427)


--- trunk/Source/_javascript_Core/dfg/DFGDOMJITPatchpointParams.h	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/dfg/DFGDOMJITPatchpointParams.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -42,7 +42,7 @@
     }
 
 private:
-#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const override;
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) override;
     DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
 #undef JSC_DEFINE_CALL_OPERATIONS
 

Modified: trunk/Source/_javascript_Core/domjit/DOMJITPatchpoint.h (207426 => 207427)


--- trunk/Source/_javascript_Core/domjit/DOMJITPatchpoint.h	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/domjit/DOMJITPatchpoint.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -34,7 +34,7 @@
 
 class PatchpointParams;
 
-typedef CCallHelpers::JumpList PatchpointGeneratorFunction(CCallHelpers&, const PatchpointParams&);
+typedef CCallHelpers::JumpList PatchpointGeneratorFunction(CCallHelpers&, PatchpointParams&);
 typedef SharedTask<PatchpointGeneratorFunction> PatchpointGenerator;
 
 // DOMJIT patchpoint is the way to inject an opaque code generator into DFG and FTL.

Modified: trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h (207426 => 207427)


--- trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -55,13 +55,13 @@
     }
 
     template<typename FunctionType, typename ResultType, typename... Arguments>
-    void addSlowPathCall(CCallHelpers::JumpList from, CCallHelpers& jit, FunctionType function, ResultType result, Arguments... arguments) const
+    void addSlowPathCall(CCallHelpers::JumpList from, CCallHelpers& jit, FunctionType function, ResultType result, Arguments... arguments)
     {
         addSlowPathCallImpl(from, jit, function, result, std::make_tuple(arguments...));
     }
 
 private:
-#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) JS_EXPORT_PRIVATE virtual void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const = 0;
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) JS_EXPORT_PRIVATE virtual void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) = 0;
     DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
 #undef JSC_DEFINE_CALL_OPERATIONS
 

Modified: trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.cpp (207426 => 207427)


--- trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.cpp	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.cpp	2016-10-17 20:43:43 UTC (rev 207427)
@@ -50,7 +50,7 @@
 }
 
 #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
-    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) const \
+    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers& jit, OperationType operation, ResultType result, std::tuple<__VA_ARGS__> args) \
     { \
         dispatch(jit, &m_state, m_params, m_node, m_exceptions, from, operation, result, args, std::make_index_sequence<std::tuple_size<decltype(args)>::value>()); \
     } \

Modified: trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.h (207426 => 207427)


--- trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.h	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/ftl/FTLDOMJITPatchpointParams.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -46,7 +46,7 @@
     }
 
 private:
-#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) const override;
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&, OperationType, ResultType, std::tuple<__VA_ARGS__> args) override;
     DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
 #undef JSC_DEFINE_CALL_OPERATIONS
 

Modified: trunk/Source/_javascript_Core/jsc.cpp (207426 => 207427)


--- trunk/Source/_javascript_Core/jsc.cpp	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/_javascript_Core/jsc.cpp	2016-10-17 20:43:43 UTC (rev 207427)
@@ -557,6 +557,22 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
+#if ENABLE(JIT)
+    static Ref<DOMJIT::Patchpoint> checkDOMJITNode()
+    {
+        Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+        patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
+            CCallHelpers::JumpList failureCases;
+            failureCases.append(jit.branch8(
+                CCallHelpers::NotEqual,
+                CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
+                CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
+            return failureCases;
+        });
+        return patchpoint;
+    }
+#endif
+
     static DOMJITNode* create(VM& vm, Structure* structure)
     {
         DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
@@ -608,16 +624,7 @@
 #if ENABLE(JIT)
         Ref<DOMJIT::Patchpoint> checkDOM() override
         {
-            Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
-            patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
-                CCallHelpers::JumpList failureCases;
-                failureCases.append(jit.branch8(
-                    CCallHelpers::NotEqual,
-                    CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
-                    CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
-                return failureCases;
-            });
-            return patchpoint;
+            return DOMJITNode::checkDOMJITNode();
         }
 
         Ref<DOMJIT::CallDOMPatchpoint> callDOM() override
@@ -624,7 +631,7 @@
         {
             Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
             patchpoint->requireGlobalObject = false;
-            patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+            patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
                 JSValueRegs results = params[0].jsValueRegs();
                 GPRReg dom = params[1].gpr();
 
@@ -666,6 +673,115 @@
     }
 };
 
+class DOMJITGetterComplex : public DOMJITNode {
+public:
+    DOMJITGetterComplex(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+
+    DECLARE_INFO;
+    typedef DOMJITNode Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
+    }
+
+    static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+    {
+        DOMJITGetterComplex* getter = new (NotNull, allocateCell<DOMJITGetterComplex>(vm.heap, sizeof(DOMJITGetterComplex))) DOMJITGetterComplex(vm, structure);
+        getter->finishCreation(vm, globalObject);
+        return getter;
+    }
+
+    class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
+    public:
+        DOMJITNodeDOMJIT()
+            : DOMJIT::GetterSetter(DOMJITGetterComplex::customGetter, nullptr, DOMJITNode::info())
+        {
+        }
+
+#if ENABLE(JIT)
+        Ref<DOMJIT::Patchpoint> checkDOM() override
+        {
+            return DOMJITNode::checkDOMJITNode();
+        }
+
+        Ref<DOMJIT::CallDOMPatchpoint> callDOM() override
+        {
+            RefPtr<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
+            static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4.");
+            patchpoint->numGPScratchRegisters = GPRInfo::numberOfRegisters - 4;
+            patchpoint->numFPScratchRegisters = 3;
+            patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
+                JSValueRegs results = params[0].jsValueRegs();
+                GPRReg domGPR = params[2].gpr();
+                for (unsigned i = 0; i < patchpoint->numGPScratchRegisters; ++i)
+                    jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i));
+
+                params.addSlowPathCall(jit.jump(), jit, static_cast<EncodedJSValue(*)(ExecState*, void*)>([](ExecState* exec, void* pointer) {
+                    VM& vm = exec->vm();
+                    auto scope = DECLARE_THROW_SCOPE(vm);
+                    auto* object = static_cast<DOMJITNode*>(pointer);
+                    auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(object);
+                    if (domjitGetterComplex) {
+                        if (domjitGetterComplex->m_enableException)
+                            return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
+                    }
+                    return JSValue::encode(jsNumber(object->value()));
+                }), results, domGPR);
+                return CCallHelpers::JumpList();
+
+            });
+            return *patchpoint.get();
+        }
+#endif
+    };
+
+    static DOMJIT::GetterSetter* domJITNodeGetterSetter()
+    {
+        static NeverDestroyed<DOMJITNodeDOMJIT> graph;
+        return &graph.get();
+    }
+
+private:
+    void finishCreation(VM& vm, JSGlobalObject* globalObject)
+    {
+        Base::finishCreation(vm);
+        DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
+        CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
+        putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
+        putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "enableException"), 0, functionEnableException, NoIntrinsic, 0);
+    }
+
+    static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec)
+    {
+        auto* object = jsDynamicCast<DOMJITGetterComplex*>(exec->thisValue());
+        if (object)
+            object->m_enableException = true;
+        return JSValue::encode(jsUndefined());
+    }
+
+    static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
+    {
+        VM& vm = exec->vm();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+
+        auto* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
+        if (!thisObject)
+            return throwVMTypeError(exec, scope);
+        if (auto* domjitGetterComplex = jsDynamicCast<DOMJITGetterComplex*>(JSValue::decode(thisValue))) {
+            if (domjitGetterComplex->m_enableException)
+                return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("DOMJITGetterComplex slow call exception"))));
+        }
+        return JSValue::encode(jsNumber(thisObject->value()));
+    }
+
+    bool m_enableException { false };
+};
+
 const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
 const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
 const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
@@ -673,6 +789,7 @@
 const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
 const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITNode) };
 const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetter) };
+const ClassInfo DOMJITGetterComplex::s_info = { "DOMJITGetterComplex", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetterComplex) };
 const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
 const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
 static bool test262AsyncPassed { false };
@@ -703,6 +820,7 @@
 static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
@@ -990,6 +1108,7 @@
         addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
         addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
         addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
+        addFunction(vm, "createDOMJITGetterComplexObject", functionCreateDOMJITGetterComplexObject, 0);
         addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
         addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
         addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
@@ -1511,6 +1630,14 @@
     return JSValue::encode(result);
 }
 
+EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
+{
+    JSLockHolder lock(exec);
+    Structure* structure = DOMJITGetterComplex::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
+    DOMJITGetterComplex* result = DOMJITGetterComplex::create(exec->vm(), exec->lexicalGlobalObject(), structure);
+    return JSValue::encode(result);
+}
+
 EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
 {
     JSLockHolder lock(exec);

Modified: trunk/Source/WebCore/ChangeLog (207426 => 207427)


--- trunk/Source/WebCore/ChangeLog	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/WebCore/ChangeLog	2016-10-17 20:43:43 UTC (rev 207427)
@@ -1,3 +1,19 @@
+2016-10-17  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [DOMJIT] Use DOMJIT::Patchpoint in IC
+        https://bugs.webkit.org/show_bug.cgi?id=163223
+
+        Reviewed by Saam Barati.
+
+        Make DOMJITPatchpointParams non-const.
+
+        * domjit/DOMJITHelpers.h:
+        (WebCore::DOMJITHelpers::toWrapper):
+        * domjit/JSNodeDOMJIT.cpp:
+        (WebCore::createCallDOMForOffsetAccess):
+        (WebCore::checkNode):
+        (WebCore::NodeNodeTypeDOMJIT::callDOM):
+
 2016-10-17  Chris Dumez  <cdu...@apple.com>
 
         Move form.reportValidity() behind InteractiveFormValidation setting

Modified: trunk/Source/WebCore/domjit/DOMJITHelpers.h (207426 => 207427)


--- trunk/Source/WebCore/domjit/DOMJITHelpers.h	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/WebCore/domjit/DOMJITHelpers.h	2016-10-17 20:43:43 UTC (rev 207427)
@@ -59,7 +59,7 @@
 }
 
 template<typename WrappedType, typename ToJSFunction>
-void toWrapper(CCallHelpers& jit, const JSC::DOMJIT::PatchpointParams& params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant)
+void toWrapper(CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant)
 {
     ASSERT(wrapped != result.payloadGPR());
     ASSERT(globalObject != result.payloadGPR());

Modified: trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp (207426 => 207427)


--- trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp	2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp	2016-10-17 20:43:43 UTC (rev 207427)
@@ -54,7 +54,7 @@
 {
     Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
     patchpoint->numGPScratchRegisters = 1;
-    patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
         JSValueRegs result = params[0].jsValueRegs();
         GPRReg globalObject = params[1].gpr();
         GPRReg node = params[2].gpr();
@@ -84,7 +84,7 @@
 static Ref<DOMJIT::Patchpoint> checkNode()
 {
     Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
-    patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
         CCallHelpers::JumpList failureCases;
         failureCases.append(DOMJITHelpers::branchIfNotNode(jit, params[0].gpr()));
         return failureCases;
@@ -157,7 +157,7 @@
 {
     Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
     patchpoint->requireGlobalObject = false;
-    patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+    patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
         JSValueRegs result = params[0].jsValueRegs();
         GPRReg node = params[1].gpr();
         jit.load8(CCallHelpers::Address(node, JSC::JSCell::typeInfoTypeOffset()), result.payloadGPR());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to