<!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>[169902] branches/ftlopt</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/169902">169902</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-06-12 10:42:10 -0700 (Thu, 12 Jun 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ftlopt] DFG get_by_id should inline chain accesses with a slightly polymorphic base
https://bugs.webkit.org/show_bug.cgi?id=133751

Reviewed by Mark Hahnenberg.


Source/JavaScriptCore: 
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::appendVariant):
(JSC::GetByIdStatus::computeForStubInfo):
* bytecode/GetByIdVariant.cpp:
(JSC::GetByIdVariant::attemptToMerge):
* bytecode/GetByIdVariant.h:
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFor):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::emitPrototypeChecks):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::handlePutById):
* runtime/IntendedStructureChain.cpp:
(JSC::IntendedStructureChain::IntendedStructureChain):
(JSC::IntendedStructureChain::isStillValid):
(JSC::IntendedStructureChain::isNormalized):
(JSC::IntendedStructureChain::terminalPrototype):
(JSC::IntendedStructureChain::operator==):
(JSC::IntendedStructureChain::visitChildren):
(JSC::IntendedStructureChain::dumpInContext):
(JSC::IntendedStructureChain::chain): Deleted.
* runtime/IntendedStructureChain.h:
(JSC::IntendedStructureChain::prototype):
(JSC::IntendedStructureChain::operator!=):
(JSC::IntendedStructureChain::head): Deleted.

