<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[207427] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/207427">207427</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2016-10-17 13:43:43 -0700 (Mon, 17 Oct 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[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/JavaScriptCore:

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:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/DOMJITAccessCasePatchpointParams.cpp: Added.
(JSC::SlowPathCallGeneratorWithArguments::SlowPathCallGeneratorWithArguments):
(JSC::SlowPathCallGeneratorWithArguments::generateImpl):
(JSC::DOMJITAccessCasePatchpointParams::emitSlowPathCalls):
* bytecode/DOMJITAccessCasePatchpointParams.h: Copied from Source/JavaScriptCore/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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp">trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePolymorphicAccessh">trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDOMJITPatchpointParamscpp">trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDOMJITPatchpointParamsh">trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredomjitDOMJITPatchpointh">trunk/Source/JavaScriptCore/domjit/DOMJITPatchpoint.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredomjitDOMJITPatchpointParamsh">trunk/Source/JavaScriptCore/domjit/DOMJITPatchpointParams.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLDOMJITPatchpointParamscpp">trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLDOMJITPatchpointParamsh">trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomjitDOMJITHelpersh">trunk/Source/WebCore/domjit/DOMJITHelpers.h</a></li>
<li><a href="#trunkSourceWebCoredomjitJSNodeDOMJITcpp">trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressdomjitexceptionicjs">trunk/JSTests/stress/domjit-exception-ic.js</a></li>
<li><a href="#trunkJSTestsstressdomjitexceptionjs">trunk/JSTests/stress/domjit-exception.js</a></li>
<li><a href="#trunkJSTestsstressdomjitgettercomplexwithincorrectobjectjs">trunk/JSTests/stress/domjit-getter-complex-with-incorrect-object.js</a></li>
<li><a href="#trunkJSTestsstressdomjitgettercomplexjs">trunk/JSTests/stress/domjit-getter-complex.js</a></li>
<li><a href="#trunkJSTestsstressdomjitgettertrycatchgetterasgetbyidregisterrestorationjs">trunk/JSTests/stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeDOMJITAccessCasePatchpointParamscpp">trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeDOMJITAccessCasePatchpointParamsh">trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/JSTests/ChangeLog        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2016-10-17  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        [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):
+
</ins><span class="cx"> 2016-10-15  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Assertion failed under operationToLowerCase with a rope with zero length
</span></span></pre></div>
<a id="trunkJSTestsstressdomjitexceptionicjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/domjit-exception-ic.js (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+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 &lt; 1e4; ++i) {
+        shouldBe(access(domjit), 42);
+        shouldBe(access(normal), 42);
+    }
+    domjit.enableException();
+    shouldThrow(() =&gt; access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
</ins></span></pre></div>
<a id="trunkJSTestsstressdomjitexceptionjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/domjit-exception.js (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/domjit-exception.js                                (rev 0)
+++ trunk/JSTests/stress/domjit-exception.js        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+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 &lt; 1e4; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() =&gt; access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (let i = 0; i &lt; 1e2; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() =&gt; access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (let i = 0; i &lt; 50; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() =&gt; access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
+(function () {
+    let domjit = createDOMJITGetterComplexObject();
+    function access(object)
+    {
+        return object.customGetter;
+    }
+    noInline(access);
+    for (let i = 0; i &lt; 10; ++i)
+        shouldBe(access(domjit), 42);
+    domjit.enableException();
+    shouldThrow(() =&gt; access(domjit), `Error: DOMJITGetterComplex slow call exception`);
+}());
</ins></span></pre></div>
<a id="trunkJSTestsstressdomjitgettercomplexwithincorrectobjectjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/domjit-getter-complex-with-incorrect-object.js (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+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 &lt; 1e4; ++i) {
+    shouldThrow(() =&gt; {
+        access(object);
+    }, `TypeError: Type error`);
+}
</ins></span></pre></div>
<a id="trunkJSTestsstressdomjitgettercomplexjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/domjit-getter-complex.js (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+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 &lt; 1e4; ++i) {
+    shouldBe(access(complex), 42);
+}
</ins></span></pre></div>
<a id="trunkJSTestsstressdomjitgettertrycatchgetterasgetbyidregisterrestorationjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/domjit-getter-try-catch-getter-as-get-by-id-register-restoration.js (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+function assert(b) {
+    if (!b) throw new Error(&quot;bad value&quot;);
+}
+noInline(assert);
+
+let i;
+var o1 = createDOMJITGetterComplexObject();
+o1.x = &quot;x&quot;;
+
+var o2 = {
+    customGetter: 40
+}
+
+var o3 = {
+    x: 100,
+    customGetter: &quot;f&quot;
+}
+
+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 === &quot;x&quot;);
+        assert(o === o1);
+    }
+}
+noInline(foo);
+
+foo(i);
+for (i = 0; i &lt; 1000; i++)
+    foo(i);
+
+o1.enableException();
+i = -1000;
+for (let j = 0; j &lt; 1000; j++)
+    foo(i);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -204,6 +204,7 @@
</span><span class="cx">     bytecode/ComplexGetStatus.cpp
</span><span class="cx">     bytecode/DataFormat.cpp
</span><span class="cx">     bytecode/DFGExitProfile.cpp
</span><ins>+    bytecode/DOMJITAccessCasePatchpointParams.cpp
</ins><span class="cx">     bytecode/DeferredCompilationCallback.cpp
</span><span class="cx">     bytecode/DeferredSourceDump.cpp
</span><span class="cx">     bytecode/ExecutionCounter.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -1,3 +1,74 @@
</span><ins>+2016-10-17  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        [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:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/DOMJITAccessCasePatchpointParams.cpp: Added.
+        (JSC::SlowPathCallGeneratorWithArguments::SlowPathCallGeneratorWithArguments):
+        (JSC::SlowPathCallGeneratorWithArguments::generateImpl):
+        (JSC::DOMJITAccessCasePatchpointParams::emitSlowPathCalls):
+        * bytecode/DOMJITAccessCasePatchpointParams.h: Copied from Source/JavaScriptCore/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):
+
</ins><span class="cx"> 2016-10-17  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Build fix for HasOwnPropertyCache::Entry caused slowdown by introducing a constructor that doesn't use move semantics for the RefPtr&lt;UniquedStringImpl&gt; parameter
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -2114,6 +2114,8 @@
</span><span class="cx">                 E39DA4A61B7E8B7C0084F33A /* JSModuleRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */; };
</span><span class="cx">                 E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 E3A421431D6F58930007C617 /* PreciseJumpTargetsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */; };
+                E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */; };
</ins><span class="cx">                 E3C08E3C1DA41B810039478F /* DOMJITPatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 E3D239C81B829C1C00BBEF67 /* JSModuleEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */; };
</span><span class="cx">                 E3D239C91B829C1C00BBEF67 /* JSModuleEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D239C71B829C1C00BBEF67 /* JSModuleEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -4423,6 +4425,8 @@
</span><span class="cx">                 E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreciseJumpTargetsInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMJITAccessCasePatchpointParams.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAccessCasePatchpointParams.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpoint.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E3CB1E241DA7540A00FA1E56 /* DOMJITSlowPathCalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITSlowPathCalls.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleEnvironment.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -6824,6 +6828,8 @@
</span><span class="cx">                                 0F0B83A514BCF50400885B4F /* CodeType.h */,
</span><span class="cx">                                 0F6FC74E196110A800E1D02D /* ComplexGetStatus.cpp */,
</span><span class="cx">                                 0F6FC74F196110A800E1D02D /* ComplexGetStatus.h */,
</span><ins>+                                E3BFD0B91DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.cpp */,
+                                E3BFD0BA1DAF807C0065DEA2 /* DOMJITAccessCasePatchpointParams.h */,
</ins><span class="cx">                                 62E3D5EF1B8D0B7300B868BB /* DataFormat.cpp */,
</span><span class="cx">                                 0F426A4A1460CD6B00131F8F /* DataFormat.h */,
</span><span class="cx">                                 0FC712DC17CD8778008CC93C /* DeferredCompilationCallback.cpp */,
</span><span class="lines">@@ -7526,6 +7532,7 @@
</span><span class="cx">                                 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */,
</span><span class="cx">                                 86EC9DC51328DF82002B2AD7 /* DFGByteCodeParser.h in Headers */,
</span><span class="cx">                                 0F256C361627B0AD007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h in Headers */,
</span><ins>+                                E3BFD0BC1DAF808E0065DEA2 /* DOMJITAccessCasePatchpointParams.h in Headers */,
</ins><span class="cx">                                 0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */,
</span><span class="cx">                                 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */,
</span><span class="cx">                                 0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */,
</span><span class="lines">@@ -9422,6 +9429,7 @@
</span><span class="cx">                                 E35E035F1B7AB43E0073AD2A /* InspectorInstrumentationObject.cpp in Sources */,
</span><span class="cx">                                 A532438B18568335002ED692 /* InspectorProtocolObjects.cpp in Sources */,
</span><span class="cx">                                 A50E4B6118809DD50068A46D /* InspectorRuntimeAgent.cpp in Sources */,
</span><ins>+                                E3BFD0BB1DAF80870065DEA2 /* DOMJITAccessCasePatchpointParams.cpp in Sources */,
</ins><span class="cx">                                 A593CF821840377100BFCE27 /* InspectorValues.cpp in Sources */,
</span><span class="cx">                                 147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */,
</span><span class="cx">                                 1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeDOMJITAccessCasePatchpointParamscpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.cpp (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.cpp        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -0,0 +1,127 @@
</span><ins>+/*
+ * 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 &quot;config.h&quot;
+#include &quot;DOMJITAccessCasePatchpointParams.h&quot;
+
+#include &quot;LinkBuffer.h&quot;
+#include &quot;PolymorphicAccess.h&quot;
+#include &quot;StructureStubInfo.h&quot;
+
+#if ENABLE(JIT)
+
+namespace JSC {
+
+template&lt;typename JumpType, typename FunctionType, typename ResultType, typename... Arguments&gt;
+class SlowPathCallGeneratorWithArguments : public DOMJITAccessCasePatchpointParams::SlowPathCallGenerator {
+public:
+    SlowPathCallGeneratorWithArguments(JumpType from, CCallHelpers::Label to, FunctionType function, ResultType result, std::tuple&lt;Arguments...&gt; arguments)
+        : m_from(from)
+        , m_to(to)
+        , m_function(function)
+        , m_result(result)
+        , m_arguments(arguments)
+    {
+    }
+
+    template&lt;size_t... ArgumentsIndex&gt;
+    CCallHelpers::JumpList generateImpl(VM&amp; vm, AccessGenerationState&amp; state, const RegisterSet&amp; usedRegistersByPatchpoint, CCallHelpers&amp; jit, std::index_sequence&lt;ArgumentsIndex...&gt;)
+    {
+        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&lt;VirtualRegister&gt;(CallFrameSlot::argumentCount)));
+
+        jit.makeSpaceOnStackForCCall();
+
+        jit.storePtr(GPRInfo::callFrameRegister, &amp;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&lt;ArgumentsIndex&gt;(m_arguments)...);
+
+        CCallHelpers::Call operationCall = jit.call();
+        auto function = m_function;
+        jit.addLinkTask([=] (LinkBuffer&amp; 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(&amp;jit);
+        RegisterSet dontRestore;
+        dontRestore.set(m_result);
+        state.restoreLiveRegistersFromStackForCall(spillState, dontRestore);
+
+        return exceptions;
+    }
+
+    CCallHelpers::JumpList generate(VM&amp; vm, AccessGenerationState&amp; state, const RegisterSet&amp; usedRegistersByPatchpoint, CCallHelpers&amp; jit) override
+    {
+        m_from.link(&amp;jit);
+        CCallHelpers::JumpList exceptions = generateImpl(vm, state, usedRegistersByPatchpoint, jit, std::make_index_sequence&lt;std::tuple_size&lt;std::tuple&lt;Arguments...&gt;&gt;::value&gt;());
+        jit.jump().linkTo(m_to, &amp;jit);
+        return exceptions;
+    }
+
+protected:
+    JumpType m_from;
+    CCallHelpers::Label m_to;
+    FunctionType m_function;
+    ResultType m_result;
+    std::tuple&lt;Arguments...&gt; m_arguments;
+};
+
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
+    void DOMJITAccessCasePatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&amp; jit, OperationType operation, ResultType result, std::tuple&lt;__VA_ARGS__&gt; args) \
+    { \
+        CCallHelpers::Label to = jit.label(); \
+        m_generators.append(std::make_unique&lt;SlowPathCallGeneratorWithArguments&lt;CCallHelpers::JumpList, OperationType, ResultType, __VA_ARGS__&gt;&gt;(from, to, operation, result, args)); \
+    } \
+
+DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
+#undef JSC_DEFINE_CALL_OPERATIONS
+
+CCallHelpers::JumpList DOMJITAccessCasePatchpointParams::emitSlowPathCalls(VM&amp; vm, AccessGenerationState&amp; state, const RegisterSet&amp; usedRegistersByPatchpoint, CCallHelpers&amp; jit)
+{
+    CCallHelpers::JumpList exceptions;
+    for (auto&amp; generator : m_generators)
+        exceptions.append(generator-&gt;generate(vm, state, usedRegistersByPatchpoint, jit));
+    return exceptions;
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeDOMJITAccessCasePatchpointParamshfromrev207426trunkSourceJavaScriptCoreftlFTLDOMJITPatchpointParamsh"></a>
<div class="copfile"><h4>Copied: trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.h (from rev 207426, trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h) (0 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/DOMJITAccessCasePatchpointParams.h        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+/*
+ * 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 &quot;DOMJITPatchpointParams.h&quot;
+
+namespace JSC {
+
+struct AccessGenerationState;
+
+class DOMJITAccessCasePatchpointParams : public DOMJIT::PatchpointParams {
+public:
+    DOMJITAccessCasePatchpointParams(Vector&lt;DOMJIT::Value&gt;&amp;&amp; regs, Vector&lt;GPRReg&gt;&amp;&amp; gpScratch, Vector&lt;FPRReg&gt;&amp;&amp; fpScratch)
+        : DOMJIT::PatchpointParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch))
+    {
+    }
+
+    class SlowPathCallGenerator {
+    public:
+        virtual ~SlowPathCallGenerator() { }
+        virtual CCallHelpers::JumpList generate(VM&amp;, AccessGenerationState&amp;, const RegisterSet&amp; usedRegistersByPatchpoint, CCallHelpers&amp;) = 0;
+    };
+
+    CCallHelpers::JumpList emitSlowPathCalls(VM&amp;, AccessGenerationState&amp;, const RegisterSet&amp; usedRegistersByPatchpoint, CCallHelpers&amp;);
+
+private:
+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) override;
+    DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
+#undef JSC_DEFINE_CALL_OPERATIONS
+    Vector&lt;std::unique_ptr&lt;SlowPathCallGenerator&gt;&gt; m_generators;
+};
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -31,6 +31,8 @@
</span><span class="cx"> #include &quot;BinarySwitch.h&quot;
</span><span class="cx"> #include &quot;CCallHelpers.h&quot;
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><ins>+#include &quot;DOMJITAccessCasePatchpointParams.h&quot;
+#include &quot;DOMJITCallDOMPatchpoint.h&quot;
</ins><span class="cx"> #include &quot;DirectArguments.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><span class="cx"> #include &quot;Heap.h&quot;
</span><span class="lines">@@ -72,8 +74,29 @@
</span><span class="cx">     success.append(jit-&gt;jump());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet&amp; extra)
</del><ins>+const RegisterSet&amp; AccessGenerationState::liveRegistersForCall()
</ins><span class="cx"> {
</span><ins>+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
+    return m_liveRegistersForCall;
+}
+
+const RegisterSet&amp; AccessGenerationState::liveRegistersToPreserveAtExceptionHandlingCallSite()
+{
+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
+    return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
+}
+
+static RegisterSet calleeSaveRegisters()
+{
+    RegisterSet result = RegisterSet::registersToNotSaveForJSCall();
+    result.filter(RegisterSet::registersToNotSaveForCCall());
+    return result;
+}
+
+const RegisterSet&amp; AccessGenerationState::calculateLiveRegistersForCallAndExceptionHandling()
+{
</ins><span class="cx">     if (!m_calculatedRegistersForCallAndExceptionHandling) {
</span><span class="cx">         m_calculatedRegistersForCallAndExceptionHandling = true;
</span><span class="cx"> 
</span><span class="lines">@@ -83,36 +106,26 @@
</span><span class="cx">             RELEASE_ASSERT(JITCode::isOptimizingJIT(jit-&gt;codeBlock()-&gt;jitType()));
</span><span class="cx"> 
</span><span class="cx">         m_liveRegistersForCall = RegisterSet(m_liveRegistersToPreserveAtExceptionHandlingCallSite, allocator-&gt;usedRegisters());
</span><del>-        m_liveRegistersForCall.merge(extra);
-        m_liveRegistersForCall.exclude(RegisterSet::registersToNotSaveForJSCall());
-        m_liveRegistersForCall.merge(extra);
</del><ins>+        m_liveRegistersForCall.exclude(calleeSaveRegisters());
</ins><span class="cx">     }
</span><ins>+    return m_liveRegistersForCall;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AccessGenerationState::preserveLiveRegistersToStackForCall(const RegisterSet&amp; extra)
</del><ins>+auto AccessGenerationState::preserveLiveRegistersToStackForCall(const RegisterSet&amp; extra) -&gt; SpillState
</ins><span class="cx"> {
</span><del>-    calculateLiveRegistersForCallAndExceptionHandling(extra);
</del><ins>+    RegisterSet liveRegisters = liveRegistersForCall();
+    liveRegisters.merge(extra);
</ins><span class="cx">     
</span><span class="cx">     unsigned extraStackPadding = 0;
</span><del>-    unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegistersForCall(), extraStackPadding);
-    if (m_numberOfStackBytesUsedForRegisterPreservation != std::numeric_limits&lt;unsigned&gt;::max())
-        RELEASE_ASSERT(numberOfStackBytesUsedForRegisterPreservation == m_numberOfStackBytesUsedForRegisterPreservation);
-    m_numberOfStackBytesUsedForRegisterPreservation = numberOfStackBytesUsedForRegisterPreservation;
</del><ins>+    unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(*jit, liveRegisters, extraStackPadding);
+    return SpillState {
+        liveRegisters,
+        numberOfStackBytesUsedForRegisterPreservation
+    };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AccessGenerationState::restoreLiveRegistersFromStackForCall(bool isGetter)
</del><ins>+void AccessGenerationState::restoreLiveRegistersFromStackForCallWithThrownException(const SpillState&amp; spillState)
</ins><span class="cx"> {
</span><del>-    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()
-{
</del><span class="cx">     // Even if we're a getter, we don't want to ignore the result value like we normally do
</span><span class="cx">     // because the getter threw, and therefore, didn't return a value that means anything.
</span><span class="cx">     // Instead, we want to restore that register to what it was upon entering the getter
</span><span class="lines">@@ -119,7 +132,7 @@
</span><span class="cx">     // inline cache. The subtlety here is if the base and the result are the same register,
</span><span class="cx">     // and the getter threw, we want OSR exit to see the original base value, not the result
</span><span class="cx">     // of the getter call.
</span><del>-    RegisterSet dontRestore = liveRegistersForCall();
</del><ins>+    RegisterSet dontRestore = spillState.spilledRegisters;
</ins><span class="cx">     // As an optimization here, we only need to restore what is live for exception handling.
</span><span class="cx">     // We can construct the dontRestore set to accomplish this goal by having it contain only
</span><span class="cx">     // what is live for call but not live for exception handling. By ignoring things that are
</span><span class="lines">@@ -126,18 +139,19 @@
</span><span class="cx">     // only live at the call but not the exception handler, we will only restore things live
</span><span class="cx">     // at the exception handler.
</span><span class="cx">     dontRestore.exclude(liveRegistersToPreserveAtExceptionHandlingCallSite());
</span><del>-    restoreLiveRegistersFromStackForCall(dontRestore);
</del><ins>+    restoreLiveRegistersFromStackForCall(spillState, dontRestore);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AccessGenerationState::restoreLiveRegistersFromStackForCall(const RegisterSet&amp; dontRestore)
</del><ins>+void AccessGenerationState::restoreLiveRegistersFromStackForCall(const SpillState&amp; spillState, const RegisterSet&amp; dontRestore)
</ins><span class="cx"> {
</span><span class="cx">     unsigned extraStackPadding = 0;
</span><del>-    ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, liveRegistersForCall(), dontRestore, m_numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
</del><ins>+    ScratchRegisterAllocator::restoreRegistersFromStackForCall(*jit, spillState.spilledRegisters, dontRestore, spillState.numberOfStackBytesUsedForRegisterPreservation, extraStackPadding);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CallSiteIndex AccessGenerationState::callSiteIndexForExceptionHandlingOrOriginal()
</span><span class="cx"> {
</span><del>-    RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
</del><ins>+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
</ins><span class="cx"> 
</span><span class="cx">     if (!m_calculatedCallSiteIndex) {
</span><span class="cx">         m_calculatedCallSiteIndex = true;
</span><span class="lines">@@ -151,8 +165,11 @@
</span><span class="cx">     return m_callSiteIndex;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-const HandlerInfo&amp; AccessGenerationState::originalExceptionHandler() const
</del><ins>+const HandlerInfo&amp; AccessGenerationState::originalExceptionHandler()
</ins><span class="cx"> {
</span><ins>+    if (!m_calculatedRegistersForCallAndExceptionHandling)
+        calculateLiveRegistersForCallAndExceptionHandling();
+
</ins><span class="cx">     RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
</span><span class="cx">     HandlerInfo* exceptionHandler = jit-&gt;codeBlock()-&gt;handlerForIndex(stubInfo-&gt;callSiteIndex.bits());
</span><span class="cx">     RELEASE_ASSERT(exceptionHandler);
</span><span class="lines">@@ -932,6 +949,16 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (m_type == CustomAccessorGetter &amp;&amp; m_rareData-&gt;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()-&gt;classInfo()-&gt;isSubClassOf(m_rareData-&gt;domJIT-&gt;thisClassInfo())) {
+                emitDOMJITGetter(state, baseForGetGPR);
+                return;
+            }
+        }
+
</ins><span class="cx">         // Stuff for custom getters/setters.
</span><span class="cx">         CCallHelpers::Call operationCall;
</span><span class="cx"> 
</span><span class="lines">@@ -940,13 +967,20 @@
</span><span class="cx">         CCallHelpers::Call fastPathCall;
</span><span class="cx">         CCallHelpers::Call slowPathCall;
</span><span class="cx"> 
</span><del>-        CCallHelpers::Jump success;
-        CCallHelpers::Jump fail;
-
</del><span class="cx">         // This also does the necessary calculations of whether or not we're an
</span><span class="cx">         // exception handling call site.
</span><del>-        state.preserveLiveRegistersToStackForCall();
</del><ins>+        AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall();
</ins><span class="cx"> 
</span><ins>+        auto restoreLiveRegistersFromStackForCall = [&amp;](AccessGenerationState::SpillState&amp; 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);
+        };
+
</ins><span class="cx">         jit.store32(
</span><span class="cx">             CCallHelpers::TrustedImm32(state.callSiteIndexForExceptionHandlingOrOriginal().bits()),
</span><span class="cx">             CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(CallFrameSlot::argumentCount)));
</span><span class="lines">@@ -966,6 +1000,8 @@
</span><span class="cx">             // Therefore, we temporarily grow the stack for the purpose of the call and then
</span><span class="cx">             // shrink it after.
</span><span class="cx"> 
</span><ins>+            state.setSpillStateForJSGetterSetter(spillState);
+
</ins><span class="cx">             RELEASE_ASSERT(!m_rareData-&gt;callLinkInfo);
</span><span class="cx">             m_rareData-&gt;callLinkInfo = std::make_unique&lt;CallLinkInfo&gt;();
</span><span class="cx">             
</span><span class="lines">@@ -1065,9 +1101,10 @@
</span><span class="cx"> 
</span><span class="cx">             done.link(&amp;jit);
</span><span class="cx"> 
</span><del>-            jit.addPtr(CCallHelpers::TrustedImm32((codeBlock-&gt;stackPointerOffset() * sizeof(Register)) - state.preservedReusedRegisterState.numberOfBytesPreserved - state.numberOfStackBytesUsedForRegisterPreservation()),
</del><ins>+            jit.addPtr(CCallHelpers::TrustedImm32((codeBlock-&gt;stackPointerOffset() * sizeof(Register)) - state.preservedReusedRegisterState.numberOfBytesPreserved - spillState.numberOfStackBytesUsedForRegisterPreservation),
</ins><span class="cx">                 GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
</span><del>-            state.restoreLiveRegistersFromStackForCall(isGetter());
</del><ins>+            bool callHasReturnValue = isGetter();
+            restoreLiveRegistersFromStackForCall(spillState, callHasReturnValue);
</ins><span class="cx"> 
</span><span class="cx">             jit.addLinkTask(
</span><span class="cx">                 [=, &amp;vm] (LinkBuffer&amp; linkBuffer) {
</span><span class="lines">@@ -1127,11 +1164,12 @@
</span><span class="cx">             CCallHelpers::Jump noException =
</span><span class="cx">                 jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
</span><span class="cx"> 
</span><del>-            state.restoreLiveRegistersFromStackForCallWithThrownException();
</del><ins>+            state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
</ins><span class="cx">             state.emitExplicitExceptionHandler();
</span><span class="cx">         
</span><span class="cx">             noException.link(&amp;jit);
</span><del>-            state.restoreLiveRegistersFromStackForCall(isGetter());
</del><ins>+            bool callHasReturnValue = isGetter();
+            restoreLiveRegistersFromStackForCall(spillState, callHasReturnValue);
</ins><span class="cx">         }
</span><span class="cx">         state.succeed();
</span><span class="cx">         return;
</span><span class="lines">@@ -1248,7 +1286,7 @@
</span><span class="cx">                 RegisterSet extraRegistersToPreserve;
</span><span class="cx">                 extraRegistersToPreserve.set(baseGPR);
</span><span class="cx">                 extraRegistersToPreserve.set(valueRegs);
</span><del>-                state.preserveLiveRegistersToStackForCall(extraRegistersToPreserve);
</del><ins>+                AccessGenerationState::SpillState spillState = state.preserveLiveRegistersToStackForCall(extraRegistersToPreserve);
</ins><span class="cx">                 
</span><span class="cx">                 jit.store32(
</span><span class="cx">                     CCallHelpers::TrustedImm32(
</span><span class="lines">@@ -1288,11 +1326,11 @@
</span><span class="cx">                 CCallHelpers::Jump noException =
</span><span class="cx">                     jit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
</span><span class="cx">                 
</span><del>-                state.restoreLiveRegistersFromStackForCallWithThrownException();
</del><ins>+                state.restoreLiveRegistersFromStackForCallWithThrownException(spillState);
</ins><span class="cx">                 state.emitExplicitExceptionHandler();
</span><span class="cx">                 
</span><span class="cx">                 noException.link(&amp;jit);
</span><del>-                state.restoreLiveRegistersFromStackForCall();
</del><ins>+                state.restoreLiveRegistersFromStackForCall(spillState);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1385,6 +1423,124 @@
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AccessCase::emitDOMJITGetter(AccessGenerationState&amp; state, GPRReg baseForGetGPR)
+{
+    CCallHelpers&amp; jit = *state.jit;
+    VM&amp; vm = *jit.vm();
+    StructureStubInfo&amp; 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&lt;DOMJIT::CallDOMPatchpoint&gt; patchpoint = m_rareData-&gt;domJIT-&gt;callDOM();
+
+    Vector&lt;GPRReg&gt; gpScratch;
+    Vector&lt;FPRReg&gt; fpScratch;
+    Vector&lt;DOMJIT::Value&gt; regs;
+
+    ScratchRegisterAllocator allocator(stubInfo.patch.usedRegisters);
+    allocator.lock(baseGPR);
+#if USE(JSVALUE32_64)
+    allocator.lock(static_cast&lt;GPRReg&gt;(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-&gt;requireGlobalObject)
+            remainingScratchGPR = scratchGPR;
+        else
+            paramGlobalObjectGPR = scratchGPR;
+    } else {
+        jit.move(valueRegs.payloadGPR(), scratchGPR);
+        paramBaseGPR = scratchGPR;
+        if (patchpoint-&gt;requireGlobalObject)
+            paramGlobalObjectGPR = allocator.allocateScratchGPR();
+    }
+
+    JSGlobalObject* globalObjectForDOMJIT = structure()-&gt;globalObject();
+
+    regs.append(paramValueRegs);
+    if (patchpoint-&gt;requireGlobalObject) {
+        ASSERT(paramGlobalObjectGPR != InvalidGPRReg);
+        regs.append(DOMJIT::Value(paramGlobalObjectGPR, globalObjectForDOMJIT));
+    }
+    regs.append(paramBaseGPR);
+
+    if (patchpoint-&gt;numGPScratchRegisters) {
+        unsigned i = 0;
+        if (remainingScratchGPR != InvalidGPRReg) {
+            gpScratch.append(remainingScratchGPR);
+            ++i;
+        }
+        for (; i &lt; patchpoint-&gt;numGPScratchRegisters; ++i)
+            gpScratch.append(allocator.allocateScratchGPR());
+    }
+
+    for (unsigned i = 0; i &lt; patchpoint-&gt;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(&quot;baseGPR = &quot;, baseGPR, &quot;\n&quot;);
+        dataLog(&quot;valueRegs = &quot;, valueRegs, &quot;\n&quot;);
+        dataLog(&quot;scratchGPR = &quot;, scratchGPR, &quot;\n&quot;);
+        dataLog(&quot;paramBaseGPR = &quot;, paramBaseGPR, &quot;\n&quot;);
+        if (paramGlobalObjectGPR != InvalidGPRReg)
+            dataLog(&quot;paramGlobalObjectGPR = &quot;, paramGlobalObjectGPR, &quot;\n&quot;);
+        dataLog(&quot;paramValueRegs = &quot;, paramValueRegs, &quot;\n&quot;);
+        for (unsigned i = 0; i &lt; patchpoint-&gt;numGPScratchRegisters; ++i)
+            dataLog(&quot;gpScratch[&quot;, i, &quot;] = &quot;, gpScratch[i], &quot;\n&quot;);
+    }
+
+    if (patchpoint-&gt;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&amp; 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-&gt;generator()-&gt;run(jit, params);
+    allocator.restoreReusedRegistersByPopping(jit, preservedState);
+    state.succeed();
+
+    CCallHelpers::JumpList exceptions = params.emitSlowPathCalls(vm, state, registersToSpillForCCall, jit);
+    exceptions.link(&amp;jit);
+    allocator.restoreReusedRegistersByPopping(jit, preservedState);
+    state.emitExplicitExceptionHandler();
+}
+
</ins><span class="cx"> PolymorphicAccess::PolymorphicAccess() { }
</span><span class="cx"> PolymorphicAccess::~PolymorphicAccess() { }
</span><span class="cx"> 
</span><span class="lines">@@ -1684,13 +1840,15 @@
</span><span class="cx">         MacroAssembler::Label makeshiftCatchHandler = jit.label();
</span><span class="cx"> 
</span><span class="cx">         int stackPointerOffset = codeBlock-&gt;stackPointerOffset() * sizeof(EncodedJSValue);
</span><ins>+        AccessGenerationState::SpillState spillStateForJSGetterSetter = state.spillStateForJSGetterSetter();
+        ASSERT(!spillStateForJSGetterSetter.isEmpty());
</ins><span class="cx">         stackPointerOffset -= state.preservedReusedRegisterState.numberOfBytesPreserved;
</span><del>-        stackPointerOffset -= state.numberOfStackBytesUsedForRegisterPreservation();
</del><ins>+        stackPointerOffset -= spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation;
</ins><span class="cx"> 
</span><span class="cx">         jit.loadPtr(vm.addressOfCallFrameForCatch(), GPRInfo::callFrameRegister);
</span><span class="cx">         jit.addPtr(CCallHelpers::TrustedImm32(stackPointerOffset), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
</span><span class="cx"> 
</span><del>-        state.restoreLiveRegistersFromStackForCallWithThrownException();
</del><ins>+        state.restoreLiveRegistersFromStackForCallWithThrownException(spillStateForJSGetterSetter);
</ins><span class="cx">         state.restoreScratch();
</span><span class="cx">         CCallHelpers::Jump jumpToOSRExitExceptionHandler = jit.jump();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -277,6 +277,7 @@
</span><span class="cx">     
</span><span class="cx">     void generateImpl(AccessGenerationState&amp;);
</span><span class="cx">     void emitIntrinsicGetter(AccessGenerationState&amp;);
</span><ins>+    void emitDOMJITGetter(AccessGenerationState&amp;, GPRReg baseForGetGPR);
</ins><span class="cx">     
</span><span class="cx">     AccessType m_type { Load };
</span><span class="cx">     State m_state { Primordial };
</span><span class="lines">@@ -472,20 +473,22 @@
</span><span class="cx">     void restoreScratch();
</span><span class="cx">     void succeed();
</span><span class="cx"> 
</span><del>-    void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet&amp; extra = RegisterSet());
</del><ins>+    struct SpillState {
+        RegisterSet spilledRegisters { };
+        unsigned numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits&lt;unsigned&gt;::max() };
</ins><span class="cx"> 
</span><del>-    void preserveLiveRegistersToStackForCall(const RegisterSet&amp; extra = RegisterSet());
</del><ins>+        bool isEmpty() const { return numberOfStackBytesUsedForRegisterPreservation == std::numeric_limits&lt;unsigned&gt;::max(); }
+    };
</ins><span class="cx"> 
</span><del>-    void restoreLiveRegistersFromStackForCall(bool isGetter = false);
-    void restoreLiveRegistersFromStackForCallWithThrownException();
-    void restoreLiveRegistersFromStackForCall(const RegisterSet&amp; dontRestore);
</del><ins>+    const RegisterSet&amp; calculateLiveRegistersForCallAndExceptionHandling();
</ins><span class="cx"> 
</span><del>-    const RegisterSet&amp; liveRegistersForCall()
-    {
-        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
-        return m_liveRegistersForCall;
-    }
</del><ins>+    SpillState preserveLiveRegistersToStackForCall(const RegisterSet&amp; extra = RegisterSet());
</ins><span class="cx"> 
</span><ins>+    void restoreLiveRegistersFromStackForCallWithThrownException(const SpillState&amp;);
+    void restoreLiveRegistersFromStackForCall(const SpillState&amp;, const RegisterSet&amp; dontRestore = RegisterSet());
+
+    const RegisterSet&amp; liveRegistersForCall();
+
</ins><span class="cx">     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
</span><span class="cx">     CallSiteIndex callSiteIndexForExceptionHandling()
</span><span class="cx">     {
</span><span class="lines">@@ -495,29 +498,30 @@
</span><span class="cx">         return m_callSiteIndex;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    const HandlerInfo&amp; originalExceptionHandler() const;
-    unsigned numberOfStackBytesUsedForRegisterPreservation() const
-    {
-        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
-        return m_numberOfStackBytesUsedForRegisterPreservation;
-    }
</del><ins>+    const HandlerInfo&amp; originalExceptionHandler();
</ins><span class="cx"> 
</span><span class="cx">     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
</span><span class="cx">     CallSiteIndex originalCallSiteIndex() const;
</span><span class="cx">     
</span><span class="cx">     void emitExplicitExceptionHandler();
</span><del>-    
-private:
-    const RegisterSet&amp; liveRegistersToPreserveAtExceptionHandlingCallSite()
</del><ins>+
+    void setSpillStateForJSGetterSetter(SpillState&amp; spillState)
</ins><span class="cx">     {
</span><del>-        RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
-        return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
</del><ins>+        if (!m_spillStateForJSGetterSetter.isEmpty()) {
+            ASSERT(m_spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation == spillState.numberOfStackBytesUsedForRegisterPreservation);
+            ASSERT(m_spillStateForJSGetterSetter.spilledRegisters == spillState.spilledRegisters);
+        }
+        m_spillStateForJSGetterSetter = spillState;
</ins><span class="cx">     }
</span><ins>+    SpillState spillStateForJSGetterSetter() const { return m_spillStateForJSGetterSetter; }
</ins><span class="cx">     
</span><ins>+private:
+    const RegisterSet&amp; liveRegistersToPreserveAtExceptionHandlingCallSite();
+    
</ins><span class="cx">     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
</span><span class="cx">     RegisterSet m_liveRegistersForCall;
</span><span class="cx">     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits&lt;unsigned&gt;::max()) };
</span><del>-    unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits&lt;unsigned&gt;::max() };
</del><ins>+    SpillState m_spillStateForJSGetterSetter;
</ins><span class="cx">     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
</span><span class="cx">     bool m_needsToRestoreRegistersIfException : 1;
</span><span class="cx">     bool m_calculatedCallSiteIndex : 1;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDOMJITPatchpointParamscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.cpp (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.cpp        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.cpp        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
</span><del>-    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&amp;, OperationType operation, ResultType result, std::tuple&lt;__VA_ARGS__&gt; args) const \
</del><ins>+    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&amp;, OperationType operation, ResultType result, std::tuple&lt;__VA_ARGS__&gt; args) \
</ins><span class="cx">     { \
</span><span class="cx">         dispatch(m_jit, from, operation, result, args, std::make_index_sequence&lt;std::tuple_size&lt;decltype(args)&gt;::value&gt;()); \
</span><span class="cx">     } \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDOMJITPatchpointParamsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.h (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.h        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/dfg/DFGDOMJITPatchpointParams.h        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) const override;
</del><ins>+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) override;
</ins><span class="cx">     DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
</span><span class="cx"> #undef JSC_DEFINE_CALL_OPERATIONS
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredomjitDOMJITPatchpointh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/domjit/DOMJITPatchpoint.h (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/domjit/DOMJITPatchpoint.h        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/domjit/DOMJITPatchpoint.h        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> 
</span><span class="cx"> class PatchpointParams;
</span><span class="cx"> 
</span><del>-typedef CCallHelpers::JumpList PatchpointGeneratorFunction(CCallHelpers&amp;, const PatchpointParams&amp;);
</del><ins>+typedef CCallHelpers::JumpList PatchpointGeneratorFunction(CCallHelpers&amp;, PatchpointParams&amp;);
</ins><span class="cx"> typedef SharedTask&lt;PatchpointGeneratorFunction&gt; PatchpointGenerator;
</span><span class="cx"> 
</span><span class="cx"> // DOMJIT patchpoint is the way to inject an opaque code generator into DFG and FTL.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredomjitDOMJITPatchpointParamsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/domjit/DOMJITPatchpointParams.h (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/domjit/DOMJITPatchpointParams.h        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/domjit/DOMJITPatchpointParams.h        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -55,13 +55,13 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template&lt;typename FunctionType, typename ResultType, typename... Arguments&gt;
</span><del>-    void addSlowPathCall(CCallHelpers::JumpList from, CCallHelpers&amp; jit, FunctionType function, ResultType result, Arguments... arguments) const
</del><ins>+    void addSlowPathCall(CCallHelpers::JumpList from, CCallHelpers&amp; jit, FunctionType function, ResultType result, Arguments... arguments)
</ins><span class="cx">     {
</span><span class="cx">         addSlowPathCallImpl(from, jit, function, result, std::make_tuple(arguments...));
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) JS_EXPORT_PRIVATE virtual void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) const = 0;
</del><ins>+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) JS_EXPORT_PRIVATE virtual void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) = 0;
</ins><span class="cx">     DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
</span><span class="cx"> #undef JSC_DEFINE_CALL_OPERATIONS
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLDOMJITPatchpointParamscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.cpp (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.cpp        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.cpp        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -50,7 +50,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) \
</span><del>-    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&amp; jit, OperationType operation, ResultType result, std::tuple&lt;__VA_ARGS__&gt; args) const \
</del><ins>+    void DOMJITPatchpointParams::addSlowPathCallImpl(CCallHelpers::JumpList from, CCallHelpers&amp; jit, OperationType operation, ResultType result, std::tuple&lt;__VA_ARGS__&gt; args) \
</ins><span class="cx">     { \
</span><span class="cx">         dispatch(jit, &amp;m_state, m_params, m_node, m_exceptions, from, operation, result, args, std::make_index_sequence&lt;std::tuple_size&lt;decltype(args)&gt;::value&gt;()); \
</span><span class="cx">     } \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLDOMJITPatchpointParamsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/ftl/FTLDOMJITPatchpointParams.h        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) const override;
</del><ins>+#define JSC_DEFINE_CALL_OPERATIONS(OperationType, ResultType, ...) void addSlowPathCallImpl(CCallHelpers::JumpList, CCallHelpers&amp;, OperationType, ResultType, std::tuple&lt;__VA_ARGS__&gt; args) override;
</ins><span class="cx">     DOMJIT_SLOW_PATH_CALLS(JSC_DEFINE_CALL_OPERATIONS)
</span><span class="cx"> #undef JSC_DEFINE_CALL_OPERATIONS
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2016-10-17 20:38:46 UTC (rev 207426)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2016-10-17 20:43:43 UTC (rev 207427)
</span><span class="lines">@@ -557,6 +557,22 @@
</span><span class="cx">         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+#if ENABLE(JIT)
+    static Ref&lt;DOMJIT::Patchpoint&gt; checkDOMJITNode()
+    {
+        Ref&lt;DOMJIT::Patchpoint&gt; patchpoint = DOMJIT::Patchpoint::create();
+        patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, DOMJIT::PatchpointParams&amp; 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
+
</ins><span class="cx">     static DOMJITNode* create(VM&amp; vm, Structure* structure)
</span><span class="cx">     {
</span><span class="cx">         DOMJITNode* getter = new (NotNull, allocateCell&lt;DOMJITNode&gt;(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
</span><span class="lines">@@ -608,16 +624,7 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx">         Ref&lt;DOMJIT::Patchpoint&gt; checkDOM() override
</span><span class="cx">         {
</span><del>-            Ref&lt;DOMJIT::Patchpoint&gt; patchpoint = DOMJIT::Patchpoint::create();
-            patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, const DOMJIT::PatchpointParams&amp; 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;
</del><ins>+            return DOMJITNode::checkDOMJITNode();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         Ref&lt;DOMJIT::CallDOMPatchpoint&gt; callDOM() override
</span><span class="lines">@@ -624,7 +631,7 @@
</span><span class="cx">         {
</span><span class="cx">             Ref&lt;DOMJIT::CallDOMPatchpoint&gt; patchpoint = DOMJIT::CallDOMPatchpoint::create();
</span><span class="cx">             patchpoint-&gt;requireGlobalObject = false;
</span><del>-            patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, const DOMJIT::PatchpointParams&amp; params) {
</del><ins>+            patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, DOMJIT::PatchpointParams&amp; params) {
</ins><span class="cx">                 JSValueRegs results = params[0].jsValueRegs();
</span><span class="cx">                 GPRReg dom = params[1].gpr();
</span><span class="cx"> 
</span><span class="lines">@@ -666,6 +673,115 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class DOMJITGetterComplex : public DOMJITNode {
+public:
+    DOMJITGetterComplex(VM&amp; vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+
+    DECLARE_INFO;
+    typedef DOMJITNode Base;
+    static const unsigned StructureFlags = Base::StructureFlags;
+
+    static Structure* createStructure(VM&amp; vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
+    }
+
+    static DOMJITGetterComplex* create(VM&amp; vm, JSGlobalObject* globalObject, Structure* structure)
+    {
+        DOMJITGetterComplex* getter = new (NotNull, allocateCell&lt;DOMJITGetterComplex&gt;(vm.heap, sizeof(DOMJITGetterComplex))) DOMJITGetterComplex(vm, structure);
+        getter-&gt;finishCreation(vm, globalObject);
+        return getter;
+    }
+
+    class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
+    public:
+        DOMJITNodeDOMJIT()
+            : DOMJIT::GetterSetter(DOMJITGetterComplex::customGetter, nullptr, DOMJITNode::info())
+        {
+        }
+
+#if ENABLE(JIT)
+        Ref&lt;DOMJIT::Patchpoint&gt; checkDOM() override
+        {
+            return DOMJITNode::checkDOMJITNode();
+        }
+
+        Ref&lt;DOMJIT::CallDOMPatchpoint&gt; callDOM() override
+        {
+            RefPtr&lt;DOMJIT::CallDOMPatchpoint&gt; patchpoint = DOMJIT::CallDOMPatchpoint::create();
+            static_assert(GPRInfo::numberOfRegisters &gt;= 4, &quot;Number of registers should be larger or equal to 4.&quot;);
+            patchpoint-&gt;numGPScratchRegisters = GPRInfo::numberOfRegisters - 4;
+            patchpoint-&gt;numFPScratchRegisters = 3;
+            patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, DOMJIT::PatchpointParams&amp; params) {
+                JSValueRegs results = params[0].jsValueRegs();
+                GPRReg domGPR = params[2].gpr();
+                for (unsigned i = 0; i &lt; patchpoint-&gt;numGPScratchRegisters; ++i)
+                    jit.move(CCallHelpers::TrustedImm32(42), params.gpScratch(i));
+
+                params.addSlowPathCall(jit.jump(), jit, static_cast&lt;EncodedJSValue(*)(ExecState*, void*)&gt;([](ExecState* exec, void* pointer) {
+                    VM&amp; vm = exec-&gt;vm();
+                    auto scope = DECLARE_THROW_SCOPE(vm);
+                    auto* object = static_cast&lt;DOMJITNode*&gt;(pointer);
+                    auto* domjitGetterComplex = jsDynamicCast&lt;DOMJITGetterComplex*&gt;(object);
+                    if (domjitGetterComplex) {
+                        if (domjitGetterComplex-&gt;m_enableException)
+                            return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral(&quot;DOMJITGetterComplex slow call exception&quot;))));
+                    }
+                    return JSValue::encode(jsNumber(object-&gt;value()));
+                }), results, domGPR);
+                return CCallHelpers::JumpList();
+
+            });
+            return *patchpoint.get();
+        }
+#endif
+    };
+
+    static DOMJIT::GetterSetter* domJITNodeGetterSetter()
+    {
+        static NeverDestroyed&lt;DOMJITNodeDOMJIT&gt; graph;
+        return &amp;graph.get();
+    }
+
+private:
+    void finishCreation(VM&amp; vm, JSGlobalObject* globalObject)
+    {
+        Base::finishCreation(vm);
+        DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
+        CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT-&gt;getter(), domJIT-&gt;setter(), domJIT);
+        putDirectCustomAccessor(vm, Identifier::fromString(&amp;vm, &quot;customGetter&quot;), customGetterSetter, ReadOnly | CustomAccessor);
+        putDirectNativeFunction(vm, globalObject, Identifier::fromString(&amp;vm, &quot;enableException&quot;), 0, functionEnableException, NoIntrinsic, 0);
+    }
+
+    static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec)
+    {
+        auto* object = jsDynamicCast&lt;DOMJITGetterComplex*&gt;(exec-&gt;thisValue());
+        if (object)
+            object-&gt;m_enableException = true;
+        return JSValue::encode(jsUndefined());
+    }
+
+    static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
+    {
+        VM&amp; vm = exec-&gt;vm();
+        auto scope = DECLARE_THROW_SCOPE(vm);
+
+        auto* thisObject = jsDynamicCast&lt;DOMJITNode*&gt;(JSValue::decode(thisValue));
+        if (!thisObject)
+            return throwVMTypeError(exec, scope);
+        if (auto* domjitGetterComplex = jsDynamicCast&lt;DOMJITGetterComplex*&gt;(JSValue::decode(thisValue))) {
+            if (domjitGetterComplex-&gt;m_enableException)
+                return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral(&quot;DOMJITGetterComplex slow call exception&quot;))));
+        }
+        return JSValue::encode(jsNumber(thisObject-&gt;value()));
+    }
+
+    bool m_enableException { false };
+};
+
</ins><span class="cx"> const ClassInfo Element::s_info = { &quot;Element&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
</span><span class="cx"> const ClassInfo Masquerader::s_info = { &quot;Masquerader&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
</span><span class="cx"> const ClassInfo Root::s_info = { &quot;Root&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
</span><span class="lines">@@ -673,6 +789,7 @@
</span><span class="cx"> const ClassInfo CustomGetter::s_info = { &quot;CustomGetter&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
</span><span class="cx"> const ClassInfo DOMJITNode::s_info = { &quot;DOMJITNode&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITNode) };
</span><span class="cx"> const ClassInfo DOMJITGetter::s_info = { &quot;DOMJITGetter&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetter) };
</span><ins>+const ClassInfo DOMJITGetterComplex::s_info = { &quot;DOMJITGetterComplex&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetterComplex) };
</ins><span class="cx"> const ClassInfo RuntimeArray::s_info = { &quot;RuntimeArray&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
</span><span class="cx"> const ClassInfo SimpleObject::s_info = { &quot;SimpleObject&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
</span><span class="cx"> static bool test262AsyncPassed { false };
</span><span class="lines">@@ -703,6 +820,7 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState*);
</ins><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
</span><span class="lines">@@ -990,6 +1108,7 @@
</span><span class="cx">         addFunction(vm, &quot;createCustomGetterObject&quot;, functionCreateCustomGetterObject, 0);
</span><span class="cx">         addFunction(vm, &quot;createDOMJITNodeObject&quot;, functionCreateDOMJITNodeObject, 0);
</span><span class="cx">         addFunction(vm, &quot;createDOMJITGetterObject&quot;, functionCreateDOMJITGetterObject, 0);
</span><ins>+        addFunction(vm, &quot;createDOMJITGetterComplexObject&quot;, functionCreateDOMJITGetterComplexObject, 0);
</ins><span class="cx">         addFunction(vm, &quot;createBuiltin&quot;, functionCreateBuiltin, 2);
</span><span class="cx">         addFunction(vm, &quot;createGlobalObject&quot;, functionCreateGlobalObject, 0);
</span><span class="cx">         addFunction(vm, &quot;setImpureGetterDelegate&quot;, functionSetImpureGetterDelegate, 2);
</span><span class="lines">@@ -1511,6 +1630,14 @@
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
+{
+    JSLockHolder lock(exec);
+    Structure* structure = DOMJITGetterComplex::createStructure(exec-&gt;vm(), exec-&gt;lexicalGlobalObject(), jsNull());
+    DOMJITGetterComplex* result = DOMJITGetterComplex::create(exec-&gt;vm(), exec-&gt;lexicalGlobalObject(), structure);
+    return JSValue::encode(result);
+}
+
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     JSLockHolder lock(exec);
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2016-10-17  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        [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):
+
</ins><span class="cx"> 2016-10-17  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Move form.reportValidity() behind InteractiveFormValidation setting
</span></span></pre></div>
<a id="trunkSourceWebCoredomjitDOMJITHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/domjit/DOMJITHelpers.h (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename WrappedType, typename ToJSFunction&gt;
</span><del>-void toWrapper(CCallHelpers&amp; jit, const JSC::DOMJIT::PatchpointParams&amp; params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant)
</del><ins>+void toWrapper(CCallHelpers&amp; jit, JSC::DOMJIT::PatchpointParams&amp; params, GPRReg wrapped, GPRReg globalObject, JSValueRegs result, ToJSFunction function, JSC::JSValue globalObjectConstant)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(wrapped != result.payloadGPR());
</span><span class="cx">     ASSERT(globalObject != result.payloadGPR());
</span></span></pre></div>
<a id="trunkSourceWebCoredomjitJSNodeDOMJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/domjit/JSNodeDOMJIT.cpp (207426 => 207427)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx"> {
</span><span class="cx">     Ref&lt;DOMJIT::CallDOMPatchpoint&gt; patchpoint = DOMJIT::CallDOMPatchpoint::create();
</span><span class="cx">     patchpoint-&gt;numGPScratchRegisters = 1;
</span><del>-    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, const DOMJIT::PatchpointParams&amp; params) {
</del><ins>+    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, DOMJIT::PatchpointParams&amp; params) {
</ins><span class="cx">         JSValueRegs result = params[0].jsValueRegs();
</span><span class="cx">         GPRReg globalObject = params[1].gpr();
</span><span class="cx">         GPRReg node = params[2].gpr();
</span><span class="lines">@@ -84,7 +84,7 @@
</span><span class="cx"> static Ref&lt;DOMJIT::Patchpoint&gt; checkNode()
</span><span class="cx"> {
</span><span class="cx">     Ref&lt;DOMJIT::Patchpoint&gt; patchpoint = DOMJIT::Patchpoint::create();
</span><del>-    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, const DOMJIT::PatchpointParams&amp; params) {
</del><ins>+    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, DOMJIT::PatchpointParams&amp; params) {
</ins><span class="cx">         CCallHelpers::JumpList failureCases;
</span><span class="cx">         failureCases.append(DOMJITHelpers::branchIfNotNode(jit, params[0].gpr()));
</span><span class="cx">         return failureCases;
</span><span class="lines">@@ -157,7 +157,7 @@
</span><span class="cx"> {
</span><span class="cx">     Ref&lt;DOMJIT::CallDOMPatchpoint&gt; patchpoint = DOMJIT::CallDOMPatchpoint::create();
</span><span class="cx">     patchpoint-&gt;requireGlobalObject = false;
</span><del>-    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, const DOMJIT::PatchpointParams&amp; params) {
</del><ins>+    patchpoint-&gt;setGenerator([=](CCallHelpers&amp; jit, DOMJIT::PatchpointParams&amp; params) {
</ins><span class="cx">         JSValueRegs result = params[0].jsValueRegs();
</span><span class="cx">         GPRReg node = params[1].gpr();
</span><span class="cx">         jit.load8(CCallHelpers::Address(node, JSC::JSCell::typeInfoTypeOffset()), result.payloadGPR());
</span></span></pre>
</div>
</div>

</body>
</html>