<!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>[199069] 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/199069">199069</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-04-05 12:58:04 -0700 (Tue, 05 Apr 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>PolymorphicAccess should have a MegamorphicLoad case
https://bugs.webkit.org/show_bug.cgi?id=156182

Reviewed by Geoffrey Garen and Keith Miller.

Source/JavaScriptCore:

This introduces a new case to PolymorphicAccess called MegamorphicLoad. This inlines the lookup in
the PropertyTable. It's cheaper than switching on a huge number of cases and it's cheaper than
calling into C++ to do the same job - particularly since inlining the lookup into an access means
that we can precompute the hash code.

When writing the inline code for the hashtable lookup, I found that our hashing algorithm was not
optimal. It used a double-hashing method for reducing collision pathologies. This is great for
improving the performance of some worst-case scenarios. But this misses the point of a hashtable: we
want to optimize the average-case performance. When optimizing for average-case, we can choose to
either focus on maximizing the likelihood of the fast case happening, or to minimize the cost of the
worst-case, or to minimize the cost of the fast case. Even a very basic hashtable will achieve a high
probability of hitting the fast case. So, doing work to reduce the likelihood of a worst-case
pathology only makes sense if it also preserves the good performance of the fast case, or reduces the
likelihood of the worst-case by so much that it's a win for the average case even with a slow-down in
the fast case.

I don't believe, based on looking at how the double-hashing is implemented, that it's possible that
this preserves the good performance of the fast case. It requires at least one more value to be live
around the loop, and dramatically increases the register pressure at key points inside the loop. The
biggest offender is the doubleHash() method itself. There is no getting around how bad this is: if
the compiler live-range-splits that method to death to avoid degrading register pressure elsewhere
then we will pay a steep price anytime we take the second iteration around the loop; but if the
compiler doesn't split around the call then the hashtable lookup fast path will be full of spills on
some architectures (I performed biological register allocation and found that I needed 9 registers
for complete lookup, while x86-64 has only 6 callee-saves; OTOH ARM64 has 10 callee-saves so it might
be better off).

Hence, this patch changes the hashtable lookup to use simple linear probing. This was not a slow-down
on anything, and it made MegamorphicLoad much more sensible since it is less likely to have to spill.

There are some other small changes in this patch, like rationalizing the IC's choice between giving
up after a repatch (i.e. never trying again) and just pretending that nothing happened (so we can
try to repatch again in the future). It looked like the code in Repatch.cpp was set up to be able to
choose between those options, but we weren't fully taking advantage of it because the
regenerateWithCase() method just returned null for any failure, and didn't say whether it was the
sort of failure that renders the inline cache unrepatchable (like memory allocation failure). Now
this is all made explicit. I wanted to make sure this change happened in this patch since the
MegamorphicLoad code automagically generates a MegamorphicLoad case by coalescing other cases. Since
this is intended to avoid blowing out the cache and making it unrepatchable, I wanted to make sure
that the rules for giving up were something that made sense to me.
        
This is a big win on microbenchmarks. It's neutral on traditional JS benchmarks. It's a slight
speed-up for page loading, because many real websites like to have megamorphic property accesses.

* bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationResult::dump):
(JSC::AccessGenerationState::addWatchpoint):
(JSC::AccessCase::get):
(JSC::AccessCase::megamorphicLoad):
(JSC::AccessCase::replace):
(JSC::AccessCase::guardedByStructureCheck):
(JSC::AccessCase::couldStillSucceed):
(JSC::AccessCase::canBeReplacedByMegamorphicLoad):
(JSC::AccessCase::canReplace):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generate):
(JSC::PolymorphicAccess::PolymorphicAccess):
(JSC::PolymorphicAccess::~PolymorphicAccess):
(JSC::PolymorphicAccess::regenerateWithCases):
(JSC::PolymorphicAccess::regenerateWithCase):
(WTF::printInternal):
* bytecode/PolymorphicAccess.h:
(JSC::AccessCase::isGet):
(JSC::AccessCase::isPut):
(JSC::AccessCase::isIn):
(JSC::AccessGenerationResult::AccessGenerationResult):
(JSC::AccessGenerationResult::operator==):
(JSC::AccessGenerationResult::operator!=):
(JSC::AccessGenerationResult::operator bool):
(JSC::AccessGenerationResult::kind):
(JSC::AccessGenerationResult::code):
(JSC::AccessGenerationResult::madeNoChanges):
(JSC::AccessGenerationResult::gaveUp):
(JSC::AccessGenerationResult::generatedNewCode):
(JSC::PolymorphicAccess::isEmpty):
(JSC::AccessGenerationState::AccessGenerationState):
* bytecode/StructureStubInfo.cpp:
(JSC::StructureStubInfo::aboutToDie):
(JSC::StructureStubInfo::addAccessCase):
* bytecode/StructureStubInfo.h:
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
(JSC::AssemblyHelpers::loadProperty):
(JSC::emitRandomThunkImpl):
(JSC::AssemblyHelpers::emitRandomThunk):
(JSC::AssemblyHelpers::emitLoadStructure):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::loadValue):
(JSC::AssemblyHelpers::moveValueRegs):
(JSC::AssemblyHelpers::argumentsStart):
(JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
(JSC::AssemblyHelpers::emitLoadStructure): Deleted.
* jit/GPRInfo.cpp:
(JSC::JSValueRegs::dump):
* jit/GPRInfo.h:
(JSC::JSValueRegs::uses):
* jit/Repatch.cpp:
(JSC::replaceWithJump):
(JSC::tryCacheGetByID):
(JSC::tryCachePutByID):
(JSC::tryRepatchIn):
* jit/ThunkGenerators.cpp:
(JSC::virtualThunkFor):
* runtime/Options.h:
* runtime/PropertyMapHashTable.h:
(JSC::PropertyTable::begin):
(JSC::PropertyTable::find):
(JSC::PropertyTable::get):
* runtime/Structure.h:

LayoutTests:

* js/regress/megamorphic-load-expected.txt: Added.
* js/regress/megamorphic-load.html: Added.
* js/regress/script-tests/megamorphic-load.js: Added.
* js/regress/string-repeat-not-resolving-no-inline-expected.txt: Added.
* js/regress/string-repeat-not-resolving-no-inline.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</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="#trunkSourceJavaScriptCorebytecodeStructureStubInfocpp">trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeStructureStubInfoh">trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelperscpp">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelpersh">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitGPRInfocpp">trunk/Source/JavaScriptCore/jit/GPRInfo.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitGPRInfoh">trunk/Source/JavaScriptCore/jit/GPRInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRepatchcpp">trunk/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitThunkGeneratorscpp">trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimePropertyMapHashTableh">trunk/Source/JavaScriptCore/runtime/PropertyMapHashTable.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregressmegamorphicloadexpectedtxt">trunk/LayoutTests/js/regress/megamorphic-load-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressmegamorphicloadhtml">trunk/LayoutTests/js/regress/megamorphic-load.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsmegamorphicloadjs">trunk/LayoutTests/js/regress/script-tests/megamorphic-load.js</a></li>
<li><a href="#trunkLayoutTestsjsregressstringrepeatnotresolvingnoinlineexpectedtxt">trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressstringrepeatnotresolvingnoinlinehtml">trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/LayoutTests/ChangeLog        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-04-04  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        PolymorphicAccess should have a MegamorphicLoad case
+        https://bugs.webkit.org/show_bug.cgi?id=156182
+
+        Reviewed by Geoffrey Garen and Keith Miller.
+
+        * js/regress/megamorphic-load-expected.txt: Added.
+        * js/regress/megamorphic-load.html: Added.
+        * js/regress/script-tests/megamorphic-load.js: Added.
+        * js/regress/string-repeat-not-resolving-no-inline-expected.txt: Added.
+        * js/regress/string-repeat-not-resolving-no-inline.html: Added.
+
</ins><span class="cx"> 2016-04-05  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Un-marking plugins/focus.html as flaky on mac
</span></span></pre></div>
<a id="trunkLayoutTestsjsregressmegamorphicloadexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/megamorphic-load-expected.txt (0 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/megamorphic-load-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/megamorphic-load-expected.txt        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/megamorphic-load
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressmegamorphicloadhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/megamorphic-load.html (0 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/megamorphic-load.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/megamorphic-load.html        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/megamorphic-load.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsmegamorphicloadjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/megamorphic-load.js (0 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/megamorphic-load.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/megamorphic-load.js        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+(function() {
+    var array = [];
+    for (var i = 0; i &lt; 1000; ++i) {
+        var o = {};
+        o[&quot;i&quot; + i] = i;
+        o.f = 42;
+        array.push(o);
+    }
+    
+    for (var i = 0; i &lt; 1000000; ++i) {
+        var result = array[i % array.length].f;
+        if (result != 42)
+            throw &quot;Error: bad result: &quot; + result;
+    }
+})();
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressstringrepeatnotresolvingnoinlineexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline-expected.txt (0 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline-expected.txt        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/string-repeat-not-resolving-no-inline
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressstringrepeatnotresolvingnoinlinehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline.html (0 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/string-repeat-not-resolving-no-inline.html        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/string-repeat-not-resolving-no-inline.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,3 +1,120 @@
</span><ins>+2016-04-04  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        PolymorphicAccess should have a MegamorphicLoad case
+        https://bugs.webkit.org/show_bug.cgi?id=156182
+
+        Reviewed by Geoffrey Garen and Keith Miller.
+
+        This introduces a new case to PolymorphicAccess called MegamorphicLoad. This inlines the lookup in
+        the PropertyTable. It's cheaper than switching on a huge number of cases and it's cheaper than
+        calling into C++ to do the same job - particularly since inlining the lookup into an access means
+        that we can precompute the hash code.
+
+        When writing the inline code for the hashtable lookup, I found that our hashing algorithm was not
+        optimal. It used a double-hashing method for reducing collision pathologies. This is great for
+        improving the performance of some worst-case scenarios. But this misses the point of a hashtable: we
+        want to optimize the average-case performance. When optimizing for average-case, we can choose to
+        either focus on maximizing the likelihood of the fast case happening, or to minimize the cost of the
+        worst-case, or to minimize the cost of the fast case. Even a very basic hashtable will achieve a high
+        probability of hitting the fast case. So, doing work to reduce the likelihood of a worst-case
+        pathology only makes sense if it also preserves the good performance of the fast case, or reduces the
+        likelihood of the worst-case by so much that it's a win for the average case even with a slow-down in
+        the fast case.
+
+        I don't believe, based on looking at how the double-hashing is implemented, that it's possible that
+        this preserves the good performance of the fast case. It requires at least one more value to be live
+        around the loop, and dramatically increases the register pressure at key points inside the loop. The
+        biggest offender is the doubleHash() method itself. There is no getting around how bad this is: if
+        the compiler live-range-splits that method to death to avoid degrading register pressure elsewhere
+        then we will pay a steep price anytime we take the second iteration around the loop; but if the
+        compiler doesn't split around the call then the hashtable lookup fast path will be full of spills on
+        some architectures (I performed biological register allocation and found that I needed 9 registers
+        for complete lookup, while x86-64 has only 6 callee-saves; OTOH ARM64 has 10 callee-saves so it might
+        be better off).
+
+        Hence, this patch changes the hashtable lookup to use simple linear probing. This was not a slow-down
+        on anything, and it made MegamorphicLoad much more sensible since it is less likely to have to spill.
+
+        There are some other small changes in this patch, like rationalizing the IC's choice between giving
+        up after a repatch (i.e. never trying again) and just pretending that nothing happened (so we can
+        try to repatch again in the future). It looked like the code in Repatch.cpp was set up to be able to
+        choose between those options, but we weren't fully taking advantage of it because the
+        regenerateWithCase() method just returned null for any failure, and didn't say whether it was the
+        sort of failure that renders the inline cache unrepatchable (like memory allocation failure). Now
+        this is all made explicit. I wanted to make sure this change happened in this patch since the
+        MegamorphicLoad code automagically generates a MegamorphicLoad case by coalescing other cases. Since
+        this is intended to avoid blowing out the cache and making it unrepatchable, I wanted to make sure
+        that the rules for giving up were something that made sense to me.
+        
+        This is a big win on microbenchmarks. It's neutral on traditional JS benchmarks. It's a slight
+        speed-up for page loading, because many real websites like to have megamorphic property accesses.
+
+        * bytecode/PolymorphicAccess.cpp:
+        (JSC::AccessGenerationResult::dump):
+        (JSC::AccessGenerationState::addWatchpoint):
+        (JSC::AccessCase::get):
+        (JSC::AccessCase::megamorphicLoad):
+        (JSC::AccessCase::replace):
+        (JSC::AccessCase::guardedByStructureCheck):
+        (JSC::AccessCase::couldStillSucceed):
+        (JSC::AccessCase::canBeReplacedByMegamorphicLoad):
+        (JSC::AccessCase::canReplace):
+        (JSC::AccessCase::generateWithGuard):
+        (JSC::AccessCase::generate):
+        (JSC::PolymorphicAccess::PolymorphicAccess):
+        (JSC::PolymorphicAccess::~PolymorphicAccess):
+        (JSC::PolymorphicAccess::regenerateWithCases):
+        (JSC::PolymorphicAccess::regenerateWithCase):
+        (WTF::printInternal):
+        * bytecode/PolymorphicAccess.h:
+        (JSC::AccessCase::isGet):
+        (JSC::AccessCase::isPut):
+        (JSC::AccessCase::isIn):
+        (JSC::AccessGenerationResult::AccessGenerationResult):
+        (JSC::AccessGenerationResult::operator==):
+        (JSC::AccessGenerationResult::operator!=):
+        (JSC::AccessGenerationResult::operator bool):
+        (JSC::AccessGenerationResult::kind):
+        (JSC::AccessGenerationResult::code):
+        (JSC::AccessGenerationResult::madeNoChanges):
+        (JSC::AccessGenerationResult::gaveUp):
+        (JSC::AccessGenerationResult::generatedNewCode):
+        (JSC::PolymorphicAccess::isEmpty):
+        (JSC::AccessGenerationState::AccessGenerationState):
+        * bytecode/StructureStubInfo.cpp:
+        (JSC::StructureStubInfo::aboutToDie):
+        (JSC::StructureStubInfo::addAccessCase):
+        * bytecode/StructureStubInfo.h:
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
+        (JSC::AssemblyHelpers::loadProperty):
+        (JSC::emitRandomThunkImpl):
+        (JSC::AssemblyHelpers::emitRandomThunk):
+        (JSC::AssemblyHelpers::emitLoadStructure):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::loadValue):
+        (JSC::AssemblyHelpers::moveValueRegs):
+        (JSC::AssemblyHelpers::argumentsStart):
+        (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
+        (JSC::AssemblyHelpers::emitLoadStructure): Deleted.
+        * jit/GPRInfo.cpp:
+        (JSC::JSValueRegs::dump):
+        * jit/GPRInfo.h:
+        (JSC::JSValueRegs::uses):
+        * jit/Repatch.cpp:
+        (JSC::replaceWithJump):
+        (JSC::tryCacheGetByID):
+        (JSC::tryCachePutByID):
+        (JSC::tryRepatchIn):
+        * jit/ThunkGenerators.cpp:
+        (JSC::virtualThunkFor):
+        * runtime/Options.h:
+        * runtime/PropertyMapHashTable.h:
+        (JSC::PropertyTable::begin):
+        (JSC::PropertyTable::find):
+        (JSC::PropertyTable::get):
+        * runtime/Structure.h:
+
</ins><span class="cx"> 2016-04-05  Antoine Quint  &lt;graouts@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WebGL2] Turn the ENABLE_WEBGL2 flag on
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccesscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -46,6 +46,13 @@
</span><span class="cx"> 
</span><span class="cx"> static const bool verbose = false;
</span><span class="cx"> 
</span><ins>+void AccessGenerationResult::dump(PrintStream&amp; out) const
+{
+    out.print(m_kind);
+    if (m_code)
+        out.print(&quot;:&quot;, m_code);
+}
+
</ins><span class="cx"> Watchpoint* AccessGenerationState::addWatchpoint(const ObjectPropertyCondition&amp; condition)
</span><span class="cx"> {
</span><span class="cx">     return WatchpointsOnStructureStubInfo::ensureReferenceAndAddWatchpoint(
</span><span class="lines">@@ -175,6 +182,21 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+std::unique_ptr&lt;AccessCase&gt; AccessCase::megamorphicLoad(VM&amp; vm, JSCell* owner)
+{
+    UNUSED_PARAM(vm);
+    UNUSED_PARAM(owner);
+    
+    if (GPRInfo::numberOfRegisters &lt; 9)
+        return nullptr;
+    
+    std::unique_ptr&lt;AccessCase&gt; result(new AccessCase());
+    
+    result-&gt;m_type = MegamorphicLoad;
+    
+    return result;
+}
+
</ins><span class="cx"> std::unique_ptr&lt;AccessCase&gt; AccessCase::replace(
</span><span class="cx">     VM&amp; vm, JSCell* owner, Structure* structure, PropertyOffset offset)
</span><span class="cx"> {
</span><span class="lines">@@ -322,6 +344,7 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     switch (m_type) {
</span><ins>+    case MegamorphicLoad:
</ins><span class="cx">     case ArrayLength:
</span><span class="cx">     case StringLength:
</span><span class="cx">         return false;
</span><span class="lines">@@ -342,9 +365,21 @@
</span><span class="cx">     return m_conditionSet.structuresEnsureValidityAssumingImpurePropertyWatchpoint();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AccessCase::canReplace(const AccessCase&amp; other)
</del><ins>+bool AccessCase::canBeReplacedByMegamorphicLoad() const
</ins><span class="cx"> {
</span><ins>+    return type() == Load
+        &amp;&amp; !viaProxy()
+        &amp;&amp; conditionSet().isEmpty()
+        &amp;&amp; !additionalSet()
+        &amp;&amp; !customSlotBase();
+}
+
+bool AccessCase::canReplace(const AccessCase&amp; other) const
+{
</ins><span class="cx">     // We could do a lot better here, but for now we just do something obvious.
</span><ins>+    
+    if (type() == MegamorphicLoad &amp;&amp; other.canBeReplacedByMegamorphicLoad())
+        return true;
</ins><span class="cx"> 
</span><span class="cx">     if (!guardedByStructureCheck() || !other.guardedByStructureCheck()) {
</span><span class="cx">         // FIXME: Implement this!
</span><span class="lines">@@ -407,17 +442,25 @@
</span><span class="cx">     AccessGenerationState&amp; state, CCallHelpers::JumpList&amp; fallThrough)
</span><span class="cx"> {
</span><span class="cx">     CCallHelpers&amp; jit = *state.jit;
</span><ins>+    VM&amp; vm = *jit.vm();
+    const Identifier&amp; ident = *state.ident;
+    StructureStubInfo&amp; stubInfo = *state.stubInfo;
+    JSValueRegs valueRegs = state.valueRegs;
+    GPRReg baseGPR = state.baseGPR;
+    GPRReg scratchGPR = state.scratchGPR;
+    
+    UNUSED_PARAM(vm);
</ins><span class="cx"> 
</span><span class="cx">     switch (m_type) {
</span><span class="cx">     case ArrayLength: {
</span><span class="cx">         ASSERT(!viaProxy());
</span><del>-        jit.load8(CCallHelpers::Address(state.baseGPR, JSCell::indexingTypeOffset()), state.scratchGPR);
</del><ins>+        jit.load8(CCallHelpers::Address(baseGPR, JSCell::indexingTypeOffset()), scratchGPR);
</ins><span class="cx">         fallThrough.append(
</span><span class="cx">             jit.branchTest32(
</span><del>-                CCallHelpers::Zero, state.scratchGPR, CCallHelpers::TrustedImm32(IsArray)));
</del><ins>+                CCallHelpers::Zero, scratchGPR, CCallHelpers::TrustedImm32(IsArray)));
</ins><span class="cx">         fallThrough.append(
</span><span class="cx">             jit.branchTest32(
</span><del>-                CCallHelpers::Zero, state.scratchGPR, CCallHelpers::TrustedImm32(IndexingShapeMask)));
</del><ins>+                CCallHelpers::Zero, scratchGPR, CCallHelpers::TrustedImm32(IndexingShapeMask)));
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -426,33 +469,146 @@
</span><span class="cx">         fallThrough.append(
</span><span class="cx">             jit.branch8(
</span><span class="cx">                 CCallHelpers::NotEqual,
</span><del>-                CCallHelpers::Address(state.baseGPR, JSCell::typeInfoTypeOffset()),
</del><ins>+                CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()),
</ins><span class="cx">                 CCallHelpers::TrustedImm32(StringType)));
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+        
+    case MegamorphicLoad: {
+        UniquedStringImpl* key = ident.impl();
+        unsigned hash = IdentifierRepHash::hash(key);
+        
+        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 intermediateGPR = scratchGPR;
+        GPRReg maskGPR = allocator.allocateScratchGPR();
+        GPRReg maskedHashGPR = allocator.allocateScratchGPR();
+        GPRReg indexGPR = allocator.allocateScratchGPR();
+        GPRReg offsetGPR = allocator.allocateScratchGPR();
+        
+        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;intermediateGPR = &quot;, intermediateGPR, &quot;\n&quot;);
+            dataLog(&quot;maskGPR = &quot;, maskGPR, &quot;\n&quot;);
+            dataLog(&quot;maskedHashGPR = &quot;, maskedHashGPR, &quot;\n&quot;);
+            dataLog(&quot;indexGPR = &quot;, indexGPR, &quot;\n&quot;);
+            dataLog(&quot;offsetGPR = &quot;, offsetGPR, &quot;\n&quot;);
+        }
</ins><span class="cx"> 
</span><ins>+        ScratchRegisterAllocator::PreservedState preservedState =
+            allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::SpaceForCCall);
+
+        CCallHelpers::JumpList myFailAndIgnore;
+        CCallHelpers::JumpList myFallThrough;
+        
+        jit.emitLoadStructure(baseGPR, intermediateGPR, maskGPR);
+        jit.loadPtr(
+            CCallHelpers::Address(intermediateGPR, Structure::propertyTableUnsafeOffset()),
+            intermediateGPR);
+        
+        myFailAndIgnore.append(jit.branchTestPtr(CCallHelpers::Zero, intermediateGPR));
+        
+        jit.load32(CCallHelpers::Address(intermediateGPR, PropertyTable::offsetOfIndexMask()), maskGPR);
+        jit.loadPtr(CCallHelpers::Address(intermediateGPR, PropertyTable::offsetOfIndex()), indexGPR);
+        jit.load32(
+            CCallHelpers::Address(intermediateGPR, PropertyTable::offsetOfIndexSize()),
+            intermediateGPR);
+
+        jit.move(maskGPR, maskedHashGPR);
+        jit.and32(CCallHelpers::TrustedImm32(hash), maskedHashGPR);
+        jit.lshift32(CCallHelpers::TrustedImm32(2), intermediateGPR);
+        jit.addPtr(indexGPR, intermediateGPR);
+        
+        CCallHelpers::Label loop = jit.label();
+        
+        jit.load32(CCallHelpers::BaseIndex(indexGPR, maskedHashGPR, CCallHelpers::TimesFour), offsetGPR);
+        
+        myFallThrough.append(
+            jit.branch32(
+                CCallHelpers::Equal,
+                offsetGPR,
+                CCallHelpers::TrustedImm32(PropertyTable::EmptyEntryIndex)));
+        
+        jit.sub32(CCallHelpers::TrustedImm32(1), offsetGPR);
+        jit.mul32(CCallHelpers::TrustedImm32(sizeof(PropertyMapEntry)), offsetGPR, offsetGPR);
+        jit.addPtr(intermediateGPR, offsetGPR);
+        
+        CCallHelpers::Jump collision =  jit.branchPtr(
+            CCallHelpers::NotEqual,
+            CCallHelpers::Address(offsetGPR, OBJECT_OFFSETOF(PropertyMapEntry, key)),
+            CCallHelpers::TrustedImmPtr(key));
+        
+        // offsetGPR currently holds a pointer to the PropertyMapEntry, which has the offset and attributes.
+        // Check them and then attempt the load.
+        
+        myFallThrough.append(
+            jit.branchTest32(
+                CCallHelpers::NonZero,
+                CCallHelpers::Address(offsetGPR, OBJECT_OFFSETOF(PropertyMapEntry, attributes)),
+                CCallHelpers::TrustedImm32(Accessor | CustomAccessor)));
+        
+        jit.load32(CCallHelpers::Address(offsetGPR, OBJECT_OFFSETOF(PropertyMapEntry, offset)), offsetGPR);
+        
+        jit.loadProperty(baseGPR, offsetGPR, valueRegs);
+        
+        allocator.restoreReusedRegistersByPopping(jit, preservedState);
+        state.succeed();
+        
+        collision.link(&amp;jit);
+
+        jit.add32(CCallHelpers::TrustedImm32(1), maskedHashGPR);
+        
+        // FIXME: We could be smarter about this. Currently we're burning a GPR for the mask. But looping
+        // around isn't super common so we could, for example, recompute the mask from the difference between
+        // the table and index. But before we do that we should probably make it easier to multiply and
+        // divide by the size of PropertyMapEntry. That probably involves making PropertyMapEntry be arranged
+        // to have a power-of-2 size.
+        jit.and32(maskGPR, maskedHashGPR);
+        jit.jump().linkTo(loop, &amp;jit);
+        
+        if (allocator.didReuseRegisters()) {
+            myFailAndIgnore.link(&amp;jit);
+            allocator.restoreReusedRegistersByPopping(jit, preservedState);
+            state.failAndIgnore.append(jit.jump());
+            
+            myFallThrough.link(&amp;jit);
+            allocator.restoreReusedRegistersByPopping(jit, preservedState);
+            fallThrough.append(jit.jump());
+        } else {
+            state.failAndIgnore.append(myFailAndIgnore);
+            fallThrough.append(myFallThrough);
+        }
+        return;
+    }
+
</ins><span class="cx">     default: {
</span><span class="cx">         if (viaProxy()) {
</span><span class="cx">             fallThrough.append(
</span><span class="cx">                 jit.branch8(
</span><span class="cx">                     CCallHelpers::NotEqual,
</span><del>-                    CCallHelpers::Address(state.baseGPR, JSCell::typeInfoTypeOffset()),
</del><ins>+                    CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()),
</ins><span class="cx">                     CCallHelpers::TrustedImm32(PureForwardingProxyType)));
</span><span class="cx"> 
</span><del>-            jit.loadPtr(
-                CCallHelpers::Address(state.baseGPR, JSProxy::targetOffset()),
-                state.scratchGPR);
</del><ins>+            jit.loadPtr(CCallHelpers::Address(baseGPR, JSProxy::targetOffset()), scratchGPR);
</ins><span class="cx"> 
</span><span class="cx">             fallThrough.append(
</span><span class="cx">                 jit.branchStructure(
</span><span class="cx">                     CCallHelpers::NotEqual,
</span><del>-                    CCallHelpers::Address(state.scratchGPR, JSCell::structureIDOffset()),
</del><ins>+                    CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()),
</ins><span class="cx">                     structure()));
</span><span class="cx">         } else {
</span><span class="cx">             fallThrough.append(
</span><span class="cx">                 jit.branchStructure(
</span><span class="cx">                     CCallHelpers::NotEqual,
</span><del>-                    CCallHelpers::Address(state.baseGPR, JSCell::structureIDOffset()),
</del><ins>+                    CCallHelpers::Address(baseGPR, JSCell::structureIDOffset()),
</ins><span class="cx">                     structure()));
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -1091,15 +1247,22 @@
</span><span class="cx"> 
</span><span class="cx">         emitIntrinsicGetter(state);
</span><span class="cx">         return;
</span><del>-    } }
</del><ins>+    }
</ins><span class="cx">     
</span><ins>+    case MegamorphicLoad:
+        // These need to be handled by generateWithGuard(), since the guard is part of the megamorphic load
+        // algorithm. We can be sure that nobody will call generate() directly for MegamorphicLoad since
+        // MegamorphicLoad is not guarded by a structure check.
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    
</ins><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PolymorphicAccess::PolymorphicAccess() { }
</span><span class="cx"> PolymorphicAccess::~PolymorphicAccess() { }
</span><span class="cx"> 
</span><del>-MacroAssemblerCodePtr PolymorphicAccess::regenerateWithCases(
</del><ins>+AccessGenerationResult PolymorphicAccess::regenerateWithCases(
</ins><span class="cx">     VM&amp; vm, CodeBlock* codeBlock, StructureStubInfo&amp; stubInfo, const Identifier&amp; ident,
</span><span class="cx">     Vector&lt;std::unique_ptr&lt;AccessCase&gt;&gt; originalCasesToAdd)
</span><span class="cx"> {
</span><span class="lines">@@ -1114,8 +1277,7 @@
</span><span class="cx">     //   and the previous stub are kept intact and the new cases are destroyed. It's OK to attempt to
</span><span class="cx">     //   add more things after failure.
</span><span class="cx">     
</span><del>-    // First, verify that we can generate code for all of the new cases while eliminating any of the
-    // new cases that replace each other.
</del><ins>+    // First ensure that the originalCasesToAdd doesn't contain duplicates.
</ins><span class="cx">     Vector&lt;std::unique_ptr&lt;AccessCase&gt;&gt; casesToAdd;
</span><span class="cx">     for (unsigned i = 0; i &lt; originalCasesToAdd.size(); ++i) {
</span><span class="cx">         std::unique_ptr&lt;AccessCase&gt; myCase = WTFMove(originalCasesToAdd[i]);
</span><span class="lines">@@ -1142,7 +1304,7 @@
</span><span class="cx">     // new stub that will be identical to the old one. Returning null should tell the caller to just
</span><span class="cx">     // keep doing what they were doing before.
</span><span class="cx">     if (casesToAdd.isEmpty())
</span><del>-        return MacroAssemblerCodePtr();
</del><ins>+        return AccessGenerationResult::MadeNoChanges;
</ins><span class="cx"> 
</span><span class="cx">     // Now construct the list of cases as they should appear if we are successful. This means putting
</span><span class="cx">     // all of the previous cases in this list in order but excluding those that can be replaced, and
</span><span class="lines">@@ -1171,22 +1333,43 @@
</span><span class="cx"> 
</span><span class="cx">     if (verbose)
</span><span class="cx">         dataLog(&quot;newCases: &quot;, listDump(newCases), &quot;\n&quot;);
</span><ins>+    
+    // See if we are close to having too many cases and if some of those cases can be subsumed by a
+    // megamorphic load.
+    if (newCases.size() &gt;= Options::maxAccessVariantListSize()) {
+        unsigned numSelfLoads = 0;
+        for (auto&amp; newCase : newCases) {
+            if (newCase-&gt;canBeReplacedByMegamorphicLoad())
+                numSelfLoads++;
+        }
+        
+        if (numSelfLoads &gt;= Options::megamorphicLoadCost()) {
+            if (auto mega = AccessCase::megamorphicLoad(vm, codeBlock)) {
+                newCases.removeAllMatching(
+                    [&amp;] (std::unique_ptr&lt;AccessCase&gt;&amp; newCase) -&gt; bool {
+                        return newCase-&gt;canBeReplacedByMegamorphicLoad();
+                    });
+                
+                newCases.append(WTFMove(mega));
+            }
+        }
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (newCases.size() &gt; Options::maxAccessVariantListSize()) {
</span><span class="cx">         if (verbose)
</span><span class="cx">             dataLog(&quot;Too many cases.\n&quot;);
</span><del>-        return MacroAssemblerCodePtr();
</del><ins>+        return AccessGenerationResult::GaveUp;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     MacroAssemblerCodePtr result = regenerate(vm, codeBlock, stubInfo, ident, newCases);
</span><span class="cx">     if (!result)
</span><del>-        return MacroAssemblerCodePtr();
</del><ins>+        return AccessGenerationResult::GaveUp;
</ins><span class="cx"> 
</span><span class="cx">     m_list = WTFMove(newCases);
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MacroAssemblerCodePtr PolymorphicAccess::regenerateWithCase(
</del><ins>+AccessGenerationResult PolymorphicAccess::regenerateWithCase(
</ins><span class="cx">     VM&amp; vm, CodeBlock* codeBlock, StructureStubInfo&amp; stubInfo, const Identifier&amp; ident,
</span><span class="cx">     std::unique_ptr&lt;AccessCase&gt; newAccess)
</span><span class="cx"> {
</span><span class="lines">@@ -1403,12 +1586,32 @@
</span><span class="cx"> 
</span><span class="cx"> using namespace JSC;
</span><span class="cx"> 
</span><ins>+void printInternal(PrintStream&amp; out, AccessGenerationResult::Kind kind)
+{
+    switch (kind) {
+    case AccessGenerationResult::MadeNoChanges:
+        out.print(&quot;MadeNoChanges&quot;);
+        return;
+    case AccessGenerationResult::GaveUp:
+        out.print(&quot;GaveUp&quot;);
+        return;
+    case AccessGenerationResult::GeneratedNewCode:
+        out.print(&quot;GeneratedNewCode&quot;);
+        return;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> void printInternal(PrintStream&amp; out, AccessCase::AccessType type)
</span><span class="cx"> {
</span><span class="cx">     switch (type) {
</span><span class="cx">     case AccessCase::Load:
</span><span class="cx">         out.print(&quot;Load&quot;);
</span><span class="cx">         return;
</span><ins>+    case AccessCase::MegamorphicLoad:
+        out.print(&quot;MegamorphicLoad&quot;);
+        return;
</ins><span class="cx">     case AccessCase::Transition:
</span><span class="cx">         out.print(&quot;Transition&quot;);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePolymorphicAccessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx"> public:
</span><span class="cx">     enum AccessType {
</span><span class="cx">         Load,
</span><ins>+        MegamorphicLoad,
</ins><span class="cx">         Transition,
</span><span class="cx">         Replace,
</span><span class="cx">         Miss,
</span><span class="lines">@@ -81,6 +82,7 @@
</span><span class="cx">         case InMiss:
</span><span class="cx">             return false;
</span><span class="cx">         case Load:
</span><ins>+        case MegamorphicLoad:
</ins><span class="cx">         case Miss:
</span><span class="cx">         case Getter:
</span><span class="cx">         case CustomValueGetter:
</span><span class="lines">@@ -96,6 +98,7 @@
</span><span class="cx">     {
</span><span class="cx">         switch (type) {
</span><span class="cx">         case Load:
</span><ins>+        case MegamorphicLoad:
</ins><span class="cx">         case Miss:
</span><span class="cx">         case Getter:
</span><span class="cx">         case CustomValueGetter:
</span><span class="lines">@@ -119,6 +122,7 @@
</span><span class="cx">     {
</span><span class="cx">         switch (type) {
</span><span class="cx">         case Load:
</span><ins>+        case MegamorphicLoad:
</ins><span class="cx">         case Miss:
</span><span class="cx">         case Getter:
</span><span class="cx">         case CustomValueGetter:
</span><span class="lines">@@ -145,7 +149,9 @@
</span><span class="cx">         WatchpointSet* additionalSet = nullptr,
</span><span class="cx">         PropertySlot::GetValueFunc = nullptr,
</span><span class="cx">         JSObject* customSlotBase = nullptr);
</span><del>-
</del><ins>+    
+    static std::unique_ptr&lt;AccessCase&gt; megamorphicLoad(VM&amp;, JSCell* owner);
+    
</ins><span class="cx">     static std::unique_ptr&lt;AccessCase&gt; replace(VM&amp;, JSCell* owner, Structure*, PropertyOffset);
</span><span class="cx"> 
</span><span class="cx">     static std::unique_ptr&lt;AccessCase&gt; transition(
</span><span class="lines">@@ -247,13 +253,15 @@
</span><span class="cx"> 
</span><span class="cx">     // Is it still possible for this case to ever be taken?
</span><span class="cx">     bool couldStillSucceed() const;
</span><del>-
</del><ins>+    
</ins><span class="cx">     static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
</span><span class="cx"> 
</span><ins>+    bool canBeReplacedByMegamorphicLoad() const;
+
</ins><span class="cx">     // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
</span><span class="cx">     // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
</span><span class="cx">     // more useful, truth. This method can be conservative; it will return false when it doubt.
</span><del>-    bool canReplace(const AccessCase&amp; other);
</del><ins>+    bool canReplace(const AccessCase&amp; other) const;
</ins><span class="cx"> 
</span><span class="cx">     void dump(PrintStream&amp; out) const;
</span><span class="cx">     
</span><span class="lines">@@ -308,6 +316,61 @@
</span><span class="cx">     std::unique_ptr&lt;RareData&gt; m_rareData;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class AccessGenerationResult {
+public:
+    enum Kind {
+        MadeNoChanges,
+        GaveUp,
+        GeneratedNewCode
+    };
+    
+    AccessGenerationResult()
+    {
+    }
+    
+    AccessGenerationResult(Kind kind)
+        : m_kind(kind)
+    {
+        ASSERT(kind != GeneratedNewCode);
+    }
+    
+    AccessGenerationResult(MacroAssemblerCodePtr code)
+        : m_kind(GeneratedNewCode)
+        , m_code(code)
+    {
+        RELEASE_ASSERT(code);
+    }
+    
+    bool operator==(const AccessGenerationResult&amp; other) const
+    {
+        return m_kind == other.m_kind &amp;&amp; m_code == other.m_code;
+    }
+    
+    bool operator!=(const AccessGenerationResult&amp; other) const
+    {
+        return !(*this == other);
+    }
+    
+    explicit operator bool() const
+    {
+        return *this != AccessGenerationResult();
+    }
+    
+    Kind kind() const { return m_kind; }
+    
+    const MacroAssemblerCodePtr&amp; code() const { return m_code; }
+    
+    bool madeNoChanges() const { return m_kind == MadeNoChanges; }
+    bool gaveUp() const { return m_kind == GaveUp; }
+    bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
+    
+    void dump(PrintStream&amp;) const;
+    
+private:
+    Kind m_kind;
+    MacroAssemblerCodePtr m_code;
+};
+
</ins><span class="cx"> class PolymorphicAccess {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="lines">@@ -318,10 +381,10 @@
</span><span class="cx">     // This may return null, in which case the old stub routine is left intact. You are required to
</span><span class="cx">     // pass a vector of non-null access cases. This will prune the access cases by rejecting any case
</span><span class="cx">     // in the list that is subsumed by a later case in the list.
</span><del>-    MacroAssemblerCodePtr regenerateWithCases(
</del><ins>+    AccessGenerationResult regenerateWithCases(
</ins><span class="cx">         VM&amp;, CodeBlock*, StructureStubInfo&amp;, const Identifier&amp;, Vector&lt;std::unique_ptr&lt;AccessCase&gt;&gt;);
</span><span class="cx"> 
</span><del>-    MacroAssemblerCodePtr regenerateWithCase(
</del><ins>+    AccessGenerationResult regenerateWithCase(
</ins><span class="cx">         VM&amp;, CodeBlock*, StructureStubInfo&amp;, const Identifier&amp;, std::unique_ptr&lt;AccessCase&gt;);
</span><span class="cx">     
</span><span class="cx">     bool isEmpty() const { return m_list.isEmpty(); }
</span><span class="lines">@@ -362,9 +425,9 @@
</span><span class="cx"> 
</span><span class="cx"> struct AccessGenerationState {
</span><span class="cx">     AccessGenerationState()
</span><del>-    : m_calculatedRegistersForCallAndExceptionHandling(false)
-    , m_needsToRestoreRegistersIfException(false)
-    , m_calculatedCallSiteIndex(false)
</del><ins>+        : m_calculatedRegistersForCallAndExceptionHandling(false)
+        , m_needsToRestoreRegistersIfException(false)
+        , m_calculatedCallSiteIndex(false)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     CCallHelpers* jit { nullptr };
</span><span class="lines">@@ -441,6 +504,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><ins>+void printInternal(PrintStream&amp;, JSC::AccessGenerationResult::Kind);
</ins><span class="cx"> void printInternal(PrintStream&amp;, JSC::AccessCase::AccessType);
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTF
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeStructureStubInfocpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008, 2014, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008, 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -104,13 +104,13 @@
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MacroAssemblerCodePtr StructureStubInfo::addAccessCase(
</del><ins>+AccessGenerationResult StructureStubInfo::addAccessCase(
</ins><span class="cx">     CodeBlock* codeBlock, const Identifier&amp; ident, std::unique_ptr&lt;AccessCase&gt; accessCase)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = *codeBlock-&gt;vm();
</span><span class="cx">     
</span><span class="cx">     if (!accessCase)
</span><del>-        return MacroAssemblerCodePtr();
</del><ins>+        return AccessGenerationResult::MadeNoChanges;
</ins><span class="cx">     
</span><span class="cx">     if (cacheType == CacheType::Stub)
</span><span class="cx">         return u.stub-&gt;regenerateWithCase(vm, codeBlock, *this, ident, WTFMove(accessCase));
</span><span class="lines">@@ -126,11 +126,11 @@
</span><span class="cx"> 
</span><span class="cx">     accessCases.append(WTFMove(accessCase));
</span><span class="cx"> 
</span><del>-    MacroAssemblerCodePtr result =
</del><ins>+    AccessGenerationResult result =
</ins><span class="cx">         access-&gt;regenerateWithCases(vm, codeBlock, *this, ident, WTFMove(accessCases));
</span><span class="cx"> 
</span><del>-    if (!result)
-        return MacroAssemblerCodePtr();
</del><ins>+    if (!result.generatedNewCode())
+        return result;
</ins><span class="cx"> 
</span><span class="cx">     initStub(codeBlock, WTFMove(access));
</span><span class="cx">     return result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeStructureStubInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008, 2012-2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008, 2012-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -33,7 +33,6 @@
</span><span class="cx"> #include &quot;ObjectPropertyConditionSet.h&quot;
</span><span class="cx"> #include &quot;Opcode.h&quot;
</span><span class="cx"> #include &quot;Options.h&quot;
</span><del>-#include &quot;PolymorphicAccess.h&quot;
</del><span class="cx"> #include &quot;RegisterSet.h&quot;
</span><span class="cx"> #include &quot;Structure.h&quot;
</span><span class="cx"> #include &quot;StructureStubClearingWatchpoint.h&quot;
</span><span class="lines">@@ -42,6 +41,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> 
</span><ins>+class AccessCase;
+class AccessGenerationResult;
</ins><span class="cx"> class PolymorphicAccess;
</span><span class="cx"> 
</span><span class="cx"> enum class AccessType : int8_t {
</span><span class="lines">@@ -68,8 +69,7 @@
</span><span class="cx">     void initPutByIdReplace(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
</span><span class="cx">     void initStub(CodeBlock*, std::unique_ptr&lt;PolymorphicAccess&gt;);
</span><span class="cx"> 
</span><del>-    MacroAssemblerCodePtr addAccessCase(
-        CodeBlock*, const Identifier&amp;, std::unique_ptr&lt;AccessCase&gt;);
</del><ins>+    AccessGenerationResult addAccessCase(CodeBlock*, const Identifier&amp;, std::unique_ptr&lt;AccessCase&gt;);
</ins><span class="cx"> 
</span><span class="cx">     void reset(CodeBlock*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -419,7 +419,43 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AssemblyHelpers::loadProperty(GPRReg object, GPRReg offset, JSValueRegs result)
+{
+    Jump isInline = branch32(LessThan, offset, TrustedImm32(firstOutOfLineOffset));
+    
+    loadPtr(Address(object, JSObject::butterflyOffset()), result.payloadGPR());
+    neg32(offset);
+    signExtend32ToPtr(offset, offset);
+    Jump ready = jump();
+    
+    isInline.link(this);
+    addPtr(
+        TrustedImm32(
+            static_cast&lt;int32_t&gt;(sizeof(JSObject)) -
+            (static_cast&lt;int32_t&gt;(firstOutOfLineOffset) - 2) * static_cast&lt;int32_t&gt;(sizeof(EncodedJSValue))),
+        object, result.payloadGPR());
+    
+    ready.link(this);
+    
+    loadValue(
+        BaseIndex(
+            result.payloadGPR(), offset, TimesEight, (firstOutOfLineOffset - 2) * sizeof(EncodedJSValue)),
+        result);
+}
+
+void AssemblyHelpers::emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
+{
</ins><span class="cx"> #if USE(JSVALUE64)
</span><ins>+    load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
+    loadPtr(vm()-&gt;heap.structureIDTable().base(), scratch);
+    loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
+#else
+    UNUSED_PARAM(scratch);
+    loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
+#endif
+}
+
+#if USE(JSVALUE64)
</ins><span class="cx"> template&lt;typename LoadFromHigh, typename StoreToHigh, typename LoadFromLow, typename StoreToLow&gt;
</span><span class="cx"> void emitRandomThunkImpl(AssemblyHelpers&amp; jit, GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, FPRReg result, const LoadFromHigh&amp; loadFromHigh, const StoreToHigh&amp; storeToHigh, const LoadFromLow&amp; loadFromLow, const StoreToLow&amp; storeToLow)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -149,6 +149,9 @@
</span><span class="cx">         }
</span><span class="cx"> #endif
</span><span class="cx">     }
</span><ins>+    
+    // Note that this clobbers offset.
+    void loadProperty(GPRReg object, GPRReg offset, JSValueRegs result);
</ins><span class="cx"> 
</span><span class="cx">     void moveValueRegs(JSValueRegs srcRegs, JSValueRegs destRegs)
</span><span class="cx">     {
</span><span class="lines">@@ -1209,30 +1212,8 @@
</span><span class="cx">         return argumentsStart(codeOrigin.inlineCallFrame);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
-    {
-#if USE(JSVALUE64)
-        load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
-        loadPtr(vm()-&gt;heap.structureIDTable().base(), scratch);
-        loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
-#else
-        UNUSED_PARAM(scratch);
-        loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
-#endif
-    }
</del><ins>+    void emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch);
</ins><span class="cx"> 
</span><del>-    static void emitLoadStructure(AssemblyHelpers&amp; jit, RegisterID base, RegisterID dest, RegisterID scratch)
-    {
-#if USE(JSVALUE64)
-        jit.load32(MacroAssembler::Address(base, JSCell::structureIDOffset()), dest);
-        jit.loadPtr(jit.vm()-&gt;heap.structureIDTable().base(), scratch);
-        jit.loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
-#else
-        UNUSED_PARAM(scratch);
-        jit.loadPtr(MacroAssembler::Address(base, JSCell::structureIDOffset()), dest);
-#endif
-    }
-
</del><span class="cx">     void emitStoreStructureWithTypeInfo(TrustedImmPtr structure, RegisterID dest, RegisterID)
</span><span class="cx">     {
</span><span class="cx">         emitStoreStructureWithTypeInfo(*this, structure, dest);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGPRInfocpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GPRInfo.cpp (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GPRInfo.cpp        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/jit/GPRInfo.cpp        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -30,6 +30,15 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+void JSValueRegs::dump(PrintStream&amp; out) const
+{
+#if USE(JSVALUE64)
+    out.print(m_gpr);
+#else
+    out.print(&quot;(tag:&quot;, tagGPR(), &quot;, payload:&quot;, payloadGPR(), &quot;)&quot;);
+#endif
+}
+
</ins><span class="cx"> // This is in the .cpp file to work around clang issues.
</span><span class="cx"> #if CPU(X86_64)
</span><span class="cx"> const GPRReg GPRInfo::patchpointScratchRegister = MacroAssembler::s_scratchRegister;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitGPRInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/GPRInfo.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/GPRInfo.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/jit/GPRInfo.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -77,6 +77,8 @@
</span><span class="cx">     
</span><span class="cx">     bool uses(GPRReg gpr) const { return m_gpr == gpr; }
</span><span class="cx">     
</span><ins>+    void dump(PrintStream&amp;) const;
+    
</ins><span class="cx"> private:
</span><span class="cx">     GPRReg m_gpr;
</span><span class="cx"> };
</span><span class="lines">@@ -202,6 +204,8 @@
</span><span class="cx"> 
</span><span class="cx">     bool uses(GPRReg gpr) const { return m_tagGPR == gpr || m_payloadGPR == gpr; }
</span><span class="cx">     
</span><ins>+    void dump(PrintStream&amp;) const;
+    
</ins><span class="cx"> private:
</span><span class="cx">     int8_t m_tagGPR;
</span><span class="cx">     int8_t m_payloadGPR;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/Repatch.cpp (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/Repatch.cpp        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/jit/Repatch.cpp        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -161,6 +161,8 @@
</span><span class="cx"> 
</span><span class="cx"> static void replaceWithJump(StructureStubInfo&amp; stubInfo, const MacroAssemblerCodePtr target)
</span><span class="cx"> {
</span><ins>+    RELEASE_ASSERT(target);
+    
</ins><span class="cx">     if (MacroAssembler::canJumpReplacePatchableBranch32WithPatch()) {
</span><span class="cx">         MacroAssembler::replaceWithJump(
</span><span class="cx">             MacroAssembler::startOfPatchableBranch32WithPatchOnAddress(
</span><span class="lines">@@ -315,14 +317,16 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    MacroAssemblerCodePtr codePtr =
-        stubInfo.addAccessCase(codeBlock, propertyName, WTFMove(newCase));
</del><ins>+    AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, propertyName, WTFMove(newCase));
</ins><span class="cx"> 
</span><del>-    if (!codePtr)
</del><ins>+    if (result.gaveUp())
</ins><span class="cx">         return GiveUpOnCache;
</span><del>-
-    replaceWithJump(stubInfo, codePtr);
</del><ins>+    if (result.madeNoChanges())
+        return RetryCacheLater;
</ins><span class="cx">     
</span><ins>+    RELEASE_ASSERT(result.code());
+    replaceWithJump(stubInfo, result.code());
+    
</ins><span class="cx">     return RetryCacheLater;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -457,16 +461,19 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    MacroAssemblerCodePtr codePtr = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
</del><ins>+    AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
</ins><span class="cx">     
</span><del>-    if (!codePtr)
</del><ins>+    if (result.gaveUp())
</ins><span class="cx">         return GiveUpOnCache;
</span><ins>+    if (result.madeNoChanges())
+        return RetryCacheLater;
</ins><span class="cx"> 
</span><ins>+    RELEASE_ASSERT(result.code());
</ins><span class="cx">     resetPutByIDCheckAndLoad(stubInfo);
</span><span class="cx">     MacroAssembler::repatchJump(
</span><span class="cx">         stubInfo.callReturnLocation.jumpAtOffset(
</span><span class="cx">             stubInfo.patch.deltaCallToJump),
</span><del>-        CodeLocationLabel(codePtr));
</del><ins>+        CodeLocationLabel(result.code()));
</ins><span class="cx">     
</span><span class="cx">     return RetryCacheLater;
</span><span class="cx"> }
</span><span class="lines">@@ -514,13 +521,16 @@
</span><span class="cx">     std::unique_ptr&lt;AccessCase&gt; newCase = AccessCase::in(
</span><span class="cx">         vm, codeBlock, wasFound ? AccessCase::InHit : AccessCase::InMiss, structure, conditionSet);
</span><span class="cx"> 
</span><del>-    MacroAssemblerCodePtr codePtr = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
-    if (!codePtr)
</del><ins>+    AccessGenerationResult result = stubInfo.addAccessCase(codeBlock, ident, WTFMove(newCase));
+    if (result.gaveUp())
</ins><span class="cx">         return GiveUpOnCache;
</span><ins>+    if (result.madeNoChanges())
+        return RetryCacheLater;
</ins><span class="cx"> 
</span><ins>+    RELEASE_ASSERT(result.code());
</ins><span class="cx">     MacroAssembler::repatchJump(
</span><span class="cx">         stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump),
</span><del>-        CodeLocationLabel(codePtr));
</del><ins>+        CodeLocationLabel(result.code()));
</ins><span class="cx">     
</span><span class="cx">     return RetryCacheLater;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitThunkGeneratorscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -191,7 +191,7 @@
</span><span class="cx">             CCallHelpers::NotEqual, GPRInfo::regT1,
</span><span class="cx">             CCallHelpers::TrustedImm32(JSValue::CellTag)));
</span><span class="cx"> #endif
</span><del>-    AssemblyHelpers::emitLoadStructure(jit, GPRInfo::regT0, GPRInfo::regT4, GPRInfo::regT1);
</del><ins>+    jit.emitLoadStructure(GPRInfo::regT0, GPRInfo::regT4, GPRInfo::regT1);
</ins><span class="cx">     slowCase.append(
</span><span class="cx">         jit.branchPtr(
</span><span class="cx">             CCallHelpers::NotEqual,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -187,7 +187,8 @@
</span><span class="cx">     v(bool, ftlCrashes, false, nullptr) /* fool-proof way of checking that you ended up in the FTL. ;-) */\
</span><span class="cx">     v(bool, clobberAllRegsInFTLICSlowPath, !ASSERT_DISABLED, nullptr) \
</span><span class="cx">     v(bool, useAccessInlining, true, nullptr) \
</span><del>-    v(unsigned, maxAccessVariantListSize, 8, nullptr) \
</del><ins>+    v(unsigned, maxAccessVariantListSize, 13, nullptr) \
+    v(unsigned, megamorphicLoadCost, 10, nullptr) \
</ins><span class="cx">     v(bool, usePolyvariantDevirtualization, true, nullptr) \
</span><span class="cx">     v(bool, usePolymorphicAccessInlining, true, nullptr) \
</span><span class="cx">     v(bool, usePolymorphicCallInlining, true, nullptr) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimePropertyMapHashTableh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/PropertyMapHashTable.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/PropertyMapHashTable.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/runtime/PropertyMapHashTable.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -191,7 +191,13 @@
</span><span class="cx">     size_t sizeInMemory();
</span><span class="cx">     void checkConsistency();
</span><span class="cx"> #endif
</span><ins>+    
+    static ptrdiff_t offsetOfIndexSize() { return OBJECT_OFFSETOF(PropertyTable, m_indexSize); }
+    static ptrdiff_t offsetOfIndexMask() { return OBJECT_OFFSETOF(PropertyTable, m_indexMask); }
+    static ptrdiff_t offsetOfIndex() { return OBJECT_OFFSETOF(PropertyTable, m_index); }
</ins><span class="cx"> 
</span><ins>+    static const unsigned EmptyEntryIndex = 0;
+
</ins><span class="cx"> private:
</span><span class="cx">     PropertyTable(VM&amp;, unsigned initialCapacity);
</span><span class="cx">     PropertyTable(VM&amp;, const PropertyTable&amp;);
</span><span class="lines">@@ -244,7 +250,6 @@
</span><span class="cx">     std::unique_ptr&lt;Vector&lt;PropertyOffset&gt;&gt; m_deletedOffsets;
</span><span class="cx"> 
</span><span class="cx">     static const unsigned MinimumTableSize = 16;
</span><del>-    static const unsigned EmptyEntryIndex = 0;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline PropertyTable::iterator PropertyTable::begin()
</span><span class="lines">@@ -272,7 +277,6 @@
</span><span class="cx">     ASSERT(key);
</span><span class="cx">     ASSERT(key-&gt;isAtomic() || key-&gt;isSymbol());
</span><span class="cx">     unsigned hash = IdentifierRepHash::hash(key);
</span><del>-    unsigned step = 0;
</del><span class="cx"> 
</span><span class="cx"> #if DUMP_PROPERTYMAP_STATS
</span><span class="cx">     ++propertyMapHashTableStats-&gt;numFinds;
</span><span class="lines">@@ -285,19 +289,16 @@
</span><span class="cx">         if (key == table()[entryIndex - 1].key)
</span><span class="cx">             return std::make_pair(&amp;table()[entryIndex - 1], hash &amp; m_indexMask);
</span><span class="cx"> 
</span><del>-        if (!step)
-            step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
-
</del><span class="cx"> #if DUMP_PROPERTYMAP_STATS
</span><span class="cx">         ++propertyMapHashTableStats-&gt;numCollisions;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if DUMP_PROPERTYMAP_COLLISIONS
</span><del>-        dataLog(&quot;PropertyTable collision for &quot;, key, &quot; (&quot;, hash, &quot;) with step &quot;, step, &quot;\n&quot;);
</del><ins>+        dataLog(&quot;PropertyTable collision for &quot;, key, &quot; (&quot;, hash, &quot;)\n&quot;);
</ins><span class="cx">         dataLog(&quot;Collided with &quot;, table()[entryIndex - 1].key, &quot;(&quot;, IdentifierRepHash::hash(table()[entryIndex - 1].key), &quot;)\n&quot;);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-        hash += step;
</del><ins>+        hash++;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -310,7 +311,6 @@
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="cx">     unsigned hash = IdentifierRepHash::hash(key);
</span><del>-    unsigned step = 0;
</del><span class="cx"> 
</span><span class="cx"> #if DUMP_PROPERTYMAP_STATS
</span><span class="cx">     ++propertyMapHashTableStats-&gt;numLookups;
</span><span class="lines">@@ -327,9 +327,7 @@
</span><span class="cx">         ++propertyMapHashTableStats-&gt;numLookupProbing;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-        if (!step)
-            step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
-        hash += step;
</del><ins>+        hash++;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (199068 => 199069)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2016-04-05 19:40:07 UTC (rev 199068)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2016-04-05 19:58:04 UTC (rev 199069)
</span><span class="lines">@@ -420,6 +420,11 @@
</span><span class="cx">     {
</span><span class="cx">         return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset();
</span><span class="cx">     }
</span><ins>+    
+    static ptrdiff_t propertyTableUnsafeOffset()
+    {
+        return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
+    }
</ins><span class="cx"> 
</span><span class="cx">     static Structure* createStructure(VM&amp;);
</span><span class="cx">         
</span></span></pre>
</div>
</div>

</body>
</html>