LayoutTests: 
* js/regress/poly-chain-access-expected.txt: Added.
* js/regress/poly-chain-access-simpler-expected.txt: Added.
* js/regress/poly-chain-access-simpler.html: Added.
* js/regress/poly-chain-access.html: Added.
* js/regress/script-tests/poly-chain-access-simpler.js: Added.
* js/regress/script-tests/poly-chain-access.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsChangeLog">branches/ftlopt/LayoutTests/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreChangeLog">branches/ftlopt/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChaincpp">branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChainh">branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsjsregresspolychainaccessexpectedtxt">branches/ftlopt/LayoutTests/js/regress/poly-chain-access-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregresspolychainaccesssimplerexpectedtxt">branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregresspolychainaccesssimplerhtml">branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregresspolychainaccesshtml">branches/ftlopt/LayoutTests/js/regress/poly-chain-access.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestspolychainaccesssimplerjs">branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access-simpler.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestspolychainaccessjs">branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/LayoutTests/ChangeLog (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/ChangeLog        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/LayoutTests/ChangeLog        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-06-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG get_by_id should inline chain accesses with a slightly polymorphic base
+        https://bugs.webkit.org/show_bug.cgi?id=133751
+
+        Reviewed by Mark Hahnenberg.
+
+        * js/regress/poly-chain-access-expected.txt: Added.
+        * js/regress/poly-chain-access-simpler-expected.txt: Added.
+        * js/regress/poly-chain-access-simpler.html: Added.
+        * js/regress/poly-chain-access.html: Added.
+        * js/regress/script-tests/poly-chain-access-simpler.js: Added.
+        * js/regress/script-tests/poly-chain-access.js: Added.
+
</ins><span class="cx"> 2014-06-01  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ftlopt] AI should be able track structure sets larger than 1
</span></span></pre></div>
<a id="branchesftloptLayoutTestsjsregresspolychainaccessexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/poly-chain-access-expected.txt (0 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/poly-chain-access-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/poly-chain-access-expected.txt        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/poly-chain-access
+
+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="branchesftloptLayoutTestsjsregresspolychainaccesssimplerexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler-expected.txt (0 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler-expected.txt        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/poly-chain-access-simpler
+
+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="branchesftloptLayoutTestsjsregresspolychainaccesssimplerhtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler.html (0 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/poly-chain-access-simpler.html        2014-06-12 17:42:10 UTC (rev 169902)
</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/poly-chain-access-simpler.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="branchesftloptLayoutTestsjsregresspolychainaccesshtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/poly-chain-access.html (0 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/poly-chain-access.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/poly-chain-access.html        2014-06-12 17:42:10 UTC (rev 169902)
</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/poly-chain-access.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="branchesftloptLayoutTestsjsregressscripttestspolychainaccesssimplerjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access-simpler.js (0 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access-simpler.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access-simpler.js        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+(function() {
+    function Foo() { }
+    Foo.prototype.f = 42;
+    function Bar() { }
+    Bar.prototype = new Foo();
+
+    function foo(o, p) {
+        var n = 1000000;
+        var result = 0;
+        for (var i = 0; i &lt; n; ++i) {
+            result += o.f;
+            var tmp = o;
+            o = p;
+            p = tmp;
+        }
+        
+        if (result != n * 42)
+            throw &quot;Error: bad result: &quot; + result;
+    }
+
+    var o = new Bar();
+    var p = new Bar();
+    p.g = 43;
+    
+    foo(o, p);
+})();
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestspolychainaccessjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access.js (0 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/poly-chain-access.js        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+(function() {
+    function Foo() { }
+    Foo.prototype.f = 42;
+    function Bar() { }
+    Bar.prototype = new Foo();
+    
+    var o = new Bar();
+    var p = new Bar();
+    p.g = 43;
+    
+    var n = 1000000;
+    var result = 0;
+    for (var i = 0; i &lt; n; ++i) {
+        result += o.f;
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    
+    if (result != n * 42)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2014-06-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG get_by_id should inline chain accesses with a slightly polymorphic base
+        https://bugs.webkit.org/show_bug.cgi?id=133751
+
+        Reviewed by Mark Hahnenberg.
+
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::appendVariant):
+        (JSC::GetByIdStatus::computeForStubInfo):
+        * bytecode/GetByIdVariant.cpp:
+        (JSC::GetByIdVariant::attemptToMerge):
+        * bytecode/GetByIdVariant.h:
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeFor):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::emitPrototypeChecks):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::handlePutById):
+        * runtime/IntendedStructureChain.cpp:
+        (JSC::IntendedStructureChain::IntendedStructureChain):
+        (JSC::IntendedStructureChain::isStillValid):
+        (JSC::IntendedStructureChain::isNormalized):
+        (JSC::IntendedStructureChain::terminalPrototype):
+        (JSC::IntendedStructureChain::operator==):
+        (JSC::IntendedStructureChain::visitChildren):
+        (JSC::IntendedStructureChain::dumpInContext):
+        (JSC::IntendedStructureChain::chain): Deleted.
+        * runtime/IntendedStructureChain.h:
+        (JSC::IntendedStructureChain::prototype):
+        (JSC::IntendedStructureChain::operator!=):
+        (JSC::IntendedStructureChain::head): Deleted.
+
</ins><span class="cx"> 2014-06-11  Matthew Mirman  &lt;mmirman@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">        Readded native calling to the FTL and Split the DFG nodes 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -39,10 +39,20 @@
</span><span class="cx"> 
</span><span class="cx"> bool GetByIdStatus::appendVariant(const GetByIdVariant&amp; variant)
</span><span class="cx"> {
</span><ins>+    // Attempt to merge this variant with an already existing variant.
</ins><span class="cx">     for (unsigned i = 0; i &lt; m_variants.size(); ++i) {
</span><ins>+        if (m_variants[i].attemptToMerge(variant))
+            return true;
+    }
+    
+    // Make sure there is no overlap. We should have pruned out opportunities for
+    // overlap but it's possible that an inline cache got into a weird state. We are
+    // defensive and bail if we detect crazy.
+    for (unsigned i = 0; i &lt; m_variants.size(); ++i) {
</ins><span class="cx">         if (m_variants[i].structureSet().overlaps(variant.structureSet()))
</span><span class="cx">             return false;
</span><span class="cx">     }
</span><ins>+    
</ins><span class="cx">     m_variants.append(variant);
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="lines">@@ -187,10 +197,12 @@
</span><span class="cx">                     profiledBlock, structure, list-&gt;at(listIndex).chain(),
</span><span class="cx">                     list-&gt;at(listIndex).chainCount()));
</span><span class="cx">                 
</span><del>-                if (!chain-&gt;isStillValid())
-                    return GetByIdStatus(slowPathState, true);
</del><ins>+                if (!chain-&gt;isStillValid()) {
+                    // This won't ever run again so skip it.
+                    continue;
+                }
</ins><span class="cx">                 
</span><del>-                if (chain-&gt;head()-&gt;takesSlowPathInDFGForImpureProperty())
</del><ins>+                if (structure-&gt;takesSlowPathInDFGForImpureProperty())
</ins><span class="cx">                     return GetByIdStatus(slowPathState, true);
</span><span class="cx">                 
</span><span class="cx">                 size_t chainSize = chain-&gt;size();
</span><span class="lines">@@ -217,36 +229,7 @@
</span><span class="cx">             
</span><span class="cx">             if (!isValidOffset(myOffset))
</span><span class="cx">                 return GetByIdStatus(slowPathState, true);
</span><del>-
-            if (!chain &amp;&amp; !list-&gt;at(listIndex).doesCalls()) {
-                // For non-chain, non-getter accesses, we try to do some coalescing.
-                bool found = false;
-                for (unsigned variantIndex = 0; variantIndex &lt; result.m_variants.size(); ++variantIndex) {
-                    GetByIdVariant&amp; variant = result.m_variants[variantIndex];
-                    if (variant.m_chain)
-                        continue;
-                
-                    if (variant.m_offset != myOffset)
-                        continue;
-                
-                    if (variant.callLinkStatus())
-                        continue;
-                
-                    found = true;
-                    if (variant.m_structureSet.contains(structure))
-                        break;
-                
-                    if (variant.m_specificValue != JSValue(specificValue))
-                        variant.m_specificValue = JSValue();
-                
-                    variant.m_structureSet.add(structure);
-                    break;
-                }
</del><span class="cx">             
</span><del>-                if (found)
-                    continue;
-            }
-            
</del><span class="cx">             std::unique_ptr&lt;CallLinkStatus&gt; callLinkStatus;
</span><span class="cx">             switch (list-&gt;at(listIndex).type()) {
</span><span class="cx">             case GetByIdAccess::SimpleInline:
</span><span class="lines">@@ -272,6 +255,7 @@
</span><span class="cx">             GetByIdVariant variant(
</span><span class="cx">                 StructureSet(structure), myOffset, specificValue, chain,
</span><span class="cx">                 std::move(callLinkStatus));
</span><ins>+            
</ins><span class="cx">             if (!result.appendVariant(variant))
</span><span class="cx">                 return GetByIdStatus(slowPathState, true);
</span><span class="cx">         }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -51,6 +51,25 @@
</span><span class="cx">     return *this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool GetByIdVariant::attemptToMerge(const GetByIdVariant&amp; other)
+{
+    if (!!m_chain != !!other.m_chain)
+        return false;
+    if (m_chain &amp;&amp; *m_chain != *other.m_chain)
+        return false;
+    if (m_offset != other.m_offset)
+        return false;
+    if (m_callLinkStatus || other.m_callLinkStatus)
+        return false;
+    
+    if (m_specificValue != other.m_specificValue)
+        m_specificValue = JSValue();
+
+    m_structureSet.merge(other.m_structureSet);
+    
+    return true;
+}
+
</ins><span class="cx"> void GetByIdVariant::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     dumpInContext(out, 0);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -71,6 +71,8 @@
</span><span class="cx">     PropertyOffset offset() const { return m_offset; }
</span><span class="cx">     CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); }
</span><span class="cx">     
</span><ins>+    bool attemptToMerge(const GetByIdVariant&amp; other);
+    
</ins><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     void dumpInContext(PrintStream&amp;, DumpContext*) const;
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -309,7 +309,7 @@
</span><span class="cx">         // dictionaries if we have evidence to suggest that those objects were never used as
</span><span class="cx">         // prototypes in a cacheable prototype access - i.e. there's a good chance that some of
</span><span class="cx">         // the other checks below will fail.
</span><del>-        if (!chain-&gt;isNormalized())
</del><ins>+        if (structure-&gt;isProxy() || !chain-&gt;isNormalized())
</ins><span class="cx">             return PutByIdStatus(TakesSlowPath);
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -192,7 +192,7 @@
</span><span class="cx">     void handlePutById(
</span><span class="cx">         Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&amp;,
</span><span class="cx">         bool isDirect);
</span><del>-    Node* emitPrototypeChecks(Structure*, IntendedStructureChain*);
</del><ins>+    Node* emitPrototypeChecks(IntendedStructureChain*);
</ins><span class="cx"> 
</span><span class="cx">     Node* getScope(bool skipTop, unsigned skipCount);
</span><span class="cx">     
</span><span class="lines">@@ -1705,18 +1705,18 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Node* ByteCodeParser::emitPrototypeChecks(
-    Structure* structure, IntendedStructureChain* chain)
</del><ins>+Node* ByteCodeParser::emitPrototypeChecks(IntendedStructureChain* chain)
</ins><span class="cx"> {
</span><del>-    ASSERT(structure);
-    Node* base = 0;
</del><span class="cx">     m_graph.chains().addLazily(chain);
</span><del>-    Structure* currentStructure = structure;
-    JSObject* currentObject = 0;
</del><ins>+    JSValue prototype = chain-&gt;prototype();
+    if (prototype.isNull())
+        return nullptr;
+    Node* base = nullptr;
</ins><span class="cx">     for (unsigned i = 0; i &lt; chain-&gt;size(); ++i) {
</span><del>-        currentObject = asObject(currentStructure-&gt;prototypeForLookup(m_inlineStackTop-&gt;m_codeBlock));
-        currentStructure = chain-&gt;at(i);
</del><ins>+        JSObject* currentObject = asObject(prototype);
+        Structure* currentStructure = chain-&gt;at(i);
</ins><span class="cx">         base = cellConstantWithStructureCheck(currentObject, currentStructure);
</span><ins>+        prototype = currentStructure-&gt;prototypeForLookup(m_inlineStackTop-&gt;m_codeBlock);
</ins><span class="cx">     }
</span><span class="cx">     return base;
</span><span class="cx"> }
</span><span class="lines">@@ -1748,11 +1748,8 @@
</span><span class="cx">         //    optimal, if there is some rarely executed case in the chain that requires a lot
</span><span class="cx">         //    of checks and those checks are not watchpointable.
</span><span class="cx">         for (unsigned variantIndex = getByIdStatus.numVariants(); variantIndex--;) {
</span><del>-            if (getByIdStatus[variantIndex].chain()) {
-                emitPrototypeChecks(
-                    getByIdStatus[variantIndex].structureSet().onlyStructure(),
-                    getByIdStatus[variantIndex].chain());
-            }
</del><ins>+            if (getByIdStatus[variantIndex].chain())
+                emitPrototypeChecks(getByIdStatus[variantIndex].chain());
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // 2) Emit a MultiGetByOffset
</span><span class="lines">@@ -1774,10 +1771,8 @@
</span><span class="cx">                 
</span><span class="cx">     addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base);
</span><span class="cx">     
</span><del>-    if (variant.chain()) {
-        base = emitPrototypeChecks(
-            variant.structureSet().onlyStructure(), variant.chain());
-    }
</del><ins>+    if (variant.chain())
+        base = emitPrototypeChecks(variant.chain());
</ins><span class="cx">     
</span><span class="cx">     // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to
</span><span class="cx">     // ensure that the base of the original get_by_id is kept alive until we're done with
</span><span class="lines">@@ -1876,9 +1871,7 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 if (!putByIdStatus[variantIndex].structureChain())
</span><span class="cx">                     continue;
</span><del>-                emitPrototypeChecks(
-                    putByIdStatus[variantIndex].oldStructure(),
-                    putByIdStatus[variantIndex].structureChain());
</del><ins>+                emitPrototypeChecks(putByIdStatus[variantIndex].structureChain());
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -1914,7 +1907,7 @@
</span><span class="cx">                 
</span><span class="cx">     addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base);
</span><span class="cx">     if (!isDirect)
</span><del>-        emitPrototypeChecks(variant.oldStructure(), variant.structureChain());
</del><ins>+        emitPrototypeChecks(variant.structureChain());
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(variant.oldStructure()-&gt;transitionWatchpointSetHasBeenInvalidated());
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChaincpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -33,27 +33,37 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-IntendedStructureChain::IntendedStructureChain(JSGlobalObject* globalObject, Structure* head)
</del><ins>+IntendedStructureChain::IntendedStructureChain(JSGlobalObject* globalObject, JSValue prototype)
</ins><span class="cx">     : m_globalObject(globalObject)
</span><del>-    , m_head(head)
</del><ins>+    , m_prototype(prototype)
</ins><span class="cx"> {
</span><del>-    JSValue prototype = head-&gt;prototypeForLookup(globalObject);
</del><ins>+    ASSERT(m_prototype.isNull() || m_prototype.isObject());
</ins><span class="cx">     if (prototype.isNull())
</span><span class="cx">         return;
</span><span class="cx">     for (Structure* current = asObject(prototype)-&gt;structure(); current; current = current-&gt;storedPrototypeStructure())
</span><span class="cx">         m_vector.append(current);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+IntendedStructureChain::IntendedStructureChain(JSGlobalObject* globalObject, Structure* head)
+    : m_globalObject(globalObject)
+    , m_prototype(head-&gt;prototypeForLookup(m_globalObject))
+{
+    if (m_prototype.isNull())
+        return;
+    for (Structure* current = asObject(m_prototype)-&gt;structure(); current; current = current-&gt;storedPrototypeStructure())
+        m_vector.append(current);
+}
+
</ins><span class="cx"> IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, Structure* prototypeStructure)
</span><span class="cx">     : m_globalObject(codeBlock-&gt;globalObject())
</span><del>-    , m_head(head)
</del><ins>+    , m_prototype(head-&gt;prototypeForLookup(m_globalObject))
</ins><span class="cx"> {
</span><span class="cx">     m_vector.append(prototypeStructure);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain)
</span><span class="cx">     : m_globalObject(codeBlock-&gt;globalObject())
</span><del>-    , m_head(head)
</del><ins>+    , m_prototype(head-&gt;prototypeForLookup(m_globalObject))
</ins><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; chain-&gt;head()[i]; ++i)
</span><span class="cx">         m_vector.append(chain-&gt;head()[i].get());
</span><span class="lines">@@ -61,7 +71,7 @@
</span><span class="cx"> 
</span><span class="cx"> IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain, unsigned count)
</span><span class="cx">     : m_globalObject(codeBlock-&gt;globalObject())
</span><del>-    , m_head(head)
</del><ins>+    , m_prototype(head-&gt;prototypeForLookup(m_globalObject))
</ins><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; i &lt; count; ++i)
</span><span class="cx">         m_vector.append(chain-&gt;head()[i].get());
</span><span class="lines">@@ -73,7 +83,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool IntendedStructureChain::isStillValid() const
</span><span class="cx"> {
</span><del>-    JSValue currentPrototype = m_head-&gt;prototypeForLookup(m_globalObject);
</del><ins>+    JSValue currentPrototype = m_prototype;
</ins><span class="cx">     for (unsigned i = 0; i &lt; m_vector.size(); ++i) {
</span><span class="cx">         if (asObject(currentPrototype)-&gt;structure() != m_vector[i])
</span><span class="cx">             return false;
</span><span class="lines">@@ -93,14 +103,6 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-StructureChain* IntendedStructureChain::chain(VM&amp; vm) const
-{
-    ASSERT(isStillValid());
-    StructureChain* result = StructureChain::create(vm, m_head);
-    ASSERT(matches(result));
-    return result;
-}
-
</del><span class="cx"> bool IntendedStructureChain::mayInterceptStoreTo(VM&amp; vm, StringImpl* uid)
</span><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; i &lt; m_vector.size(); ++i) {
</span><span class="lines">@@ -118,8 +120,6 @@
</span><span class="cx"> 
</span><span class="cx"> bool IntendedStructureChain::isNormalized()
</span><span class="cx"> {
</span><del>-    if (m_head-&gt;isProxy())
-        return false;
</del><span class="cx">     for (unsigned i = 0; i &lt; m_vector.size(); ++i) {
</span><span class="cx">         Structure* structure = m_vector[i];
</span><span class="cx">         if (structure-&gt;isProxy())
</span><span class="lines">@@ -134,14 +134,21 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_vector.isEmpty());
</span><span class="cx">     if (m_vector.size() == 1)
</span><del>-        return asObject(m_head-&gt;prototypeForLookup(m_globalObject));
</del><ins>+        return asObject(m_prototype);
</ins><span class="cx">     return asObject(m_vector[m_vector.size() - 2]-&gt;storedPrototype());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool IntendedStructureChain::operator==(const IntendedStructureChain&amp; other) const
+{
+    return m_globalObject == other.m_globalObject
+        &amp;&amp; m_prototype == other.m_prototype
+        &amp;&amp; m_vector == other.m_vector;
+}
+
</ins><span class="cx"> void IntendedStructureChain::visitChildren(SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><span class="cx">     visitor.appendUnbarrieredPointer(&amp;m_globalObject);
</span><del>-    visitor.appendUnbarrieredPointer(&amp;m_head);
</del><ins>+    visitor.appendUnbarrieredValue(&amp;m_prototype);
</ins><span class="cx">     for (unsigned i = m_vector.size(); i--;)
</span><span class="cx">         visitor.appendUnbarrieredPointer(&amp;m_vector[i]);
</span><span class="cx"> }
</span><span class="lines">@@ -155,7 +162,7 @@
</span><span class="cx"> {
</span><span class="cx">     out.print(
</span><span class="cx">         &quot;(global = &quot;, RawPointer(m_globalObject), &quot;, head = &quot;,
</span><del>-        pointerDumpInContext(m_head, context), &quot;, vector = [&quot;);
</del><ins>+        inContext(m_prototype, context), &quot;, vector = [&quot;);
</ins><span class="cx">     CommaPrinter comma;
</span><span class="cx">     for (unsigned i = 0; i &lt; m_vector.size(); ++i)
</span><span class="cx">         out.print(comma, pointerDumpInContext(m_vector[i], context));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreruntimeIntendedStructureChainh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h (169901 => 169902)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h        2014-06-12 17:33:05 UTC (rev 169901)
+++ branches/ftlopt/Source/JavaScriptCore/runtime/IntendedStructureChain.h        2014-06-12 17:42:10 UTC (rev 169902)
</span><span class="lines">@@ -39,7 +39,8 @@
</span><span class="cx"> 
</span><span class="cx"> class IntendedStructureChain : public RefCounted&lt;IntendedStructureChain&gt; {
</span><span class="cx"> public:
</span><del>-    IntendedStructureChain(JSGlobalObject* globalObject, Structure* head);
</del><ins>+    IntendedStructureChain(JSGlobalObject* globalObject, JSValue prototype);
+    IntendedStructureChain(JSGlobalObject* globalObject, Structure*);
</ins><span class="cx">     IntendedStructureChain(CodeBlock* codeBlock, Structure* head, Structure* prototypeStructure);
</span><span class="cx">     IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain);
</span><span class="cx">     IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain, unsigned count);
</span><span class="lines">@@ -47,11 +48,10 @@
</span><span class="cx">     
</span><span class="cx">     bool isStillValid() const;
</span><span class="cx">     bool matches(StructureChain*) const;
</span><del>-    StructureChain* chain(VM&amp;) const;
</del><span class="cx">     bool mayInterceptStoreTo(VM&amp;, StringImpl* uid);
</span><span class="cx">     bool isNormalized();
</span><span class="cx">     
</span><del>-    Structure* head() const { return m_head; }
</del><ins>+    JSValue prototype() const { return m_prototype; }
</ins><span class="cx">     
</span><span class="cx">     size_t size() const { return m_vector.size(); }
</span><span class="cx">     Structure* at(size_t index) { return m_vector[index]; }
</span><span class="lines">@@ -61,13 +61,19 @@
</span><span class="cx">     
</span><span class="cx">     Structure* last() const { return m_vector.last(); }
</span><span class="cx">     
</span><ins>+    bool operator==(const IntendedStructureChain&amp;) const;
+    bool operator!=(const IntendedStructureChain&amp; other) const
+    {
+        return !(*this == other);
+    }
+    
</ins><span class="cx">     void visitChildren(SlotVisitor&amp;);
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     void dumpInContext(PrintStream&amp;, DumpContext*) const;
</span><span class="cx">     
</span><span class="cx"> private:
</span><span class="cx">     JSGlobalObject* m_globalObject;
</span><del>-    Structure* m_head;
</del><ins>+    JSValue m_prototype;
</ins><span class="cx">     Vector&lt;Structure*&gt; m_vector;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>