<!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>[170141] 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/170141">170141</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-06-18 21:34:25 -0700 (Wed, 18 Jun 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
https://bugs.webkit.org/show_bug.cgi?id=133918

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore: 
        
This also adds pruning of PutStructure, since I basically had no choice but
to implement such logic within MultiPutByOffset.
        
Also adds a bunch of PutById cache status dumping to bytecode dumping.

* bytecode/GetByIdVariant.cpp:
(JSC::GetByIdVariant::dumpInContext):
* bytecode/GetByIdVariant.h:
(JSC::GetByIdVariant::structureSet):
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::oldStructure):
* bytecode/StructureSet.cpp:
(JSC::StructureSet::filter):
(JSC::StructureSet::filterArrayModes):
* bytecode/StructureSet.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGAbstractValue.cpp:
(JSC::DFG::AbstractValue::changeStructure):
(JSC::DFG::AbstractValue::contains):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::couldBeType):
(JSC::DFG::AbstractValue::isType):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
(JSC::DFG::ConstantFoldingPhase::addBaseCheck):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::freezeStrong):
* dfg/DFGGraph.h:
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::operator=):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
* tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added.
(foo):
(fu):
(bar):
(baz):
(.bar):
(.baz):
* tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added.
(foo):
(fu):
(bar):
(baz):
(.bar):
(.baz):
* tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added.
(foo):
(fu):
(bar):
(baz):
(.bar):
(.baz):

LayoutTests: 

