<!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>[170275] 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/170275">170275</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-06-22 18:02:01 -0700 (Sun, 22 Jun 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
https://bugs.webkit.org/show_bug.cgi?id=134090

Reviewed by Oliver Hunt.

Source/JavaScriptCore: 
        
This pretty much finishes off the work to eliminate the special-casing of singleton
structure sets by making it possible to fold GetById and PutById to various polymorphic
forms of the ByOffset nodes.
        
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeForStubInfo):
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdStatus.h:
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFor):
* bytecode/PutByIdStatus.h:
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::constantChecks):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
(JSC::DFG::ConstantFoldingPhase::addChecks):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToMultiGetByOffset):
(JSC::DFG::Node::convertToMultiPutByOffset):
* dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging.
(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt52):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compileLogicalNot):
(JSC::DFG::SpeculativeJIT::emitBranch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::set):

LayoutTests: 

* js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt: Added.
* js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt: Added.
* js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html: Added.
* js/regress/fold-get-by-id-to-multi-get-by-offset.html: Added.
* js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt: Added.
* js/regress/fold-put-by-id-to-multi-put-by-offset.html: Added.
* js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js: Added.
(foo):
(fu):
(bar):
(.bar):
(Number):
* js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
(Number):
* js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):</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="#branchesftloptSourceJavaScriptCorebytecodeGetByIdStatush">branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdStatush">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGNodeh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGStructureAbstractValueh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsetrareintexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsetrareinthtml">branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldputbyidtomultiputbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldputbyidtomultiputbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldgetbyidtomultigetbyoffsetrareintjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldgetbyidtomultigetbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldputbyidtomultiputbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/LayoutTests/ChangeLog (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/ChangeLog        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/LayoutTests/ChangeLog        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -1,3 +1,34 @@
</span><ins>+2014-06-21  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
+        https://bugs.webkit.org/show_bug.cgi?id=134090
+
+        Reviewed by Oliver Hunt.
+
+        * js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt: Added.
+        * js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt: Added.
+        * js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html: Added.
+        * js/regress/fold-get-by-id-to-multi-get-by-offset.html: Added.
+        * js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt: Added.
+        * js/regress/fold-put-by-id-to-multi-put-by-offset.html: Added.
+        * js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        (Number):
+        * js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        (Number):
+        * js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+
</ins><span class="cx"> 2014-06-19  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ftlopt] LICM should be able to hoist CheckStructure even if the loop clobbers structures so long as the structures being checked are watchable
</span></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-expected.txt        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-get-by-id-to-multi-get-by-offset
+
+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="branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsetrareintexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int-expected.txt        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-get-by-id-to-multi-get-by-offset-rare-int
+
+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="branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsetrareinthtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset-rare-int.html        2014-06-23 01:02:01 UTC (rev 170275)
</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/fold-get-by-id-to-multi-get-by-offset-rare-int.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="branchesftloptLayoutTestsjsregressfoldgetbyidtomultigetbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset.html (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-get-by-id-to-multi-get-by-offset.html        2014-06-23 01:02:01 UTC (rev 170275)
</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/fold-get-by-id-to-multi-get-by-offset.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="branchesftloptLayoutTestsjsregressfoldputbyidtomultiputbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset-expected.txt        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-put-by-id-to-multi-put-by-offset
+
+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="branchesftloptLayoutTestsjsregressfoldputbyidtomultiputbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset.html (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-put-by-id-to-multi-put-by-offset.html        2014-06-23 01:02:01 UTC (rev 170275)
</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/fold-put-by-id-to-multi-put-by-offset.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="branchesftloptLayoutTestsjsregressscripttestsfoldgetbyidtomultigetbyoffsetrareintjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset-rare-int.js        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+function fu(o) {
+    return o.e;
+}
+
+function bar(f, o) {
+    return f(o);
+}
+
+for (var i = 0; i &lt; 1000; ++i) {
+    var o = {f:1};
+    o[&quot;i&quot; + i] = 42;
+    foo(o);
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+
+Number.prototype.f = 100;
+    
+(function(f, o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n + 1; ++i) {
+        result += fu(o);
+        var q;
+        if (i == n)
+            q = 42;
+        else
+            q = o;
+        result += bar(f, q);
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != (o.f + o.e + p.f + p.e) * n / 2 + 100 + p.e)
+        throw &quot;Error: bad result: &quot; + result;
+})(foo, {f:42, e:43}, {e:44, f:45});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldgetbyidtomultigetbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-get-by-id-to-multi-get-by-offset.js        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+function fu(o) {
+    return o.e;
+}
+
+function bar(f, o) {
+    return f(o);
+}
+
+for (var i = 0; i &lt; 1000; ++i) {
+    var o = {f:1};
+    o[&quot;i&quot; + i] = 42;
+    foo(o);
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+
+Number.prototype.f = 100;
+    
+(function(f, o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        result += fu(o);
+        result += bar(f, o);
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != (o.f + o.e + p.f + p.e) * n / 2)
+        throw &quot;Error: bad result: &quot; + result;
+})(foo, {f:42, e:43}, {e:44, f:45});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldputbyidtomultiputbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js (0 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-by-id-to-multi-put-by-offset.js        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+function foo(o) {
+    o.f = 1;
+}
+
+function fu(o) {
+    o.e = 2;
+}
+
+function bar(f, o) {
+    f(o);
+}
+
+for (var i = 0; i &lt; 1000; ++i) {
+    var o = {};
+    o[&quot;i&quot; + i] = 42;
+    foo(o);
+    fu({f:1, e:2});
+    fu({e:1, f:2, g:3});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+    
+(function(f, o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        fu(o);
+        bar(f, o);
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (o.e != 2)
+        throw &quot;Error: bad value in o.e: &quot; + o.e;
+    if (o.f != 1)
+        throw &quot;Error: bad value in o.f: &quot; + o.f;
+    if (p.e != 2)
+        throw &quot;Error: bad value in p.e: &quot; + p.e;
+    if (p.f != 1)
+        throw &quot;Error: bad value in p.f: &quot; + p.f;
+})(foo, {f:42, e:23}, {e:23, f:42, g:100});
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -1,3 +1,50 @@
</span><ins>+2014-06-21  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] Fold GetById/PutById to MultiGetByOffset/GetByOffset or MultiPutByOffset/PutByOffset, which implies handling non-singleton sets
+        https://bugs.webkit.org/show_bug.cgi?id=134090
+
+        Reviewed by Oliver Hunt.
+        
+        This pretty much finishes off the work to eliminate the special-casing of singleton
+        structure sets by making it possible to fold GetById and PutById to various polymorphic
+        forms of the ByOffset nodes.
+        
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeForStubInfo):
+        (JSC::GetByIdStatus::computeFor):
+        * bytecode/GetByIdStatus.h:
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeFor):
+        * bytecode/PutByIdStatus.h:
+        * bytecode/PutByIdVariant.h:
+        (JSC::PutByIdVariant::constantChecks):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+        (JSC::DFG::ConstantFoldingPhase::addChecks):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToMultiGetByOffset):
+        (JSC::DFG::Node::convertToMultiPutByOffset):
+        * dfg/DFGSpeculativeJIT64.cpp: Also convert all release assertions to DFG assertions in this file, because I was hitting some of them while debugging.
+        (JSC::DFG::SpeculativeJIT::fillJSValue):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeCompareNull):
+        (JSC::DFG::SpeculativeJIT::emitCall):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Strict):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateInt52):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
+        (JSC::DFG::SpeculativeJIT::compileLogicalNot):
+        (JSC::DFG::SpeculativeJIT::emitBranch):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureAbstractValue.h:
+        (JSC::DFG::StructureAbstractValue::set):
+
</ins><span class="cx"> 2014-06-20  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Merge r169903 to the branch.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -170,7 +170,8 @@
</span><span class="cx">         
</span><span class="cx">         variant.m_structureSet.add(structure);
</span><span class="cx">         variant.m_specificValue = JSValue(specificValue);
</span><del>-        result.appendVariant(variant);
</del><ins>+        bool didAppend = result.appendVariant(variant);
+        ASSERT_UNUSED(didAppend, didAppend);
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="lines">@@ -312,34 +313,43 @@
</span><span class="cx">     return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-GetByIdStatus GetByIdStatus::computeFor(VM&amp; vm, Structure* structure, StringImpl* uid)
</del><ins>+GetByIdStatus GetByIdStatus::computeFor(VM&amp; vm, const StructureSet&amp; set, StringImpl* uid)
</ins><span class="cx"> {
</span><span class="cx">     // For now we only handle the super simple self access case. We could handle the
</span><span class="cx">     // prototype case in the future.
</span><span class="cx">     
</span><del>-    if (!structure)
-        return GetByIdStatus(TakesSlowPath);
</del><ins>+    if (set.isEmpty())
+        return GetByIdStatus();
</ins><span class="cx"> 
</span><span class="cx">     if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
</span><span class="cx">         return GetByIdStatus(TakesSlowPath);
</span><span class="cx">     
</span><del>-    if (structure-&gt;typeInfo().overridesGetOwnPropertySlot() &amp;&amp; structure-&gt;typeInfo().type() != GlobalObjectType)
-        return GetByIdStatus(TakesSlowPath);
</del><ins>+    GetByIdStatus result;
+    result.m_state = Simple;
+    result.m_wasSeenInJIT = false;
+    for (unsigned i = 0; i &lt; set.size(); ++i) {
+        Structure* structure = set[i];
+        if (structure-&gt;typeInfo().overridesGetOwnPropertySlot() &amp;&amp; structure-&gt;typeInfo().type() != GlobalObjectType)
+            return GetByIdStatus(TakesSlowPath);
+        
+        if (!structure-&gt;propertyAccessesAreCacheable())
+            return GetByIdStatus(TakesSlowPath);
+        
+        unsigned attributes;
+        JSCell* specificValue;
+        PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes, specificValue);
+        if (!isValidOffset(offset))
+            return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
+        if (attributes &amp; Accessor)
+            return GetByIdStatus(MakesCalls); // We could be smarter here, like strenght-reducing this to a Call.
+        if (structure-&gt;isDictionary())
+            specificValue = 0;
+        
+        if (!result.appendVariant(GetByIdVariant(structure, offset, specificValue)))
+            return GetByIdStatus(TakesSlowPath);
+    }
</ins><span class="cx">     
</span><del>-    if (!structure-&gt;propertyAccessesAreCacheable())
-        return GetByIdStatus(TakesSlowPath);
-
-    unsigned attributes;
-    JSCell* specificValue;
-    PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes, specificValue);
-    if (!isValidOffset(offset))
-        return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
-    if (attributes &amp; Accessor)
-        return GetByIdStatus(MakesCalls);
-    if (structure-&gt;isDictionary())
-        specificValue = 0;
-    return GetByIdStatus(
-        Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue));
</del><ins>+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool GetByIdStatus::makesCalls() const
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdStatush"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdStatus.h        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -68,7 +68,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     static GetByIdStatus computeFor(CodeBlock*, StubInfoMap&amp;, unsigned bytecodeIndex, StringImpl* uid);
</span><del>-    static GetByIdStatus computeFor(VM&amp;, Structure*, StringImpl* uid);
</del><ins>+    static GetByIdStatus computeFor(VM&amp;, const StructureSet&amp;, StringImpl* uid);
</ins><span class="cx">     
</span><span class="cx">     static GetByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap&amp; baselineMap, StubInfoMap&amp; dfgMap, CodeOrigin, StringImpl* uid);
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -259,88 +259,101 @@
</span><span class="cx">     return computeFor(baselineBlock, baselineMap, codeOrigin.bytecodeIndex, uid);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PutByIdStatus PutByIdStatus::computeFor(VM&amp; vm, JSGlobalObject* globalObject, Structure* structure, StringImpl* uid, bool isDirect)
</del><ins>+PutByIdStatus PutByIdStatus::computeFor(VM&amp; vm, JSGlobalObject* globalObject, const StructureSet&amp; set, StringImpl* uid, bool isDirect)
</ins><span class="cx"> {
</span><span class="cx">     if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
</span><span class="cx">         return PutByIdStatus(TakesSlowPath);
</span><span class="cx"> 
</span><del>-    if (!structure)
-        return PutByIdStatus(TakesSlowPath);
</del><ins>+    if (set.isEmpty())
+        return PutByIdStatus();
</ins><span class="cx">     
</span><del>-    if (structure-&gt;typeInfo().overridesGetOwnPropertySlot() &amp;&amp; structure-&gt;typeInfo().type() != GlobalObjectType)
-        return PutByIdStatus(TakesSlowPath);
</del><ins>+    PutByIdStatus result;
+    result.m_state = Simple;
+    for (unsigned i = 0; i &lt; set.size(); ++i) {
+        Structure* structure = set[i];
+        
+        if (structure-&gt;typeInfo().overridesGetOwnPropertySlot() &amp;&amp; structure-&gt;typeInfo().type() != GlobalObjectType)
+            return PutByIdStatus(TakesSlowPath);
</ins><span class="cx"> 
</span><del>-    if (!structure-&gt;propertyAccessesAreCacheable())
-        return PutByIdStatus(TakesSlowPath);
</del><ins>+        if (!structure-&gt;propertyAccessesAreCacheable())
+            return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">     
</span><del>-    unsigned attributes;
-    JSCell* specificValue;
-    PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes, specificValue);
-    if (isValidOffset(offset)) {
-        if (attributes &amp; CustomAccessor)
-            return PutByIdStatus(MakesCalls);
</del><ins>+        unsigned attributes;
+        JSCell* specificValue;
+        PropertyOffset offset = structure-&gt;getConcurrently(vm, uid, attributes, specificValue);
+        if (isValidOffset(offset)) {
+            if (attributes &amp; CustomAccessor)
+                return PutByIdStatus(MakesCalls);
</ins><span class="cx"> 
</span><del>-        if (attributes &amp; (Accessor | ReadOnly))
-            return PutByIdStatus(TakesSlowPath);
-        if (specificValue) {
-            // We need the PutById slow path to verify that we're storing the right value into
-            // the specialized slot.
-            return PutByIdStatus(TakesSlowPath);
</del><ins>+            if (attributes &amp; (Accessor | ReadOnly))
+                return PutByIdStatus(TakesSlowPath);
+            if (specificValue) {
+                // We need the PutById slow path to verify that we're storing the right value into
+                // the specialized slot.
+                return PutByIdStatus(TakesSlowPath);
+            }
+            if (!result.appendVariant(PutByIdVariant::replace(structure, offset)))
+                return PutByIdStatus(TakesSlowPath);
+            continue;
</ins><span class="cx">         }
</span><del>-        return PutByIdVariant::replace(structure, offset);
-    }
</del><span class="cx">     
</span><del>-    // Our hypothesis is that we're doing a transition. Before we prove that this is really
-    // true, we want to do some sanity checks.
</del><ins>+        // Our hypothesis is that we're doing a transition. Before we prove that this is really
+        // true, we want to do some sanity checks.
</ins><span class="cx">     
</span><del>-    // Don't cache put transitions on dictionaries.
-    if (structure-&gt;isDictionary())
-        return PutByIdStatus(TakesSlowPath);
</del><ins>+        // Don't cache put transitions on dictionaries.
+        if (structure-&gt;isDictionary())
+            return PutByIdStatus(TakesSlowPath);
</ins><span class="cx"> 
</span><del>-    // If the structure corresponds to something that isn't an object, then give up, since
-    // we don't want to be adding properties to strings.
-    if (structure-&gt;typeInfo().type() == StringType)
-        return PutByIdStatus(TakesSlowPath);
</del><ins>+        // If the structure corresponds to something that isn't an object, then give up, since
+        // we don't want to be adding properties to strings.
+        if (structure-&gt;typeInfo().type() == StringType)
+            return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">     
</span><del>-    RefPtr&lt;IntendedStructureChain&gt; chain;
-    if (!isDirect) {
-        chain = adoptRef(new IntendedStructureChain(globalObject, structure));
</del><ins>+        RefPtr&lt;IntendedStructureChain&gt; chain;
+        if (!isDirect) {
+            chain = adoptRef(new IntendedStructureChain(globalObject, structure));
</ins><span class="cx">         
</span><del>-        // If the prototype chain has setters or read-only properties, then give up.
-        if (chain-&gt;mayInterceptStoreTo(vm, uid))
-            return PutByIdStatus(TakesSlowPath);
</del><ins>+            // If the prototype chain has setters or read-only properties, then give up.
+            if (chain-&gt;mayInterceptStoreTo(vm, uid))
+                return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">         
</span><del>-        // If the prototype chain hasn't been normalized (i.e. there are proxies or dictionaries)
-        // then give up. The dictionary case would only happen if this structure has not been
-        // used in an optimized put_by_id transition. And really the only reason why we would
-        // bail here is that I don't really feel like having the optimizing JIT go and flatten
-        // dictionaries if we have evidence to suggest that those objects were never used as
-        // prototypes in a cacheable prototype access - i.e. there's a good chance that some of
-        // the other checks below will fail.
-        if (structure-&gt;isProxy() || !chain-&gt;isNormalized())
</del><ins>+            // If the prototype chain hasn't been normalized (i.e. there are proxies or dictionaries)
+            // then give up. The dictionary case would only happen if this structure has not been
+            // used in an optimized put_by_id transition. And really the only reason why we would
+            // bail here is that I don't really feel like having the optimizing JIT go and flatten
+            // dictionaries if we have evidence to suggest that those objects were never used as
+            // prototypes in a cacheable prototype access - i.e. there's a good chance that some of
+            // the other checks below will fail.
+            if (structure-&gt;isProxy() || !chain-&gt;isNormalized())
+                return PutByIdStatus(TakesSlowPath);
+        }
+    
+        // We only optimize if there is already a structure that the transition is cached to.
+        // Among other things, this allows us to guard against a transition with a specific
+        // value.
+        //
+        // - If we're storing a value that could be specific: this would only be a problem if
+        //   the existing transition did have a specific value already, since if it didn't,
+        //   then we would behave &quot;as if&quot; we were not storing a specific value. If it did
+        //   have a specific value, then we'll know - the fact that we pass 0 for
+        //   specificValue will tell us.
+        //
+        // - If we're not storing a value that could be specific: again, this would only be a
+        //   problem if the existing transition did have a specific value, which we check for
+        //   by passing 0 for the specificValue.
+        Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset);
+        if (!transition)
+            return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above.
+        ASSERT(!transition-&gt;transitionDidInvolveSpecificValue());
+        ASSERT(isValidOffset(offset));
+    
+        bool didAppend = result.appendVariant(
+            PutByIdVariant::transition(structure, transition, chain.release(), offset));
+        if (!didAppend)
</ins><span class="cx">             return PutByIdStatus(TakesSlowPath);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    // We only optimize if there is already a structure that the transition is cached to.
-    // Among other things, this allows us to guard against a transition with a specific
-    // value.
-    //
-    // - If we're storing a value that could be specific: this would only be a problem if
-    //   the existing transition did have a specific value already, since if it didn't,
-    //   then we would behave &quot;as if&quot; we were not storing a specific value. If it did
-    //   have a specific value, then we'll know - the fact that we pass 0 for
-    //   specificValue will tell us.
-    //
-    // - If we're not storing a value that could be specific: again, this would only be a
-    //   problem if the existing transition did have a specific value, which we check for
-    //   by passing 0 for the specificValue.
-    Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset);
-    if (!transition)
-        return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above.
-    ASSERT(!transition-&gt;transitionDidInvolveSpecificValue());
-    ASSERT(isValidOffset(offset));
-    
-    return PutByIdVariant::transition(structure, transition, chain.release(), offset);
</del><ins>+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void PutByIdStatus::dump(PrintStream&amp; out) const
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdStatush"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdStatus.h        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&amp;, unsigned bytecodeIndex, StringImpl* uid);
</span><del>-    static PutByIdStatus computeFor(VM&amp;, JSGlobalObject*, Structure*, StringImpl* uid, bool isDirect);
</del><ins>+    static PutByIdStatus computeFor(VM&amp;, JSGlobalObject*, const StructureSet&amp;, StringImpl* uid, bool isDirect);
</ins><span class="cx">     
</span><span class="cx">     static PutByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap&amp; baselineMap, StubInfoMap&amp; dfgMap, CodeOrigin, StringImpl* uid);
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -106,7 +106,6 @@
</span><span class="cx">     
</span><span class="cx">     const ConstantStructureCheckVector&amp; constantChecks() const
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == Transition);
</del><span class="cx">         return m_constantChecks;
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -1370,46 +1370,45 @@
</span><span class="cx">         break;
</span><span class="cx">             
</span><span class="cx">     case GetById:
</span><del>-    case GetByIdFlush:
</del><ins>+    case GetByIdFlush: {
</ins><span class="cx">         if (!node-&gt;prediction()) {
</span><span class="cx">             m_state.setIsValid(false);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        if (isCellSpeculation(node-&gt;child1()-&gt;prediction())) {
-            // This use of onlyStructure() should be replaced by giving GetByIdStatus the ability
-            // to compute things based on a StructureSet, and then to factor ByteCodeParser's
-            // ability to generate code based on a GetByIdStatus out of ByteCodeParser so that
-            // ConstantFoldingPhase can use it.
-            // https://bugs.webkit.org/show_bug.cgi?id=133229
-            if (Structure* structure = forNode(node-&gt;child1()).m_structure.onlyStructure()) {
-                GetByIdStatus status = GetByIdStatus::computeFor(
-                    m_graph.m_vm, structure,
-                    m_graph.identifiers()[node-&gt;identifierNumber()]);
-                if (status.isSimple() &amp;&amp; status.numVariants() == 1) {
-                    // Assert things that we can't handle and that the computeFor() method
-                    // above won't be able to return.
-                    ASSERT(status[0].structureSet().size() == 1);
-                    ASSERT(status[0].constantChecks().isEmpty());
-                    ASSERT(!status[0].alternateBase());
</del><ins>+        
+        AbstractValue&amp; value = forNode(node-&gt;child1());
+        if (!value.m_structure.isTop() &amp;&amp; !value.m_structure.isClobbered()
+            &amp;&amp; (node-&gt;child1().useKind() == CellUse || !(value.m_type &amp; ~SpecCell))) {
+            GetByIdStatus status = GetByIdStatus::computeFor(
+                m_graph.m_vm, value.m_structure.set(),
+                m_graph.identifiers()[node-&gt;identifierNumber()]);
+            if (status.isSimple()) {
+                // Figure out what the result is going to be - is it TOP, a constant, or maybe
+                // something more subtle?
+                AbstractValue result;
+                for (unsigned i = status.numVariants(); i--;) {
+                    if (!status[i].specificValue()) {
+                        result.makeHeapTop();
+                        break;
+                    }
</ins><span class="cx">                     
</span><del>-                    if (status[0].specificValue()) {
-                        if (status[0].specificValue().isCell()) {
-                            Structure* structure = status[0].specificValue().asCell()-&gt;structure();
-                            m_graph.watchpoints().consider(structure);
-                        }
-                        setConstant(node, *m_graph.freeze(status[0].specificValue()));
-                    } else
-                        forNode(node).makeHeapTop();
-                    filter(node-&gt;child1(), status[0].structureSet());
-                    
</del><ins>+                    AbstractValue thisResult;
+                    thisResult.set(
+                        m_graph, *m_graph.freeze(status[i].specificValue()),
+                        m_state.structureClobberState());
+                    result.merge(thisResult);
+                }
+                if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
</ins><span class="cx">                     m_state.setFoundConstants(true);
</span><del>-                    break;
-                }
</del><ins>+                forNode(node) = result;
+                break;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><ins>+
</ins><span class="cx">         clobberWorld(node-&gt;origin.semantic, clobberLimit);
</span><span class="cx">         forNode(node).makeHeapTop();
</span><span class="cx">         break;
</span><ins>+    }
</ins><span class="cx">             
</span><span class="cx">     case GetArrayLength:
</span><span class="cx">         forNode(node).setType(SpecInt32);
</span><span class="lines">@@ -1685,37 +1684,46 @@
</span><span class="cx">         
</span><span class="cx">     case PutById:
</span><span class="cx">     case PutByIdFlush:
</span><del>-    case PutByIdDirect:
-        // This use of onlyStructure() should be replaced by giving PutByIdStatus the ability
-        // to compute things based on a StructureSet, and then to factor ByteCodeParser's
-        // ability to generate code based on a PutByIdStatus out of ByteCodeParser so that
-        // ConstantFoldingPhase can use it.
-        // https://bugs.webkit.org/show_bug.cgi?id=133229
-        if (Structure* structure = forNode(node-&gt;child1()).m_structure.onlyStructure()) {
</del><ins>+    case PutByIdDirect: {
+        AbstractValue&amp; value = forNode(node-&gt;child1());
+        if (!value.m_structure.isTop() &amp;&amp; !value.m_structure.isClobbered()) {
</ins><span class="cx">             PutByIdStatus status = PutByIdStatus::computeFor(
</span><span class="cx">                 m_graph.m_vm,
</span><span class="cx">                 m_graph.globalObjectFor(node-&gt;origin.semantic),
</span><del>-                structure,
</del><ins>+                value.m_structure.set(),
</ins><span class="cx">                 m_graph.identifiers()[node-&gt;identifierNumber()],
</span><span class="cx">                 node-&gt;op() == PutByIdDirect);
</span><del>-            if (status.isSimple() &amp;&amp; status.numVariants() == 1) {
-                if (status[0].kind() == PutByIdVariant::Replace) {
-                    filter(node-&gt;child1(), structure);
-                    m_state.setFoundConstants(true);
-                    break;
</del><ins>+            
+            if (status.isSimple()) {
+                StructureSet newSet;
+                TransitionVector transitions;
+                
+                for (unsigned i = status.numVariants(); i--;) {
+                    const PutByIdVariant&amp; variant = status[i];
+                    if (variant.kind() == PutByIdVariant::Transition) {
+                        transitions.append(
+                            Transition(
+                                variant.oldStructureForTransition(), variant.newStructure()));
+                        newSet.add(variant.newStructure());
+                    } else {
+                        ASSERT(variant.kind() == PutByIdVariant::Replace);
+                        newSet.merge(variant.oldStructure());
+                    }
</ins><span class="cx">                 }
</span><del>-                if (status[0].kind() == PutByIdVariant::Transition
-                    &amp;&amp; structure-&gt;transitionWatchpointSetHasBeenInvalidated()) {
-                    m_graph.watchpoints().consider(status[0].newStructure());
-                    clobberStructures(clobberLimit);
-                    forNode(node-&gt;child1()).set(m_graph, status[0].newStructure());
</del><ins>+                
+                if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
</ins><span class="cx">                     m_state.setFoundConstants(true);
</span><del>-                    break;
-                }
</del><ins>+                
+                observeTransitions(clobberLimit, transitions);
+                if (forNode(node-&gt;child1()).changeStructure(m_graph, newSet) == Contradiction)
+                    m_state.setIsValid(false);
+                break;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><ins>+        
</ins><span class="cx">         clobberWorld(node-&gt;origin.semantic, clobberLimit);
</span><span class="cx">         break;
</span><ins>+    }
</ins><span class="cx">         
</span><span class="cx">     case In:
</span><span class="cx">         // FIXME: We can determine when the property definitely exists based on abstract
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -2862,7 +2862,9 @@
</span><span class="cx">             case GlobalPropertyWithVarInjectionChecks: {
</span><span class="cx">                 SpeculatedType prediction = getPrediction();
</span><span class="cx">                 GetByIdStatus status = GetByIdStatus::computeFor(*m_vm, structure, uid);
</span><del>-                if (status.state() != GetByIdStatus::Simple || status.numVariants() != 1) {
</del><ins>+                if (status.state() != GetByIdStatus::Simple
+                    || status.numVariants() != 1
+                    || status[0].structureSet().size() != 1) {
</ins><span class="cx">                     set(VirtualRegister(dst), addToGraph(GetByIdFlush, OpInfo(identifierNumber), OpInfo(prediction), get(VirtualRegister(scope))));
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="lines">@@ -2947,7 +2949,9 @@
</span><span class="cx">             case GlobalProperty:
</span><span class="cx">             case GlobalPropertyWithVarInjectionChecks: {
</span><span class="cx">                 PutByIdStatus status = PutByIdStatus::computeFor(*m_vm, globalObject, structure, uid, false);
</span><del>-                if (status.numVariants() != 1 || status[0].kind() != PutByIdVariant::Replace) {
</del><ins>+                if (status.numVariants() != 1
+                    || status[0].kind() != PutByIdVariant::Replace
+                    || status[0].structure().size() != 1) {
</ins><span class="cx">                     addToGraph(PutById, OpInfo(identifierNumber), get(VirtualRegister(scope)), get(VirtualRegister(value)));
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -228,35 +228,47 @@
</span><span class="cx">                 Node* child = childEdge.node();
</span><span class="cx">                 unsigned identifierNumber = node-&gt;identifierNumber();
</span><span class="cx">                 
</span><del>-                if (childEdge.useKind() != CellUse)
-                    break;
-                
</del><span class="cx">                 AbstractValue baseValue = m_state.forNode(child);
</span><span class="cx"> 
</span><span class="cx">                 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
</span><span class="cx">                 eliminated = true; // Don't allow the default constant folder to do things to this.
</span><span class="cx"> 
</span><del>-                Structure* structure = baseValue.m_structure.onlyStructure();
-                if (!structure)
</del><ins>+                if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()
+                    || (node-&gt;child1().useKind() == UntypedUse || (baseValue.m_type &amp; ~SpecCell)))
</ins><span class="cx">                     break;
</span><del>-
</del><ins>+                
</ins><span class="cx">                 GetByIdStatus status = GetByIdStatus::computeFor(
</span><del>-                    vm(), structure, m_graph.identifiers()[identifierNumber]);
</del><ins>+                    vm(), baseValue.m_structure.set(), m_graph.identifiers()[identifierNumber]);
+                if (!status.isSimple())
+                    break;
</ins><span class="cx">                 
</span><del>-                if (!status.isSimple() || status.numVariants() != 1 ||
-                    !status[0].constantChecks().isEmpty() || status[0].alternateBase()) {
-                    // FIXME: We could handle prototype cases.
-                    // https://bugs.webkit.org/show_bug.cgi?id=110386
</del><ins>+                for (unsigned i = status.numVariants(); i--;) {
+                    if (!status[i].constantChecks().isEmpty()
+                        || status[i].alternateBase()) {
+                        // FIXME: We could handle prototype cases.
+                        // https://bugs.webkit.org/show_bug.cgi?id=110386
+                        break;
+                    }
+                }
+                
+                if (status.numVariants() == 1) {
+                    emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
</ins><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                 
</span><del>-                emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
-                eliminated = true;
</del><ins>+                if (!isFTL(m_graph.m_plan.mode))
+                    break;
+                
+                MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add();
+                data-&gt;variants = status.variants();
+                data-&gt;identifierNumber = identifierNumber;
+                node-&gt;convertToMultiGetByOffset(data);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="cx">             case PutById:
</span><del>-            case PutByIdDirect: {
</del><ins>+            case PutByIdDirect:
+            case PutByIdFlush: {
</ins><span class="cx">                 NodeOrigin origin = node-&gt;origin;
</span><span class="cx">                 Edge childEdge = node-&gt;child1();
</span><span class="cx">                 Node* child = childEdge.node();
</span><span class="lines">@@ -269,24 +281,34 @@
</span><span class="cx">                 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
</span><span class="cx">                 eliminated = true; // Don't allow the default constant folder to do things to this.
</span><span class="cx"> 
</span><del>-                Structure* structure = baseValue.m_structure.onlyStructure();
-                if (!structure)
</del><ins>+                if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered())
</ins><span class="cx">                     break;
</span><span class="cx">                 
</span><span class="cx">                 PutByIdStatus status = PutByIdStatus::computeFor(
</span><span class="cx">                     vm(),
</span><span class="cx">                     m_graph.globalObjectFor(origin.semantic),
</span><del>-                    structure,
</del><ins>+                    baseValue.m_structure.set(),
</ins><span class="cx">                     m_graph.identifiers()[identifierNumber],
</span><span class="cx">                     node-&gt;op() == PutByIdDirect);
</span><span class="cx">                 
</span><span class="cx">                 if (!status.isSimple())
</span><span class="cx">                     break;
</span><del>-                if (status.numVariants() != 1)
</del><ins>+                
+                for (unsigned i = status.numVariants(); i--;)
+                    addChecks(origin, indexInBlock, status[i].constantChecks());
+                
+                if (status.numVariants() == 1) {
+                    emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
</ins><span class="cx">                     break;
</span><ins>+                }
</ins><span class="cx">                 
</span><del>-                emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
-                eliminated = true;
</del><ins>+                if (!isFTL(m_graph.m_plan.mode))
+                    break;
+
+                MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add();
+                data-&gt;variants = status.variants();
+                data-&gt;identifierNumber = identifierNumber;
+                node-&gt;convertToMultiPutByOffset(data);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -426,13 +448,6 @@
</span><span class="cx">         if (variant.kind() == PutByIdVariant::Transition) {
</span><span class="cx">             transition = m_graph.m_transitions.add(
</span><span class="cx">                 variant.oldStructureForTransition(), variant.newStructure());
</span><del>-
-            for (unsigned i = 0; i &lt; variant.constantChecks().size(); ++i) {
-                addStructureTransitionCheck(
-                    origin, indexInBlock,
-                    variant.constantChecks()[i].constant(),
-                    variant.constantChecks()[i].structure());
-            }
</del><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         Edge propertyStorage;
</span><span class="lines">@@ -499,6 +514,15 @@
</span><span class="cx">                 indexInBlock, SpecNone, Phantom, node-&gt;origin, node-&gt;child1());
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+    
+    void addChecks(
+        NodeOrigin origin, unsigned indexInBlock, const ConstantStructureCheckVector&amp; checks)
+    {
+        for (unsigned i = 0; i &lt; checks.size(); ++i) {
+            addStructureTransitionCheck(
+                origin, indexInBlock, checks[i].constant(), checks[i].structure());
+        }
+    }
</ins><span class="cx"> 
</span><span class="cx">     void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell, Structure* structure)
</span><span class="cx">     {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -458,6 +458,15 @@
</span><span class="cx">         m_flags &amp;= ~NodeClobbersWorld;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void convertToMultiGetByOffset(MultiGetByOffsetData* data)
+    {
+        ASSERT(m_op == GetById || m_op == GetByIdFlush);
+        m_opInfo = bitwise_cast&lt;intptr_t&gt;(data);
+        child1().setUseKind(CellUse);
+        m_op = MultiGetByOffset;
+        m_flags &amp;= ~NodeClobbersWorld;
+    }
+    
</ins><span class="cx">     void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == MultiPutByOffset);
</span><span class="lines">@@ -469,6 +478,14 @@
</span><span class="cx">         m_flags &amp;= ~NodeClobbersWorld;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void convertToMultiPutByOffset(MultiPutByOffsetData* data)
+    {
+        ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush);
+        m_opInfo = bitwise_cast&lt;intptr_t&gt;(data);
+        m_op = MultiPutByOffset;
+        m_flags &amp;= ~NodeClobbersWorld;
+    }
+    
</ins><span class="cx">     void convertToPhantomLocal()
</span><span class="cx">     {
</span><span class="cx">         ASSERT(m_op == Phantom &amp;&amp; (child1()-&gt;op() == Phi || child1()-&gt;op() == SetLocal || child1()-&gt;op() == SetArgument));
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx">                 
</span><span class="cx">             default:
</span><span class="cx">                 m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
</span><del>-                RELEASE_ASSERT(spillFormat &amp; DataFormatJS);
</del><ins>+                DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat &amp; DataFormatJS);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             info.fillJSValue(*m_stream, gpr, spillFormat);
</span><span class="lines">@@ -137,10 +137,10 @@
</span><span class="cx">     case DataFormatDouble:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">         // this type currently never occurs
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Bad data format&quot;);
</ins><span class="cx">         
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Corrupt data format&quot;);
</ins><span class="cx">         return InvalidGPRReg;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -311,7 +311,7 @@
</span><span class="cx">     if (branchIndexInBlock != UINT_MAX) {
</span><span class="cx">         Node* branchNode = m_block-&gt;at(branchIndexInBlock);
</span><span class="cx"> 
</span><del>-        RELEASE_ASSERT(node-&gt;adjustedRefCount() == 1);
</del><ins>+        DFG_ASSERT(m_jit.graph(), node, node-&gt;adjustedRefCount() == 1);
</ins><span class="cx">         
</span><span class="cx">         nonSpeculativePeepholeBranchNull(operand, branchNode, invert);
</span><span class="cx">     
</span><span class="lines">@@ -628,8 +628,8 @@
</span><span class="cx"> 
</span><span class="cx">     bool isCall = node-&gt;op() == Call;
</span><span class="cx">     if (!isCall)
</span><del>-        RELEASE_ASSERT(node-&gt;op() == Construct);
-
</del><ins>+        DFG_ASSERT(m_jit.graph(), node, node-&gt;op() == Construct);
+    
</ins><span class="cx">     // For constructors, the this argument is not passed but we have to make space
</span><span class="cx">     // for it.
</span><span class="cx">     int dummyThisArgument = isCall ? 0 : 1;
</span><span class="lines">@@ -741,7 +741,7 @@
</span><span class="cx">         
</span><span class="cx">         DataFormat spillFormat = info.spillFormat();
</span><span class="cx">         
</span><del>-        RELEASE_ASSERT((spillFormat &amp; DataFormatJS) || spillFormat == DataFormatInt32);
</del><ins>+        DFG_ASSERT(m_jit.graph(), m_currentNode, (spillFormat &amp; DataFormatJS) || spillFormat == DataFormatInt32);
</ins><span class="cx">         
</span><span class="cx">         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
</span><span class="cx">         
</span><span class="lines">@@ -771,7 +771,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case DataFormatJS: {
</span><del>-        RELEASE_ASSERT(!(type &amp; SpecInt52));
</del><ins>+        DFG_ASSERT(m_jit.graph(), m_currentNode, !(type &amp; SpecInt52));
</ins><span class="cx">         // Check the value is an integer.
</span><span class="cx">         GPRReg gpr = info.gpr();
</span><span class="cx">         m_gprs.lock(gpr);
</span><span class="lines">@@ -834,10 +834,10 @@
</span><span class="cx">     case DataFormatStorage:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">     case DataFormatStrictInt52:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Bad data format&quot;);
</ins><span class="cx">         
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Corrupt data format&quot;);
</ins><span class="cx">         return InvalidGPRReg;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -854,7 +854,7 @@
</span><span class="cx"> {
</span><span class="cx">     DataFormat mustBeDataFormatInt32;
</span><span class="cx">     GPRReg result = fillSpeculateInt32Internal&lt;true&gt;(edge, mustBeDataFormatInt32);
</span><del>-    RELEASE_ASSERT(mustBeDataFormatInt32 == DataFormatInt32);
</del><ins>+    DFG_ASSERT(m_jit.graph(), m_currentNode, mustBeDataFormatInt32 == DataFormatInt32);
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -889,7 +889,7 @@
</span><span class="cx">         
</span><span class="cx">         DataFormat spillFormat = info.spillFormat();
</span><span class="cx">         
</span><del>-        RELEASE_ASSERT(spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52);
</del><ins>+        DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatInt52 || spillFormat == DataFormatStrictInt52);
</ins><span class="cx">         
</span><span class="cx">         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
</span><span class="cx">         
</span><span class="lines">@@ -941,7 +941,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Bad data format&quot;);
</ins><span class="cx">         return InvalidGPRReg;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -972,7 +972,7 @@
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         DataFormat spillFormat = info.spillFormat();
</span><del>-        RELEASE_ASSERT(spillFormat == DataFormatDouble);
</del><ins>+        DFG_ASSERT(m_jit.graph(), m_currentNode, spillFormat == DataFormatDouble);
</ins><span class="cx">         FPRReg fpr = fprAllocate();
</span><span class="cx">         m_jit.loadDouble(JITCompiler::addressFor(virtualRegister), fpr);
</span><span class="cx">         m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
</span><span class="lines">@@ -980,7 +980,7 @@
</span><span class="cx">         return fpr;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    RELEASE_ASSERT(info.registerFormat() == DataFormatDouble);
</del><ins>+    DFG_ASSERT(m_jit.graph(), m_currentNode, info.registerFormat() == DataFormatDouble);
</ins><span class="cx">     FPRReg fpr = info.fpr();
</span><span class="cx">     m_fprs.lock(fpr);
</span><span class="cx">     return fpr;
</span><span class="lines">@@ -1010,7 +1010,7 @@
</span><span class="cx">             terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
</span><span class="cx">             return gpr;
</span><span class="cx">         }
</span><del>-        RELEASE_ASSERT(info.spillFormat() &amp; DataFormatJS);
</del><ins>+        DFG_ASSERT(m_jit.graph(), m_currentNode, info.spillFormat() &amp; DataFormatJS);
</ins><span class="cx">         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
</span><span class="cx">         m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
</span><span class="cx"> 
</span><span class="lines">@@ -1055,10 +1055,10 @@
</span><span class="cx">     case DataFormatStorage:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">     case DataFormatStrictInt52:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Bad data format&quot;);
</ins><span class="cx">         
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Corrupt data format&quot;);
</ins><span class="cx">         return InvalidGPRReg;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -1091,7 +1091,7 @@
</span><span class="cx">             terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
</span><span class="cx">             return gpr;
</span><span class="cx">         }
</span><del>-        RELEASE_ASSERT(info.spillFormat() &amp; DataFormatJS);
</del><ins>+        DFG_ASSERT(m_jit.graph(), m_currentNode, info.spillFormat() &amp; DataFormatJS);
</ins><span class="cx">         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
</span><span class="cx">         m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
</span><span class="cx"> 
</span><span class="lines">@@ -1136,10 +1136,10 @@
</span><span class="cx">     case DataFormatStorage:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">     case DataFormatStrictInt52:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Bad data format&quot;);
</ins><span class="cx">         
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Corrupt data format&quot;);
</ins><span class="cx">         return InvalidGPRReg;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -1603,7 +1603,7 @@
</span><span class="cx">         return compileStringZeroLength(node);
</span><span class="cx"> 
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), node, &quot;Bad use kind&quot;);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -1758,7 +1758,7 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     default:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), m_currentNode, &quot;Bad use kind&quot;);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1783,7 +1783,7 @@
</span><span class="cx"> 
</span><span class="cx">     case Identity: {
</span><span class="cx">         // CSE should always eliminate this.
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), node, &quot;Unexpected Identity node&quot;);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1864,7 +1864,7 @@
</span><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><span class="cx">     case Check: {
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), node, &quot;Unexpected node&quot;);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1924,7 +1924,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         default:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad flush format&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -2103,7 +2103,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         default:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad use kind&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -2170,7 +2170,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         default:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad use kind&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -2292,8 +2292,7 @@
</span><span class="cx">         switch (node-&gt;arrayMode().type()) {
</span><span class="cx">         case Array::SelectUsingPredictions:
</span><span class="cx">         case Array::ForceExit:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
-            terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad array mode type&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         case Array::Generic: {
</span><span class="cx">             JSValueOperand base(this, node-&gt;child1());
</span><span class="lines">@@ -2494,12 +2493,10 @@
</span><span class="cx">         switch (arrayMode.type()) {
</span><span class="cx">         case Array::SelectUsingPredictions:
</span><span class="cx">         case Array::ForceExit:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
-            terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), 0);
-            alreadyHandled = true;
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad array mode type&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         case Array::Generic: {
</span><del>-            RELEASE_ASSERT(node-&gt;op() == PutByVal);
</del><ins>+            DFG_ASSERT(m_jit.graph(), node, node-&gt;op() == PutByVal);
</ins><span class="cx">             
</span><span class="cx">             JSValueOperand arg1(this, child1);
</span><span class="cx">             JSValueOperand arg2(this, child2);
</span><span class="lines">@@ -3038,7 +3035,7 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case ToPrimitive: {
</span><del>-        RELEASE_ASSERT(node-&gt;child1().useKind() == UntypedUse);
</del><ins>+        DFG_ASSERT(m_jit.graph(), node, node-&gt;child1().useKind() == UntypedUse);
</ins><span class="cx">         JSValueOperand op1(this, node-&gt;child1());
</span><span class="cx">         GPRTemporary result(this, Reuse, op1);
</span><span class="cx">         
</span><span class="lines">@@ -3105,7 +3102,7 @@
</span><span class="cx">         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node-&gt;origin.semantic);
</span><span class="cx">         if (!globalObject-&gt;isHavingABadTime() &amp;&amp; !hasAnyArrayStorage(node-&gt;indexingType())) {
</span><span class="cx">             Structure* structure = globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(node-&gt;indexingType());
</span><del>-            RELEASE_ASSERT(structure-&gt;indexingType() == node-&gt;indexingType());
</del><ins>+            DFG_ASSERT(m_jit.graph(), node, structure-&gt;indexingType() == node-&gt;indexingType());
</ins><span class="cx">             ASSERT(
</span><span class="cx">                 hasUndecided(structure-&gt;indexingType())
</span><span class="cx">                 || hasInt32(structure-&gt;indexingType())
</span><span class="lines">@@ -3356,7 +3353,7 @@
</span><span class="cx"> 
</span><span class="cx">             emitAllocateJSArray(resultGPR, globalObject-&gt;arrayStructureForIndexingTypeDuringAllocation(indexingType), storageGPR, numElements);
</span><span class="cx">             
</span><del>-            RELEASE_ASSERT(indexingType &amp; IsArray);
</del><ins>+            DFG_ASSERT(m_jit.graph(), node, indexingType &amp; IsArray);
</ins><span class="cx">             JSValue* data = m_jit.codeBlock()-&gt;constantBuffer(node-&gt;startConstant());
</span><span class="cx">             if (indexingType == ArrayWithDouble) {
</span><span class="cx">                 for (unsigned index = 0; index &lt; node-&gt;numConstants(); ++index) {
</span><span class="lines">@@ -3410,7 +3407,7 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         default:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad use kind&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -3640,7 +3637,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         default:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad use kind&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -3690,7 +3687,7 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         default:
</span><del>-            RELEASE_ASSERT_NOT_REACHED();
</del><ins>+            DFG_CRASH(m_jit.graph(), node, &quot;Bad use kind&quot;);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -4154,7 +4151,7 @@
</span><span class="cx">         break;
</span><span class="cx"> 
</span><span class="cx">     case CreateActivation: {
</span><del>-        RELEASE_ASSERT(!node-&gt;origin.semantic.inlineCallFrame);
</del><ins>+        DFG_ASSERT(m_jit.graph(), node, !node-&gt;origin.semantic.inlineCallFrame);
</ins><span class="cx">         
</span><span class="cx">         JSValueOperand value(this, node-&gt;child1());
</span><span class="cx">         GPRTemporary result(this, Reuse, value);
</span><span class="lines">@@ -4227,7 +4224,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case TearOffActivation: {
</span><del>-        RELEASE_ASSERT(!node-&gt;origin.semantic.inlineCallFrame);
</del><ins>+        DFG_ASSERT(m_jit.graph(), node, !node-&gt;origin.semantic.inlineCallFrame);
</ins><span class="cx"> 
</span><span class="cx">         JSValueOperand activationValue(this, node-&gt;child1());
</span><span class="cx">         GPRTemporary scratch(this);
</span><span class="lines">@@ -4299,7 +4296,7 @@
</span><span class="cx">                         m_jit.graph().machineArgumentsRegisterFor(node-&gt;origin.semantic))));
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        RELEASE_ASSERT(!node-&gt;origin.semantic.inlineCallFrame);
</del><ins>+        DFG_ASSERT(m_jit.graph(), node, !node-&gt;origin.semantic.inlineCallFrame);
</ins><span class="cx">         m_jit.load32(JITCompiler::payloadFor(JSStack::ArgumentCount), resultGPR);
</span><span class="cx">         m_jit.sub32(TrustedImm32(1), resultGPR);
</span><span class="cx">         int32Result(resultGPR, node);
</span><span class="lines">@@ -4375,7 +4372,7 @@
</span><span class="cx">         JITCompiler::JumpList slowArgument;
</span><span class="cx">         JITCompiler::JumpList slowArgumentOutOfBounds;
</span><span class="cx">         if (m_jit.symbolTableFor(node-&gt;origin.semantic)-&gt;slowArguments()) {
</span><del>-            RELEASE_ASSERT(!node-&gt;origin.semantic.inlineCallFrame);
</del><ins>+            DFG_ASSERT(m_jit.graph(), node, !node-&gt;origin.semantic.inlineCallFrame);
</ins><span class="cx">             const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get();
</span><span class="cx">             
</span><span class="cx">             slowArgumentOutOfBounds.append(
</span><span class="lines">@@ -4442,7 +4439,7 @@
</span><span class="cx">         JITCompiler::JumpList slowArgument;
</span><span class="cx">         JITCompiler::JumpList slowArgumentOutOfBounds;
</span><span class="cx">         if (m_jit.symbolTableFor(node-&gt;origin.semantic)-&gt;slowArguments()) {
</span><del>-            RELEASE_ASSERT(!node-&gt;origin.semantic.inlineCallFrame);
</del><ins>+            DFG_ASSERT(m_jit.graph(), node, !node-&gt;origin.semantic.inlineCallFrame);
</ins><span class="cx">             const SlowArgument* slowArguments = m_jit.graph().m_slowArguments.get();
</span><span class="cx"> 
</span><span class="cx">             slowArgumentOutOfBounds.append(
</span><span class="lines">@@ -4576,7 +4573,7 @@
</span><span class="cx">         break;
</span><span class="cx"> 
</span><span class="cx">     case Unreachable:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), node, &quot;Unexpected Unreachable node&quot;);
</ins><span class="cx">         break;
</span><span class="cx"> 
</span><span class="cx">     case StoreBarrier:
</span><span class="lines">@@ -4644,7 +4641,7 @@
</span><span class="cx">     case CheckTierUpInLoop:
</span><span class="cx">     case CheckTierUpAtReturn:
</span><span class="cx">     case CheckTierUpAndOSREnter:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), node, &quot;Unexpected tier-up node&quot;);
</ins><span class="cx">         break;
</span><span class="cx"> #endif // ENABLE(FTL_JIT)
</span><span class="cx"> 
</span><span class="lines">@@ -4659,7 +4656,7 @@
</span><span class="cx">     case ArithIMul:
</span><span class="cx">     case MultiGetByOffset:
</span><span class="cx">     case MultiPutByOffset:
</span><del>-        RELEASE_ASSERT_NOT_REACHED();
</del><ins>+        DFG_CRASH(m_jit.graph(), node, &quot;Unexpected FTL-only node&quot;);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGStructureAbstractValueh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h (170274 => 170275)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h        2014-06-23 00:51:33 UTC (rev 170274)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h        2014-06-23 01:02:01 UTC (rev 170275)
</span><span class="lines">@@ -161,6 +161,12 @@
</span><span class="cx">         return equalsSlow(other);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    const StructureSet&amp; set() const
+    {
+        ASSERT(!isTop());
+        return m_set;
+    }
+    
</ins><span class="cx">     size_t size() const
</span><span class="cx">     {
</span><span class="cx">         ASSERT(!isTop());
</span></span></pre>
</div>
</div>

</body>
</html>