* js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt: Added.
* js/regress/fold-multi-get-by-offset-to-get-by-offset.html: Added.
* js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt: Added.
* js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html: Added.
* js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt: Added.
* js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html: Added.
* js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt: Added.
* js/regress/fold-multi-put-by-offset-to-put-by-offset.html: Added.
* js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt: Added.
* js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html: Added.
* js/regress/fold-put-structure-expected.txt: Added.
* js/regress/fold-put-structure.html: Added.
* js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js: Added.
(foo):
(fu):
(bar):
(.bar):
* js/regress/script-tests/fold-put-structure.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="#branchesftloptSourceJavaScriptCorebytecodeCodeBlockcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeCodeBlockh">branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h</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="#branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth">branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeStructureSetcpp">branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCorebytecodeStructureSeth">branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractValuecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractValueh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGGraphcpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGGraphh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGStructureAbstractValueh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettogetbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettogetbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettopolygetbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettopolygetbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettopolyputbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettopolyputbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoputbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoputbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoreplaceortransitionputbyoffsetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoreplaceortransitionputbyoffsethtml">branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldputstructureexpectedtxt">branches/ftlopt/LayoutTests/js/regress/fold-put-structure-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressfoldputstructurehtml">branches/ftlopt/LayoutTests/js/regress/fold-put-structure.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldmultigetbyoffsettogetbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldmultigetbyoffsettopolygetbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldmultiputbyoffsettopolyputbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldmultiputbyoffsettoputbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldmultiputbyoffsettoreplaceortransitionputbyoffsetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsfoldputstructurejs">branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-structure.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressfoldmultigetbyoffsettogetbyoffsetwithoutfoldingthestructurecheckjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressfoldmultiputbyoffsettoputbyoffsetwithoutfoldingthestructurecheckjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoretestsstressprunemultiputbyoffsetreplaceortransitionvariantjs">branches/ftlopt/Source/JavaScriptCore/tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/LayoutTests/ChangeLog (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/ChangeLog        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/LayoutTests/ChangeLog        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -1,3 +1,53 @@
</span><ins>+2014-06-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
+        https://bugs.webkit.org/show_bug.cgi?id=133918
+
+        Reviewed by Mark Hahnenberg.
+
+        * js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt: Added.
+        * js/regress/fold-multi-get-by-offset-to-get-by-offset.html: Added.
+        * js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt: Added.
+        * js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html: Added.
+        * js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt: Added.
+        * js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html: Added.
+        * js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt: Added.
+        * js/regress/fold-multi-put-by-offset-to-put-by-offset.html: Added.
+        * js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt: Added.
+        * js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html: Added.
+        * js/regress/fold-put-structure-expected.txt: Added.
+        * js/regress/fold-put-structure.html: Added.
+        * js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        * js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        * js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        * js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        * js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+        * js/regress/script-tests/fold-put-structure.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (.bar):
+
</ins><span class="cx"> 2014-06-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ftlopt] DFG put_by_id should inline accesses with a slightly polymorphic base
</span></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettogetbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset-expected.txt        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-multi-get-by-offset-to-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="branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettogetbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset.html (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-get-by-offset.html        2014-06-19 04:34:25 UTC (rev 170141)
</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-multi-get-by-offset-to-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="branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettopolygetbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset-expected.txt        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-multi-get-by-offset-to-poly-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="branchesftloptLayoutTestsjsregressfoldmultigetbyoffsettopolygetbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-get-by-offset-to-poly-get-by-offset.html        2014-06-19 04:34:25 UTC (rev 170141)
</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-multi-get-by-offset-to-poly-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="branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettopolyputbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset-expected.txt        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-multi-put-by-offset-to-poly-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="branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettopolyputbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-poly-put-by-offset.html        2014-06-19 04:34:25 UTC (rev 170141)
</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-multi-put-by-offset-to-poly-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="branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoputbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset-expected.txt        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-multi-put-by-offset-to-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="branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoputbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset.html (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-put-by-offset.html        2014-06-19 04:34:25 UTC (rev 170141)
</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-multi-put-by-offset-to-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="branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoreplaceortransitionputbyoffsetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset-expected.txt        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-multi-put-by-offset-to-replace-or-transition-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="branchesftloptLayoutTestsjsregressfoldmultiputbyoffsettoreplaceortransitionputbyoffsethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.html        2014-06-19 04:34:25 UTC (rev 170141)
</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-multi-put-by-offset-to-replace-or-transition-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="branchesftloptLayoutTestsjsregressfoldputstructureexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-put-structure-expected.txt (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-put-structure-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-put-structure-expected.txt        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/fold-put-structure
+
+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="branchesftloptLayoutTestsjsregressfoldputstructurehtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/fold-put-structure.html (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/fold-put-structure.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/fold-put-structure.html        2014-06-19 04:34:25 UTC (rev 170141)
</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-structure.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="branchesftloptLayoutTestsjsregressscripttestsfoldmultigetbyoffsettogetbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-get-by-offset.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,43 @@
</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; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({d:1, e:2, f:3});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+    
+(function(f, o) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        var p;
+        if (i == n - 1) // Defeat LICM.
+            p = {f: 42, e: 42};
+        else
+            p = o;
+        result += fu(p);
+        result += bar(f, p);
+    }
+    if (result != (n - 1) * (o.f + o.e) + 42 * 2)
+        throw &quot;Error: bad result: &quot; + result;
+})(foo, {f:42, e:2});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldmultigetbyoffsettopolygetbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-get-by-offset-to-poly-get-by-offset.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,41 @@
</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; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({d:1, e:2, f: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) {
+        result += fu(o);
+        result += bar(f, o);
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != n * o.f + n * o.e)
+        throw &quot;Error: bad result: &quot; + result;
+})(foo, {f:42, e:23}, {f:42, e:23, g:100});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldmultiputbyoffsettopolyputbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-poly-put-by-offset.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,47 @@
</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; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({d:1, e:2, f: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}, {f:42, e:23, g:100});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldmultiputbyoffsettoputbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-put-by-offset.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,40 @@
</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; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({d:1, e:2, f:3});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+    
+(function(f, o) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        fu(o);
+        bar(f, o);
+    }
+    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;
+})(foo, {f:42, e:23});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldmultiputbyoffsettoreplaceortransitionputbyoffsetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-multi-put-by-offset-to-replace-or-transition-put-by-offset.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,50 @@
</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; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({d:1, e:2, f:3});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+    
+(function(f, o) {
+    var result = 0;
+    var n = 1000000;
+    var p;
+    for (var i = 0; i &lt; n; ++i) {
+        var q;
+        if (i &amp; 1)
+            q = o;
+        else
+            p = q = {e:61};
+        fu(q);
+        bar(f, q);
+    }
+    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, {e:23, f:42});
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsfoldputstructurejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-structure.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-structure.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/fold-put-structure.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,39 @@
</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; 100; ++i) {
+    foo({e:2});
+    foo({e:1, f:2});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({d:1, e:2, f:3});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {e:1});
+    bar(function() { }, null);
+    bar(function() { return 42 }, null);
+}
+    
+(function(f, o) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        fu(o);
+        bar(f, o);
+    }
+    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;
+})(foo, {e:42, f:23});
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -1,3 +1,67 @@
</span><ins>+2014-06-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG AI and constant folder should be able to precisely prune MultiGetByOffset/MultiPutByOffset even if the base structure abstract value is not a singleton
+        https://bugs.webkit.org/show_bug.cgi?id=133918
+
+        Reviewed by Mark Hahnenberg.
+        
+        This also adds pruning of PutStructure, since I basically had no choice but
+        to implement such logic within MultiPutByOffset.
+        
+        Also adds a bunch of PutById cache status dumping to bytecode dumping.
+
+        * bytecode/GetByIdVariant.cpp:
+        (JSC::GetByIdVariant::dumpInContext):
+        * bytecode/GetByIdVariant.h:
+        (JSC::GetByIdVariant::structureSet):
+        * bytecode/PutByIdVariant.h:
+        (JSC::PutByIdVariant::oldStructure):
+        * bytecode/StructureSet.cpp:
+        (JSC::StructureSet::filter):
+        (JSC::StructureSet::filterArrayModes):
+        * bytecode/StructureSet.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGAbstractValue.cpp:
+        (JSC::DFG::AbstractValue::changeStructure):
+        (JSC::DFG::AbstractValue::contains):
+        * dfg/DFGAbstractValue.h:
+        (JSC::DFG::AbstractValue::couldBeType):
+        (JSC::DFG::AbstractValue::isType):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        (JSC::DFG::ConstantFoldingPhase::emitGetByOffset):
+        (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+        (JSC::DFG::ConstantFoldingPhase::addBaseCheck):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::freezeStrong):
+        * dfg/DFGGraph.h:
+        * dfg/DFGStructureAbstractValue.h:
+        (JSC::DFG::StructureAbstractValue::operator=):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
+        * tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (baz):
+        (.bar):
+        (.baz):
+        * tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (baz):
+        (.bar):
+        (.baz):
+        * tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js: Added.
+        (foo):
+        (fu):
+        (bar):
+        (baz):
+        (.bar):
+        (.baz):
+
</ins><span class="cx"> 2014-06-18  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove CompoundType and LeafType
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -402,6 +402,120 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CodeBlock::printPutByIdCacheStatus(PrintStream&amp; out, ExecState* exec, int location, const StubInfoMap&amp; map)
+{
+    Instruction* instruction = instructions().begin() + location;
+
+    const Identifier&amp; ident = identifier(instruction[2].u.operand);
+    
+    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
+    
+#if ENABLE(LLINT)
+    if (Structure* structure = instruction[4].u.structure.get()) {
+        switch (exec-&gt;interpreter()-&gt;getOpcodeID(instruction[0].u.opcode)) {
+        case op_put_by_id:
+        case op_put_by_id_out_of_line:
+            out.print(&quot; llint(&quot;);
+            dumpStructure(out, &quot;struct&quot;, exec, structure, ident);
+            out.print(&quot;)&quot;);
+            break;
+            
+        case op_put_by_id_transition_direct:
+        case op_put_by_id_transition_normal:
+        case op_put_by_id_transition_direct_out_of_line:
+        case op_put_by_id_transition_normal_out_of_line:
+            out.print(&quot; llint(&quot;);
+            dumpStructure(out, &quot;prev&quot;, exec, structure, ident);
+            out.print(&quot;, &quot;);
+            dumpStructure(out, &quot;next&quot;, exec, instruction[6].u.structure.get(), ident);
+            if (StructureChain* chain = instruction[7].u.structureChain.get()) {
+                out.print(&quot;, &quot;);
+                dumpChain(out, exec, chain, ident);
+            }
+            out.print(&quot;)&quot;);
+            break;
+            
+        default:
+            out.print(&quot; llint(unknown)&quot;);
+            break;
+        }
+    }
+#endif
+
+#if ENABLE(JIT)
+    if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
+        StructureStubInfo&amp; stubInfo = *stubPtr;
+        if (stubInfo.resetByGC)
+            out.print(&quot; (Reset By GC)&quot;);
+        
+        if (stubInfo.seen) {
+            out.printf(&quot; jit(&quot;);
+            
+            switch (stubInfo.accessType) {
+            case access_put_by_id_replace:
+                out.print(&quot;replace, &quot;);
+                dumpStructure(out, &quot;struct&quot;, exec, stubInfo.u.putByIdReplace.baseObjectStructure.get(), ident);
+                break;
+            case access_put_by_id_transition_normal:
+            case access_put_by_id_transition_direct:
+                out.print(&quot;transition, &quot;);
+                dumpStructure(out, &quot;prev&quot;, exec, stubInfo.u.putByIdTransition.previousStructure.get(), ident);
+                out.print(&quot;, &quot;);
+                dumpStructure(out, &quot;next&quot;, exec, stubInfo.u.putByIdTransition.structure.get(), ident);
+                if (StructureChain* chain = stubInfo.u.putByIdTransition.chain.get()) {
+                    out.print(&quot;, &quot;);
+                    dumpChain(out, exec, chain, ident);
+                }
+                break;
+            case access_put_by_id_list: {
+                out.printf(&quot;list = [&quot;);
+                PolymorphicPutByIdList* list = stubInfo.u.putByIdList.list;
+                CommaPrinter comma;
+                for (unsigned i = 0; i &lt; list-&gt;size(); ++i) {
+                    out.print(comma, &quot;(&quot;);
+                    const PutByIdAccess&amp; access = list-&gt;at(i);
+                    
+                    if (access.isReplace()) {
+                        out.print(&quot;replace, &quot;);
+                        dumpStructure(out, &quot;struct&quot;, exec, access.oldStructure(), ident);
+                    } else if (access.isSetter()) {
+                        out.print(&quot;setter, &quot;);
+                        dumpStructure(out, &quot;struct&quot;, exec, access.oldStructure(), ident);
+                    } else if (access.isCustom()) {
+                        out.print(&quot;custom, &quot;);
+                        dumpStructure(out, &quot;struct&quot;, exec, access.oldStructure(), ident);
+                    } else if (access.isTransition()) {
+                        out.print(&quot;transition, &quot;);
+                        dumpStructure(out, &quot;prev&quot;, exec, access.oldStructure(), ident);
+                        out.print(&quot;, &quot;);
+                        dumpStructure(out, &quot;next&quot;, exec, access.newStructure(), ident);
+                        if (access.chain()) {
+                            out.print(&quot;, &quot;);
+                            dumpChain(out, exec, access.chain(), ident);
+                        }
+                    } else
+                        out.print(&quot;unknown&quot;);
+                    
+                    out.print(&quot;)&quot;);
+                }
+                out.print(&quot;]&quot;);
+                break;
+            }
+            case access_unset:
+                out.printf(&quot;unset&quot;);
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
+            out.printf(&quot;)&quot;);
+        }
+    }
+#else
+    UNUSED_PARAM(map);
+#endif
+}
+
</ins><span class="cx"> void CodeBlock::printCallOp(PrintStream&amp; out, ExecState* exec, int location, const Instruction*&amp; it, const char* op, CacheDumpMode cacheDumpMode, bool&amp; hasPrintedProfiling, const CallLinkInfoMap&amp; map)
</span><span class="cx"> {
</span><span class="cx">     int dst = (++it)-&gt;u.operand;
</span><span class="lines">@@ -926,26 +1040,32 @@
</span><span class="cx">         }
</span><span class="cx">         case op_put_by_id: {
</span><span class="cx">             printPutByIdOp(out, exec, location, it, &quot;put_by_id&quot;);
</span><ins>+            printPutByIdCacheStatus(out, exec, location, stubInfos);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_put_by_id_out_of_line: {
</span><span class="cx">             printPutByIdOp(out, exec, location, it, &quot;put_by_id_out_of_line&quot;);
</span><ins>+            printPutByIdCacheStatus(out, exec, location, stubInfos);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_put_by_id_transition_direct: {
</span><span class="cx">             printPutByIdOp(out, exec, location, it, &quot;put_by_id_transition_direct&quot;);
</span><ins>+            printPutByIdCacheStatus(out, exec, location, stubInfos);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_put_by_id_transition_direct_out_of_line: {
</span><span class="cx">             printPutByIdOp(out, exec, location, it, &quot;put_by_id_transition_direct_out_of_line&quot;);
</span><ins>+            printPutByIdCacheStatus(out, exec, location, stubInfos);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_put_by_id_transition_normal: {
</span><span class="cx">             printPutByIdOp(out, exec, location, it, &quot;put_by_id_transition_normal&quot;);
</span><ins>+            printPutByIdCacheStatus(out, exec, location, stubInfos);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_put_by_id_transition_normal_out_of_line: {
</span><span class="cx">             printPutByIdOp(out, exec, location, it, &quot;put_by_id_transition_normal_out_of_line&quot;);
</span><ins>+            printPutByIdCacheStatus(out, exec, location, stubInfos);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_put_getter_setter: {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -989,6 +989,7 @@
</span><span class="cx">     enum CacheDumpMode { DumpCaches, DontDumpCaches };
</span><span class="cx">     void printCallOp(PrintStream&amp;, ExecState*, int location, const Instruction*&amp;, const char* op, CacheDumpMode, bool&amp; hasPrintedProfiling, const CallLinkInfoMap&amp;);
</span><span class="cx">     void printPutByIdOp(PrintStream&amp;, ExecState*, int location, const Instruction*&amp;, const char* op);
</span><ins>+    void printPutByIdCacheStatus(PrintStream&amp;, ExecState*, int location, const StubInfoMap&amp;);
</ins><span class="cx">     void printLocationAndOp(PrintStream&amp;, ExecState*, int location, const Instruction*&amp;, const char* op);
</span><span class="cx">     void printLocationOpAndRegisterOperand(PrintStream&amp;, ExecState*, int location, const Instruction*&amp; it, const char* op, int operand);
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVariantcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -108,12 +108,14 @@
</span><span class="cx">     
</span><span class="cx">     out.print(
</span><span class="cx">         &quot;&lt;&quot;, inContext(structureSet(), context), &quot;, &quot;,
</span><del>-        &quot;[&quot;, listDumpInContext(m_constantChecks, context), &quot;], &quot;,
-        &quot;alternateBase = &quot;, inContext(JSValue(m_alternateBase), context), &quot;, &quot;,
-        &quot;specificValue = &quot;, inContext(specificValue(), context), &quot;, &quot;,
-        &quot;offset = &quot;, offset());
</del><ins>+        &quot;[&quot;, listDumpInContext(m_constantChecks, context), &quot;]&quot;);
+    if (m_alternateBase)
+        out.print(&quot;, alternateBase = &quot;, inContext(JSValue(m_alternateBase), context));
+    if (specificValue())
+        out.print(&quot;, specificValue = &quot;, inContext(specificValue(), context));
+    out.print(&quot;, offset = &quot;, offset());
</ins><span class="cx">     if (m_callLinkStatus)
</span><del>-        out.print(&quot;call = &quot;, *m_callLinkStatus);
</del><ins>+        out.print(&quot;, call = &quot;, *m_callLinkStatus);
</ins><span class="cx">     out.print(&quot;&gt;&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeGetByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/GetByIdVariant.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -55,6 +55,7 @@
</span><span class="cx">     bool isSet() const { return !!m_structureSet.size(); }
</span><span class="cx">     bool operator!() const { return !isSet(); }
</span><span class="cx">     const StructureSet&amp; structureSet() const { return m_structureSet; }
</span><ins>+    StructureSet&amp; structureSet() { return m_structureSet; }
</ins><span class="cx">     const ConstantStructureCheckVector&amp; constantChecks() const { return m_constantChecks; }
</span><span class="cx">     JSObject* alternateBase() const { return m_alternateBase; }
</span><span class="cx">     JSValue specificValue() const { return m_specificValue; }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodePutByIdVarianth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -87,6 +87,12 @@
</span><span class="cx">         return m_oldStructure;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    StructureSet&amp; oldStructure()
+    {
+        ASSERT(kind() == Transition || kind() == Replace);
+        return m_oldStructure;
+    }
+    
</ins><span class="cx">     Structure* oldStructureForTransition() const;
</span><span class="cx">     
</span><span class="cx">     Structure* newStructure() const
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeStructureSetcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;StructureSet.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;DFGAbstractValue.h&quot;
</ins><span class="cx"> #include &lt;wtf/CommaPrinter.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -160,6 +161,80 @@
</span><span class="cx">         clear();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+namespace {
+
+class StructureAbstractValueContains {
+public:
+    StructureAbstractValueContains(const DFG::StructureAbstractValue&amp; value)
+        : m_value(value)
+    {
+    }
+    
+    bool operator()(Structure* structure)
+    {
+        return m_value.contains(structure);
+    }
+private:
+    const DFG::StructureAbstractValue&amp; m_value;
+};
+
+class SpeculatedTypeContains {
+public:
+    SpeculatedTypeContains(SpeculatedType type)
+        : m_type(type)
+    {
+    }
+    
+    bool operator()(Structure* structure)
+    {
+        return m_type &amp; speculationFromStructure(structure);
+    }
+private:
+    SpeculatedType m_type;
+};
+
+class ArrayModesContains {
+public:
+    ArrayModesContains(ArrayModes arrayModes)
+        : m_arrayModes(arrayModes)
+    {
+    }
+    
+    bool operator()(Structure* structure)
+    {
+        return m_arrayModes &amp; arrayModeFromStructure(structure);
+    }
+private:
+    ArrayModes m_arrayModes;
+};
+
+} // anonymous namespace
+
+void StructureSet::filter(const DFG::StructureAbstractValue&amp; other)
+{
+    StructureAbstractValueContains functor(other);
+    genericFilter(functor);
+}
+
+void StructureSet::filter(SpeculatedType type)
+{
+    SpeculatedTypeContains functor(type);
+    genericFilter(functor);
+}
+
+void StructureSet::filterArrayModes(ArrayModes arrayModes)
+{
+    ArrayModesContains functor(arrayModes);
+    genericFilter(functor);
+}
+
+void StructureSet::filter(const DFG::AbstractValue&amp; other)
+{
+    filter(other.m_structure);
+    filter(other.m_type);
+    filterArrayModes(other.m_arrayModes);
+}
+
</ins><span class="cx"> bool StructureSet::isSubsetOf(const StructureSet&amp; other) const
</span><span class="cx"> {
</span><span class="cx">     if (isThin()) {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCorebytecodeStructureSeth"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/bytecode/StructureSet.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace DFG {
</span><span class="cx"> class StructureAbstractValue;
</span><ins>+struct AbstractValue;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> class StructureSet {
</span><span class="lines">@@ -96,6 +97,11 @@
</span><span class="cx">     void filter(const StructureSet&amp;);
</span><span class="cx">     void exclude(const StructureSet&amp;);
</span><span class="cx">     
</span><ins>+    void filter(const DFG::StructureAbstractValue&amp;);
+    void filter(SpeculatedType);
+    void filterArrayModes(ArrayModes);
+    void filter(const DFG::AbstractValue&amp;);
+    
</ins><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     void genericFilter(Functor&amp; functor)
</span><span class="cx">     {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -1445,9 +1445,13 @@
</span><span class="cx">         
</span><span class="cx">     case PutStructure:
</span><span class="cx">         if (!forNode(node-&gt;child1()).m_structure.isClear()) {
</span><del>-            observeTransition(
-                clobberLimit, node-&gt;transition()-&gt;previous, node-&gt;transition()-&gt;next);
-            forNode(node-&gt;child1()).set(m_graph, node-&gt;transition()-&gt;next);
</del><ins>+            if (forNode(node-&gt;child1()).m_structure.onlyStructure() == node-&gt;transition()-&gt;next)
+                m_state.setFoundConstants(true);
+            else {
+                observeTransition(
+                    clobberLimit, node-&gt;transition()-&gt;previous, node-&gt;transition()-&gt;next);
+                forNode(node-&gt;child1()).changeStructure(m_graph, node-&gt;transition()-&gt;next);
+            }
</ins><span class="cx">         }
</span><span class="cx">         break;
</span><span class="cx">     case GetButterfly:
</span><span class="lines">@@ -1576,39 +1580,45 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case MultiGetByOffset: {
</span><del>-        AbstractValue&amp; value = forNode(node-&gt;child1());
-        ASSERT(!(value.m_type &amp; ~SpecCell)); // Edge filtering should have already ensured this.
-
-        // This should just filter down the cases in MultiGetByOffset. If that results in all
-        // cases having the same offset then we should strength reduce it to a CheckStructure +
-        // GetByOffset.
-        // https://bugs.webkit.org/show_bug.cgi?id=133229
-        if (Structure* structure = value.m_structure.onlyStructure()) {
-            bool done = false;
-            for (unsigned i = node-&gt;multiGetByOffsetData().variants.size(); i--;) {
-                const GetByIdVariant&amp; variant = node-&gt;multiGetByOffsetData().variants[i];
-                if (!variant.structureSet().contains(structure))
-                    continue;
-                
-                if (variant.alternateBase())
-                    break;
-                
-                filter(value, structure);
-                forNode(node).makeHeapTop();
-                m_state.setFoundConstants(true);
-                done = true;
-                break;
</del><ins>+        // This code will filter the base value in a manner that is possibly different (either more
+        // or less precise) than the way it would be filtered if this was strength-reduced to a
+        // CheckStructure. This is fine. It's legal for different passes over the code to prove
+        // different things about the code, so long as all of them are sound. That even includes
+        // one guy proving that code should never execute (due to a contradiction) and another guy
+        // not finding that contradiction. If someone ever proved that there would be a
+        // contradiction then there must always be a contradiction even if subsequent passes don't
+        // realize it. This is the case here.
+        
+        // Ordinarily you have to be careful with calling setFoundConstants()
+        // because of the effect on compile times, but this node is FTL-only.
+        m_state.setFoundConstants(true);
+        
+        AbstractValue base = forNode(node-&gt;child1());
+        StructureSet baseSet;
+        AbstractValue result;
+        for (unsigned i = node-&gt;multiGetByOffsetData().variants.size(); i--;) {
+            GetByIdVariant&amp; variant = node-&gt;multiGetByOffsetData().variants[i];
+            StructureSet set = variant.structureSet();
+            set.filter(base);
+            if (set.isEmpty())
+                continue;
+            baseSet.merge(set);
+            if (!variant.specificValue()) {
+                result.makeHeapTop();
+                continue;
</ins><span class="cx">             }
</span><del>-            if (done)
-                break;
</del><ins>+            AbstractValue thisResult;
+            thisResult.set(
+                m_graph,
+                *m_graph.freeze(variant.specificValue()),
+                m_state.structureClobberState());
+            result.merge(thisResult);
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        StructureSet set;
-        for (unsigned i = node-&gt;multiGetByOffsetData().variants.size(); i--;)
-            set.merge(node-&gt;multiGetByOffsetData().variants[i].structureSet());
</del><ins>+        if (forNode(node-&gt;child1()).changeStructure(m_graph, baseSet) == Contradiction)
+            m_state.setIsValid(false);
</ins><span class="cx">         
</span><del>-        filter(node-&gt;child1(), set);
-        forNode(node).makeHeapTop();
</del><ins>+        forNode(node) = result;
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">             
</span><span class="lines">@@ -1617,58 +1627,36 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case MultiPutByOffset: {
</span><del>-        AbstractValue&amp; value = forNode(node-&gt;child1());
-        ASSERT(!(value.m_type &amp; ~SpecCell)); // Edge filtering should have already ensured this.
-
-        // This should just filter down the cases in MultiPutByOffset. If that results in either
-        // one case, or nothing but replace cases and they have the same offset, then we should
-        // just strength reduce it to the appropriate combination of CheckStructure,
-        // [Re]AllocatePropertyStorage, PutStructure, and PutByOffset.
-        // https://bugs.webkit.org/show_bug.cgi?id=133229
-        if (Structure* structure = value.m_structure.onlyStructure()) {
-            bool done = false;
-            for (unsigned i = node-&gt;multiPutByOffsetData().variants.size(); i--;) {
-                const PutByIdVariant&amp; variant = node-&gt;multiPutByOffsetData().variants[i];
-                if (!variant.oldStructure().contains(structure))
-                    continue;
-                
-                if (variant.kind() == PutByIdVariant::Replace) {
-                    filter(node-&gt;child1(), structure);
-                    m_state.setFoundConstants(true);
-                    done = true;
-                    break;
-                }
-                
-                ASSERT(variant.kind() == PutByIdVariant::Transition);
-                clobberStructures(clobberLimit);
-                forNode(node-&gt;child1()).set(m_graph, variant.newStructure());
-                m_state.setFoundConstants(true);
-                done = true;
-                break;
-            }
-            if (done)
-                break;
-        }
-        
-        StructureSet oldSet;
</del><span class="cx">         StructureSet newSet;
</span><span class="cx">         TransitionVector transitions;
</span><ins>+        
+        // Ordinarily you have to be careful with calling setFoundConstants()
+        // because of the effect on compile times, but this node is FTL-only.
+        m_state.setFoundConstants(true);
+        
+        AbstractValue base = forNode(node-&gt;child1());
+        
</ins><span class="cx">         for (unsigned i = node-&gt;multiPutByOffsetData().variants.size(); i--;) {
</span><span class="cx">             const PutByIdVariant&amp; variant = node-&gt;multiPutByOffsetData().variants[i];
</span><del>-            oldSet.merge(variant.oldStructure());
</del><ins>+            StructureSet thisSet = variant.oldStructure();
+            thisSet.filter(base);
+            if (thisSet.isEmpty())
+                continue;
</ins><span class="cx">             if (variant.kind() == PutByIdVariant::Transition) {
</span><del>-                transitions.append(
-                    Transition(variant.oldStructureForTransition(), variant.newStructure()));
</del><ins>+                if (thisSet.onlyStructure() != variant.newStructure()) {
+                    transitions.append(
+                        Transition(variant.oldStructureForTransition(), variant.newStructure()));
+                } // else this is really a replace.
</ins><span class="cx">                 newSet.add(variant.newStructure());
</span><span class="cx">             } else {
</span><span class="cx">                 ASSERT(variant.kind() == PutByIdVariant::Replace);
</span><del>-                newSet.merge(variant.oldStructure());
</del><ins>+                newSet.merge(thisSet);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        filter(node-&gt;child1(), oldSet);
</del><span class="cx">         observeTransitions(clobberLimit, transitions);
</span><del>-        forNode(node-&gt;child1()).set(m_graph, newSet);
</del><ins>+        if (forNode(node-&gt;child1()).changeStructure(m_graph, newSet) == Contradiction)
+            m_state.setIsValid(false);
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractValuecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -179,6 +179,17 @@
</span><span class="cx">     return normalizeClarity(graph);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+FiltrationResult AbstractValue::changeStructure(Graph&amp; graph, const StructureSet&amp; other)
+{
+    m_type &amp;= other.speculationFromStructures();
+    m_arrayModes = other.arrayModesFromStructures();
+    m_structure = other;
+    
+    filterValueByType();
+    
+    return normalizeClarity(graph);
+}
+
</ins><span class="cx"> FiltrationResult AbstractValue::filterArrayModes(ArrayModes arrayModes)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(arrayModes);
</span><span class="lines">@@ -229,6 +240,13 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool AbstractValue::contains(Structure* structure) const
+{
+    return couldBeType(speculationFromStructure(structure))
+        &amp;&amp; (m_arrayModes &amp; arrayModeFromStructure(structure))
+        &amp;&amp; m_structure.contains(structure);
+}
+
</ins><span class="cx"> FiltrationResult AbstractValue::filter(const AbstractValue&amp; other)
</span><span class="cx"> {
</span><span class="cx">     m_type &amp;= other.m_type;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractValueh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractValue.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -267,12 +267,12 @@
</span><span class="cx">         checkConsistency();
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool couldBeType(SpeculatedType desiredType)
</del><ins>+    bool couldBeType(SpeculatedType desiredType) const
</ins><span class="cx">     {
</span><span class="cx">         return !!(m_type &amp; desiredType);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool isType(SpeculatedType desiredType)
</del><ins>+    bool isType(SpeculatedType desiredType) const
</ins><span class="cx">     {
</span><span class="cx">         return !(m_type &amp; ~desiredType);
</span><span class="cx">     }
</span><span class="lines">@@ -284,6 +284,10 @@
</span><span class="cx">     
</span><span class="cx">     FiltrationResult filter(const AbstractValue&amp;);
</span><span class="cx">     
</span><ins>+    FiltrationResult changeStructure(Graph&amp;, const StructureSet&amp;);
+    
+    bool contains(Structure*) const;
+    
</ins><span class="cx">     bool validate(JSValue value) const
</span><span class="cx">     {
</span><span class="cx">         if (isHeapTop())
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -125,6 +125,15 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">                 
</span><ins>+            case PutStructure: {
+                if (m_state.forNode(node-&gt;child1()).m_structure.onlyStructure() != node-&gt;transition()-&gt;next)
+                    break;
+                
+                node-&gt;convertToPhantom();
+                eliminated = true;
+                break;
+            }
+                
</ins><span class="cx">             case CheckFunction: {
</span><span class="cx">                 if (m_state.forNode(node-&gt;child1()).value() != node-&gt;function()-&gt;value())
</span><span class="cx">                     break;
</span><span class="lines">@@ -147,47 +156,69 @@
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="cx">             case MultiGetByOffset: {
</span><del>-                Edge childEdge = node-&gt;child1();
-                Node* child = childEdge.node();
</del><ins>+                Edge baseEdge = node-&gt;child1();
+                Node* base = baseEdge.node();
</ins><span class="cx">                 MultiGetByOffsetData&amp; data = node-&gt;multiGetByOffsetData();
</span><span class="cx"> 
</span><del>-                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
-                if (!structure)
</del><ins>+                // First prune the variants, then check if the MultiGetByOffset can be
+                // strength-reduced to a GetByOffset.
+                
+                AbstractValue baseValue = m_state.forNode(base);
+                
+                m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+                eliminated = true; // Don't allow the default constant folder to do things to this.
+                
+                for (unsigned i = 0; i &lt; data.variants.size(); ++i) {
+                    GetByIdVariant&amp; variant = data.variants[i];
+                    variant.structureSet().filter(baseValue);
+                    if (variant.structureSet().isEmpty()) {
+                        data.variants[i--] = data.variants.last();
+                        data.variants.removeLast();
+                    }
+                }
+                
+                if (data.variants.size() != 1)
</ins><span class="cx">                     break;
</span><span class="cx">                 
</span><del>-                for (unsigned i = data.variants.size(); i--;) {
-                    const GetByIdVariant&amp; variant = data.variants[i];
-                    if (!variant.structureSet().contains(structure))
-                        continue;
-                    
-                    if (variant.alternateBase())
-                        break;
-                    
-                    emitGetByOffset(indexInBlock, node, structure, variant, data.identifierNumber);
-                    eliminated = true;
-                    break;
-                }
</del><ins>+                emitGetByOffset(
+                    indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="cx">             case MultiPutByOffset: {
</span><del>-                Edge childEdge = node-&gt;child1();
-                Node* child = childEdge.node();
</del><ins>+                Edge baseEdge = node-&gt;child1();
+                Node* base = baseEdge.node();
</ins><span class="cx">                 MultiPutByOffsetData&amp; data = node-&gt;multiPutByOffsetData();
</span><ins>+                
+                AbstractValue baseValue = m_state.forNode(base);
</ins><span class="cx"> 
</span><del>-                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
-                if (!structure)
-                    break;
</del><ins>+                m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+                eliminated = true; // Don't allow the default constant folder to do things to this.
</ins><span class="cx">                 
</span><del>-                for (unsigned i = data.variants.size(); i--;) {
-                    const PutByIdVariant&amp; variant = data.variants[i];
-                    if (!variant.oldStructure().contains(structure))
</del><ins>+
+                for (unsigned i = 0; i &lt; data.variants.size(); ++i) {
+                    PutByIdVariant&amp; variant = data.variants[i];
+                    variant.oldStructure().filter(baseValue);
+                    
+                    if (variant.oldStructure().isEmpty()) {
+                        data.variants[i--] = data.variants.last();
+                        data.variants.removeLast();
</ins><span class="cx">                         continue;
</span><ins>+                    }
</ins><span class="cx">                     
</span><del>-                    emitPutByOffset(indexInBlock, node, variant, data.identifierNumber);
-                    eliminated = true;
</del><ins>+                    if (variant.kind() == PutByIdVariant::Transition
+                        &amp;&amp; variant.oldStructure().onlyStructure() == variant.newStructure()) {
+                        variant = PutByIdVariant::replace(
+                            variant.oldStructure(),
+                            variant.offset());
+                    }
+                }
+
+                if (data.variants.size() != 1)
</ins><span class="cx">                     break;
</span><del>-                }
</del><ins>+                
+                emitPutByOffset(
+                    indexInBlock, node, baseValue, data.variants[0], data.identifierNumber);
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">         
</span><span class="lines">@@ -200,7 +231,12 @@
</span><span class="cx">                 if (childEdge.useKind() != CellUse)
</span><span class="cx">                     break;
</span><span class="cx">                 
</span><del>-                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
</del><ins>+                AbstractValue baseValue = m_state.forNode(child);
+
+                m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+                eliminated = true; // Don't allow the default constant folder to do things to this.
+
+                Structure* structure = baseValue.m_structure.onlyStructure();
</ins><span class="cx">                 if (!structure)
</span><span class="cx">                     break;
</span><span class="cx"> 
</span><span class="lines">@@ -214,7 +250,7 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                 
</span><del>-                emitGetByOffset(indexInBlock, node, structure, status[0], identifierNumber);
</del><ins>+                emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
</ins><span class="cx">                 eliminated = true;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -228,7 +264,12 @@
</span><span class="cx">                 
</span><span class="cx">                 ASSERT(childEdge.useKind() == CellUse);
</span><span class="cx">                 
</span><del>-                Structure* structure = m_state.forNode(child).m_structure.onlyStructure();
</del><ins>+                AbstractValue baseValue = m_state.forNode(child);
+
+                m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
+                eliminated = true; // Don't allow the default constant folder to do things to this.
+
+                Structure* structure = baseValue.m_structure.onlyStructure();
</ins><span class="cx">                 if (!structure)
</span><span class="cx">                     break;
</span><span class="cx">                 
</span><span class="lines">@@ -244,7 +285,7 @@
</span><span class="cx">                 if (status.numVariants() != 1)
</span><span class="cx">                     break;
</span><span class="cx">                 
</span><del>-                emitPutByOffset(indexInBlock, node, status[0], identifierNumber);
</del><ins>+                emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber);
</ins><span class="cx">                 eliminated = true;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -336,33 +377,24 @@
</span><span class="cx">         return changed;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    void emitGetByOffset(unsigned indexInBlock, Node* node, Structure* structure, const GetByIdVariant&amp; variant, unsigned identifierNumber)
</del><ins>+    void emitGetByOffset(unsigned indexInBlock, Node* node, const AbstractValue&amp; baseValue, const GetByIdVariant&amp; variant, unsigned identifierNumber)
</ins><span class="cx">     {
</span><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="cx"> 
</span><del>-        bool needsCellCheck = m_state.forNode(child).m_type &amp; ~SpecCell;
</del><ins>+        addBaseCheck(indexInBlock, node, baseValue, variant.structureSet());
</ins><span class="cx">         
</span><del>-        ASSERT(!variant.alternateBase());
-        ASSERT_UNUSED(structure, variant.structureSet().contains(structure));
-        
-        // Now before we do anything else, push the CFA forward over the GetById
-        // and make sure we signal to the loop that it should continue and not
-        // do any eliminations.
-        m_interpreter.execute(indexInBlock);
-        
-        if (needsCellCheck) {
-            m_insertionSet.insertNode(
-                indexInBlock, SpecNone, Phantom, origin, childEdge);
-        }
-        
</del><span class="cx">         if (variant.specificValue()) {
</span><span class="cx">             m_graph.convertToConstant(node, m_graph.freeze(variant.specificValue()));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        childEdge.setUseKind(KnownCellUse);
</del><ins>+        if (variant.alternateBase()) {
+            child = m_insertionSet.insertConstant(indexInBlock, origin, variant.alternateBase());
+            childEdge = Edge(child, KnownCellUse);
+        } else
+            childEdge.setUseKind(KnownCellUse);
</ins><span class="cx">         
</span><span class="cx">         Edge propertyStorage;
</span><span class="cx">         
</span><span class="lines">@@ -381,24 +413,13 @@
</span><span class="cx">         m_graph.m_storageAccessData.append(storageAccessData);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void emitPutByOffset(unsigned indexInBlock, Node* node, const PutByIdVariant&amp; variant, unsigned identifierNumber)
</del><ins>+    void emitPutByOffset(unsigned indexInBlock, Node* node, const AbstractValue&amp; baseValue, const PutByIdVariant&amp; variant, unsigned identifierNumber)
</ins><span class="cx">     {
</span><span class="cx">         NodeOrigin origin = node-&gt;origin;
</span><span class="cx">         Edge childEdge = node-&gt;child1();
</span><del>-        Node* child = childEdge.node();
</del><span class="cx">         
</span><del>-        bool needsCellCheck = m_state.forNode(child).m_type &amp; ~SpecCell;
-        
-        // Now before we do anything else, push the CFA forward over the PutById
-        // and make sure we signal to the loop that it should continue and not
-        // do any eliminations.
-        m_interpreter.execute(indexInBlock);
</del><ins>+        addBaseCheck(indexInBlock, node, baseValue, variant.oldStructure());
</ins><span class="cx"> 
</span><del>-        if (needsCellCheck) {
-            m_insertionSet.insertNode(
-                indexInBlock, SpecNone, Phantom, origin, childEdge);
-        }
-
</del><span class="cx">         childEdge.setUseKind(KnownCellUse);
</span><span class="cx"> 
</span><span class="cx">         Transition* transition = 0;
</span><span class="lines">@@ -459,6 +480,25 @@
</span><span class="cx">         storageAccessData.identifierNumber = identifierNumber;
</span><span class="cx">         m_graph.m_storageAccessData.append(storageAccessData);
</span><span class="cx">     }
</span><ins>+    
+    void addBaseCheck(
+        unsigned indexInBlock, Node* node, const AbstractValue&amp; baseValue, const StructureSet&amp; set)
+    {
+        if (!baseValue.m_structure.isSubsetOf(set)) {
+            // Arises when we prune MultiGetByOffset. We could have a
+            // MultiGetByOffset with a single variant that checks for structure S,
+            // and the input has structures S and T, for example.
+            m_insertionSet.insertNode(
+                indexInBlock, SpecNone, CheckStructure, node-&gt;origin,
+                OpInfo(m_graph.addStructureSet(set)), node-&gt;child1());
+            return;
+        }
+        
+        if (baseValue.m_type &amp; ~SpecCell) {
+            m_insertionSet.insertNode(
+                indexInBlock, SpecNone, Phantom, node-&gt;origin, node-&gt;child1());
+        }
+    }
</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="branchesftloptSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -952,7 +952,7 @@
</span><span class="cx"> 
</span><span class="cx"> FrozenValue* Graph::freezeStrong(JSValue value)
</span><span class="cx"> {
</span><del>-    FrozenValue* result = freeze(value);
</del><ins>+    FrozenValue* result = freezeFragile(value);
</ins><span class="cx">     result-&gt;strengthenTo(StrongValue);
</span><span class="cx">     return result;
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -146,8 +146,8 @@
</span><span class="cx">     void dethread();
</span><span class="cx">     
</span><span class="cx">     FrozenValue* freezeFragile(JSValue value);
</span><del>-    FrozenValue* freeze(JSValue value); // We use weak freezing by default.
-    FrozenValue* freezeStrong(JSValue value); // Shorthand for freeze(value)-&gt;markStrongly().
</del><ins>+    FrozenValue* freeze(JSValue value); // We use weak freezing by default. Shorthand for freezeFragile(value)-&gt;strengthenTo(WeakValue);
+    FrozenValue* freezeStrong(JSValue value); // Shorthand for freezeFragile(value)-&gt;strengthenTo(StrongValue).
</ins><span class="cx">     
</span><span class="cx">     void convertToConstant(Node* node, FrozenValue* value);
</span><span class="cx">     void convertToConstant(Node* node, JSValue value);
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGStructureAbstractValueh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -55,6 +55,18 @@
</span><span class="cx">         setClobbered(other.isClobbered());
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    ALWAYS_INLINE StructureAbstractValue&amp; operator=(Structure* structure)
+    {
+        m_set = structure;
+        setClobbered(false);
+        return *this;
+    }
+    ALWAYS_INLINE StructureAbstractValue&amp; operator=(const StructureSet&amp; other)
+    {
+        m_set = other;
+        setClobbered(false);
+        return *this;
+    }
</ins><span class="cx">     ALWAYS_INLINE StructureAbstractValue&amp; operator=(const StructureAbstractValue&amp; other)
</span><span class="cx">     {
</span><span class="cx">         m_set = other.m_set;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (170140 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-06-19 04:16:04 UTC (rev 170140)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -3202,6 +3202,12 @@
</span><span class="cx">         LValue base = lowCell(m_node-&gt;child1());
</span><span class="cx">         
</span><span class="cx">         MultiGetByOffsetData&amp; data = m_node-&gt;multiGetByOffsetData();
</span><ins>+
+        if (data.variants.isEmpty()) {
+            // Protect against creating a Phi function with zero inputs. LLVM doesn't like that.
+            terminate(BadCache);
+            return;
+        }
</ins><span class="cx">         
</span><span class="cx">         Vector&lt;LBasicBlock, 2&gt; blocks(data.variants.size());
</span><span class="cx">         for (unsigned i = data.variants.size(); i--;)
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressfoldmultigetbyoffsettogetbyoffsetwithoutfoldingthestructurecheckjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-get-by-offset-to-get-by-offset-without-folding-the-structure-check.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+function foo(o) {
+    return o.f;
+}
+
+function fu(o) {
+    return o.e;
+}
+
+function bar(f, o) {
+    return f(o);
+}
+
+function baz(f, o) {
+    return f(o);
+}
+
+for (var i = 0; i &lt; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2, g:3});
+    fu({d:1, e:2, f:3, g:4});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42; }, null);
+    baz(fu, {e:1});
+    baz(function() { }, null);
+    baz(function() { return 42; }, null);
+}
+    
+(function(f, g, o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        var q;
+        if (i == n - 1)
+            q = p;
+        else
+            q = o;
+        result += baz(g, q);
+        result += bar(f, q);
+    }
+    if (result != (n - 1) * (o.f + o.e) + 12 + 13)
+        throw &quot;Error: bad result: &quot; + result;
+})(foo, fu, {f:42, e:2}, {e:12, f:13, g:14});
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressfoldmultiputbyoffsettoputbyoffsetwithoutfoldingthestructurecheckjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset-without-folding-the-structure-check.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+function foo(o) {
+    o.f = 1;
+}
+
+function fu(o) {
+    o.e = 2;
+}
+
+function bar(f, o) {
+    f(o);
+}
+
+function baz(f, o) {
+    f(o);
+}
+
+for (var i = 0; i &lt; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2, g:3});
+    fu({d:1, e:2, f:3, g:4});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42; }, null);
+    baz(fu, {e:1});
+    baz(function() { }, null);
+    baz(function() { return 42; }, null);
+}
+    
+(function(f, g, o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        var q;
+        if (i == n - 1)
+            q = p;
+        else
+            q = o;
+        baz(g, q);
+        bar(f, q);
+    }
+    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, fu, {f:42, e:2}, {e:12, f:13, g:14});
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoretestsstressprunemultiputbyoffsetreplaceortransitionvariantjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js (0 => 170141)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/tests/stress/prune-multi-put-by-offset-replace-or-transition-variant.js        2014-06-19 04:34:25 UTC (rev 170141)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+function foo(o) {
+    o.f = 1;
+}
+
+function fu(o) {
+    o.e = 2;
+}
+
+function bar(f, o) {
+    f(o);
+}
+
+function baz(f, o) {
+    f(o);
+}
+
+for (var i = 0; i &lt; 100; ++i) {
+    foo({f:1, e:2});
+    foo({e:1, f:2});
+    foo({e:1});
+    foo({d:1, e:2, f:3});
+    fu({f:1, e:2});
+    fu({e:1, f:2});
+    fu({e:1, f:2, g:3});
+    fu({d:1, e:2, f:3, g:4});
+}
+    
+for (var i = 0; i &lt; 100; ++i) {
+    bar(foo, {f:1});
+    bar(function() { }, null);
+    bar(function() { return 42; }, null);
+    baz(fu, {e:1});
+    baz(function() { }, null);
+    baz(function() { return 42; }, null);
+}
+    
+(function(f, g, o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0; i &lt; n; ++i) {
+        var q;
+        if (i == n - 1)
+            q = p;
+        else
+            q = o;
+        baz(g, q);
+        bar(f, q);
+    }
+    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, fu, {e:42, f:2}, {e:12, f:13, g:14});
+
</ins></span></pre>
</div>
</div>

</body>
</html>