<!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>[164620] trunk</title>
</head>
<body>

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

<h3>Log Message</h3>
<pre>FTL should do polymorphic PutById inlining
https://bugs.webkit.org/show_bug.cgi?id=129210

Source/JavaScriptCore: 

Reviewed by Mark Hahnenberg and Oliver Hunt.
        
This makes PutByIdStatus inform us about polymorphic cases by returning an array of
PutByIdVariants. The DFG now has a node called MultiPutByOffset that indicates a
selection of multiple inlined PutByIdVariants.
        
MultiPutByOffset is almost identical to MultiGetByOffset, which we added in
http://trac.webkit.org/changeset/164207.
        
This also does some FTL refactoring to make MultiPutByOffset share code with some nodes
that generate similar code.
        
1% speed-up on V8v7 due to splay improving by 6.8%. Splay does the thing where it
sometimes swaps field insertion order, creating fake polymorphism.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):
(JSC::PutByIdStatus::computeForStubInfo):
(JSC::PutByIdStatus::dump):
* bytecode/PutByIdStatus.h:
(JSC::PutByIdStatus::PutByIdStatus):
(JSC::PutByIdStatus::isSimple):
(JSC::PutByIdStatus::numVariants):
(JSC::PutByIdStatus::variants):
(JSC::PutByIdStatus::at):
(JSC::PutByIdStatus::operator[]):
* bytecode/PutByIdVariant.cpp: Added.
(JSC::PutByIdVariant::dump):
(JSC::PutByIdVariant::dumpInContext):
* bytecode/PutByIdVariant.h: Added.
(JSC::PutByIdVariant::PutByIdVariant):
(JSC::PutByIdVariant::replace):
(JSC::PutByIdVariant::transition):
(JSC::PutByIdVariant::kind):
(JSC::PutByIdVariant::isSet):
(JSC::PutByIdVariant::operator!):
(JSC::PutByIdVariant::structure):
(JSC::PutByIdVariant::oldStructure):
(JSC::PutByIdVariant::newStructure):
(JSC::PutByIdVariant::structureChain):
(JSC::PutByIdVariant::offset):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::emitPrototypeChecks):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::emitPutById):
(JSC::DFG::ByteCodeParser::handlePutById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::checkStructureElimination):
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
(JSC::DFG::CSEPhase::putStructureStoreElimination):
(JSC::DFG::CSEPhase::getByOffsetLoadElimination):
(JSC::DFG::CSEPhase::putByOffsetStoreElimination):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
* dfg/DFGNode.cpp:
(JSC::DFG::MultiPutByOffsetData::writesStructures):
(JSC::DFG::MultiPutByOffsetData::reallocatesStorage):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPutByOffset):
(JSC::DFG::Node::hasMultiPutByOffsetData):
(JSC::DFG::Node::multiPutByOffsetData):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
(JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compilePutStructure):
(JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compilePutByOffset):
(JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
(JSC::FTL::LowerDFGToLLVM::loadProperty):
(JSC::FTL::LowerDFGToLLVM::storeProperty):
(JSC::FTL::LowerDFGToLLVM::addressOfProperty):
(JSC::FTL::LowerDFGToLLVM::storageForTransition):
(JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage):
(JSC::FTL::LowerDFGToLLVM::emitStoreBarrier):
* tests/stress/fold-multi-put-by-offset-to-put-by-offset.js: Added.
* tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js: Added.
* tests/stress/multi-put-by-offset-reallocation-cases.js: Added.

LayoutTests: 

Reviewed by Mark Hahnenberg and Oliver Hunt.
        
Add a microbenchmark for polymorphic PutById.

* js/regress/polymorphic-put-by-id-expected.txt: Added.
* js/regress/polymorphic-put-by-id.html: Added.
* js/regress/script-tests/polymorphic-put-by-id.js: Added.
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreGNUmakefilelistam">trunk/Source/JavaScriptCore/GNUmakefile.list.am</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePutByIdStatuscpp">trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePutByIdStatush">trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCSEPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodecpp">trunk/Source/JavaScriptCore/dfg/DFGNode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGTypeCheckHoistingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregresspolymorphicputbyidexpectedtxt">trunk/LayoutTests/js/regress/polymorphic-put-by-id-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregresspolymorphicputbyidhtml">trunk/LayoutTests/js/regress/polymorphic-put-by-id.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestspolymorphicputbyidjs">trunk/LayoutTests/js/regress/script-tests/polymorphic-put-by-id.js</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePutByIdVariantcpp">trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodePutByIdVarianth">trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressfoldmultiputbyoffsettoputbyoffsetjs">trunk/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressmultiputbyoffsetreallocationbutterflycsejs">trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressmultiputbyoffsetreallocationcasesjs">trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-cases.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/LayoutTests/ChangeLog        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-02-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL should do polymorphic PutById inlining
+        https://bugs.webkit.org/show_bug.cgi?id=129210
+
+        Reviewed by Mark Hahnenberg and Oliver Hunt.
+        
+        Add a microbenchmark for polymorphic PutById.
+
+        * js/regress/polymorphic-put-by-id-expected.txt: Added.
+        * js/regress/polymorphic-put-by-id.html: Added.
+        * js/regress/script-tests/polymorphic-put-by-id.js: Added.
+        (foo):
+
</ins><span class="cx"> 2014-02-24  Samuel White  &lt;samuel_white@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AX: AccessibilityObject::findMatchingObjects should never include 'this' in results.
</span></span></pre></div>
<a id="trunkLayoutTestsjsregresspolymorphicputbyidexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/polymorphic-put-by-id-expected.txt (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/polymorphic-put-by-id-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/polymorphic-put-by-id-expected.txt        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/polymorphic-put-by-id
+
+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="trunkLayoutTestsjsregresspolymorphicputbyidhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/polymorphic-put-by-id.html (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/polymorphic-put-by-id.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/polymorphic-put-by-id.html        2014-02-25 02:02:50 UTC (rev 164620)
</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/polymorphic-put-by-id.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="trunkLayoutTestsjsregressscripttestspolymorphicputbyidjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/polymorphic-put-by-id.js (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/polymorphic-put-by-id.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/polymorphic-put-by-id.js        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+function foo(o) {
+    for (var i = 0; i &lt; 100; ++i)
+        o.f = (o.f | 0) + 42;
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var object;
+    if ((i % 3) == 0)
+        object = {g:3};
+    else if ((i % 3) == 1)
+        object = {f:1, g:2};
+    else if ((i % 3) == 2)
+        object = {g:1, f:2};
+    foo(object);
+    if (object.f != 42 * 100 + (i % 3))
+        throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + object.f;
+}
+
+var r = {g:3, h:4, f:5};
+foo(r);
+if (r.f != 5 + 42 * 100)
+    throw &quot;Error: bad result at end: &quot; + r.f;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -82,6 +82,7 @@
</span><span class="cx">     bytecode/PreciseJumpTargets.cpp
</span><span class="cx">     bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp
</span><span class="cx">     bytecode/PutByIdStatus.cpp
</span><ins>+    bytecode/PutByIdVariant.cpp
</ins><span class="cx">     bytecode/ReduceWhitespace.cpp
</span><span class="cx">     bytecode/SamplingTool.cpp
</span><span class="cx">     bytecode/SpecialPointer.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -1,3 +1,119 @@
</span><ins>+2014-02-24  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL should do polymorphic PutById inlining
+        https://bugs.webkit.org/show_bug.cgi?id=129210
+
+        Reviewed by Mark Hahnenberg and Oliver Hunt.
+        
+        This makes PutByIdStatus inform us about polymorphic cases by returning an array of
+        PutByIdVariants. The DFG now has a node called MultiPutByOffset that indicates a
+        selection of multiple inlined PutByIdVariants.
+        
+        MultiPutByOffset is almost identical to MultiGetByOffset, which we added in
+        http://trac.webkit.org/changeset/164207.
+        
+        This also does some FTL refactoring to make MultiPutByOffset share code with some nodes
+        that generate similar code.
+        
+        1% speed-up on V8v7 due to splay improving by 6.8%. Splay does the thing where it
+        sometimes swaps field insertion order, creating fake polymorphism.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/PutByIdStatus.cpp:
+        (JSC::PutByIdStatus::computeFromLLInt):
+        (JSC::PutByIdStatus::computeFor):
+        (JSC::PutByIdStatus::computeForStubInfo):
+        (JSC::PutByIdStatus::dump):
+        * bytecode/PutByIdStatus.h:
+        (JSC::PutByIdStatus::PutByIdStatus):
+        (JSC::PutByIdStatus::isSimple):
+        (JSC::PutByIdStatus::numVariants):
+        (JSC::PutByIdStatus::variants):
+        (JSC::PutByIdStatus::at):
+        (JSC::PutByIdStatus::operator[]):
+        * bytecode/PutByIdVariant.cpp: Added.
+        (JSC::PutByIdVariant::dump):
+        (JSC::PutByIdVariant::dumpInContext):
+        * bytecode/PutByIdVariant.h: Added.
+        (JSC::PutByIdVariant::PutByIdVariant):
+        (JSC::PutByIdVariant::replace):
+        (JSC::PutByIdVariant::transition):
+        (JSC::PutByIdVariant::kind):
+        (JSC::PutByIdVariant::isSet):
+        (JSC::PutByIdVariant::operator!):
+        (JSC::PutByIdVariant::structure):
+        (JSC::PutByIdVariant::oldStructure):
+        (JSC::PutByIdVariant::newStructure):
+        (JSC::PutByIdVariant::structureChain):
+        (JSC::PutByIdVariant::offset):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::emitPrototypeChecks):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        (JSC::DFG::ByteCodeParser::emitPutById):
+        (JSC::DFG::ByteCodeParser::handlePutById):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::checkStructureElimination):
+        (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination):
+        (JSC::DFG::CSEPhase::putStructureStoreElimination):
+        (JSC::DFG::CSEPhase::getByOffsetLoadElimination):
+        (JSC::DFG::CSEPhase::putByOffsetStoreElimination):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGGraph.h:
+        * dfg/DFGNode.cpp:
+        (JSC::DFG::MultiPutByOffsetData::writesStructures):
+        (JSC::DFG::MultiPutByOffsetData::reallocatesStorage):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToPutByOffset):
+        (JSC::DFG::Node::hasMultiPutByOffsetData):
+        (JSC::DFG::Node::multiPutByOffsetData):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGTypeCheckHoistingPhase.cpp:
+        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks):
+        (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compilePutStructure):
+        (JSC::FTL::LowerDFGToLLVM::compileAllocatePropertyStorage):
+        (JSC::FTL::LowerDFGToLLVM::compileReallocatePropertyStorage):
+        (JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
+        (JSC::FTL::LowerDFGToLLVM::compileMultiGetByOffset):
+        (JSC::FTL::LowerDFGToLLVM::compilePutByOffset):
+        (JSC::FTL::LowerDFGToLLVM::compileMultiPutByOffset):
+        (JSC::FTL::LowerDFGToLLVM::loadProperty):
+        (JSC::FTL::LowerDFGToLLVM::storeProperty):
+        (JSC::FTL::LowerDFGToLLVM::addressOfProperty):
+        (JSC::FTL::LowerDFGToLLVM::storageForTransition):
+        (JSC::FTL::LowerDFGToLLVM::allocatePropertyStorage):
+        (JSC::FTL::LowerDFGToLLVM::reallocatePropertyStorage):
+        (JSC::FTL::LowerDFGToLLVM::emitStoreBarrier):
+        * tests/stress/fold-multi-put-by-offset-to-put-by-offset.js: Added.
+        * tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js: Added.
+        * tests/stress/multi-put-by-offset-reallocation-cases.js: Added.
+
</ins><span class="cx"> 2014-02-24  peavo@outlook.com  &lt;peavo@outlook.com&gt;
</span><span class="cx"> 
</span><span class="cx">         JSC regressions after r164494
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreGNUmakefilelistam"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/GNUmakefile.list.am (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/GNUmakefile.list.am        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/GNUmakefile.list.am        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -182,6 +182,8 @@
</span><span class="cx">         Source/JavaScriptCore/bytecode/SpeculatedType.h \
</span><span class="cx">         Source/JavaScriptCore/bytecode/PutByIdStatus.cpp \
</span><span class="cx">         Source/JavaScriptCore/bytecode/PutByIdStatus.h \
</span><ins>+        Source/JavaScriptCore/bytecode/PutByIdVariant.cpp \
+        Source/JavaScriptCore/bytecode/PutByIdVariant.h \
</ins><span class="cx">         Source/JavaScriptCore/bytecode/PutKind.h \
</span><span class="cx">         Source/JavaScriptCore/bytecode/ReduceWhitespace.cpp \
</span><span class="cx">         Source/JavaScriptCore/bytecode/ReduceWhitespace.h \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -337,6 +337,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\PreciseJumpTargets.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\PutByIdStatus.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\bytecode\PutByIdVariant.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\ReduceWhitespace.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\SamplingTool.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\bytecode\SpecialPointer.cpp&quot; /&gt;
</span><span class="lines">@@ -858,6 +859,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\PreciseJumpTargets.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\PutByIdStatus.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\bytecode\PutByIdVariant.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\PutKind.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\ReduceWhitespace.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\bytecode\SamplingTool.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -357,6 +357,8 @@
</span><span class="cx">                 0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */; };
</span><span class="cx">                 0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329B14CA7DC10085F3C6 /* StructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F93B4A918B92C4D00178A3F /* PutByIdVariant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */; };
+                0F93B4AA18B92C4D00178A3F /* PutByIdVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F96EBB316676EF6008BADE3 /* CodeBlockWithJITType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F9749711687ADE400A4FF6A /* JSCellInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -1832,6 +1834,8 @@
</span><span class="cx">                 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdStatus.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdStatus.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdVariant.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdVariant.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockWithJITType.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCellInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4585,6 +4589,8 @@
</span><span class="cx">                                 0FC97F32182020D7002C9B26 /* ProfiledCodeBlockJettisoningWatchpoint.h */,
</span><span class="cx">                                 0F93329914CA7DC10085F3C6 /* PutByIdStatus.cpp */,
</span><span class="cx">                                 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
</span><ins>+                                0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */,
+                                0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */,
</ins><span class="cx">                                 0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */,
</span><span class="cx">                                 0FF60ABF16740F8100029779 /* ReduceWhitespace.cpp */,
</span><span class="cx">                                 0FF60AC016740F8100029779 /* ReduceWhitespace.h */,
</span><span class="lines">@@ -5387,6 +5393,7 @@
</span><span class="cx">                                 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */,
</span><span class="cx">                                 860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */,
</span><span class="cx">                                 860161E60F3A83C100F84710 /* MacroAssemblerX86Common.h in Headers */,
</span><ins>+                                0F93B4AA18B92C4D00178A3F /* PutByIdVariant.h in Headers */,
</ins><span class="cx">                                 A700873A17CBE85300C3E643 /* MapConstructor.h in Headers */,
</span><span class="cx">                                 A78507D717CBC6FD0011F6E7 /* MapData.h in Headers */,
</span><span class="cx">                                 A74DEF92182D991400522C22 /* MapIteratorConstructor.h in Headers */,
</span><span class="lines">@@ -6174,6 +6181,7 @@
</span><span class="cx">                                 0FC20CB51852E2C600C9E954 /* DFGStrengthReductionPhase.cpp in Sources */,
</span><span class="cx">                                 0F2FCCFE18A60070001A27F8 /* DFGThreadData.cpp in Sources */,
</span><span class="cx">                                 0FC097A1146B28CA00CF2442 /* DFGThunks.cpp in Sources */,
</span><ins>+                                0F93B4A918B92C4D00178A3F /* PutByIdVariant.cpp in Sources */,
</ins><span class="cx">                                 0FD8A32717D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.cpp in Sources */,
</span><span class="cx">                                 0FD8A32917D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.cpp in Sources */,
</span><span class="cx">                                 0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePutByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -30,8 +30,10 @@
</span><span class="cx"> #include &quot;LLIntData.h&quot;
</span><span class="cx"> #include &quot;LowLevelInterpreter.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><ins>+#include &quot;PolymorphicPutByIdList.h&quot;
</ins><span class="cx"> #include &quot;Structure.h&quot;
</span><span class="cx"> #include &quot;StructureChain.h&quot;
</span><ins>+#include &lt;wtf/ListDump.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -56,15 +58,15 @@
</span><span class="cx"> 
</span><span class="cx">     Structure* structure = instruction[4].u.structure.get();
</span><span class="cx">     if (!structure)
</span><del>-        return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(NoInformation);
</ins><span class="cx">     
</span><span class="cx">     if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id)
</span><span class="cx">         || instruction[0].u.opcode == LLInt::getOpcode(llint_op_put_by_id_out_of_line)) {
</span><span class="cx">         PropertyOffset offset = structure-&gt;getConcurrently(*profiledBlock-&gt;vm(), uid);
</span><span class="cx">         if (!isValidOffset(offset))
</span><del>-            return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
</del><ins>+            return PutByIdStatus(NoInformation);
</ins><span class="cx">         
</span><del>-        return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
</del><ins>+        return PutByIdVariant::replace(structure, offset);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ASSERT(structure-&gt;transitionWatchpointSetHasBeenInvalidated());
</span><span class="lines">@@ -81,14 +83,14 @@
</span><span class="cx">     
</span><span class="cx">     PropertyOffset offset = newStructure-&gt;getConcurrently(*profiledBlock-&gt;vm(), uid);
</span><span class="cx">     if (!isValidOffset(offset))
</span><del>-        return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(NoInformation);
</ins><span class="cx">     
</span><del>-    return PutByIdStatus(
-        SimpleTransition, structure, newStructure,
</del><ins>+    return PutByIdVariant::transition(
+        structure, newStructure,
</ins><span class="cx">         chain ? adoptRef(new IntendedStructureChain(profiledBlock, structure, chain)) : 0,
</span><span class="cx">         offset);
</span><span class="cx"> #else
</span><del>-    return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
</del><ins>+    return PutByIdStatus(NoInformation);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -102,7 +104,7 @@
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     if (profiledBlock-&gt;likelyToTakeSlowCase(bytecodeIndex)
</span><span class="cx">         || hasExitSite(locker, profiledBlock, bytecodeIndex))
</span><del>-        return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">     
</span><span class="cx">     StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex));
</span><span class="cx">     PutByIdStatus result = computeForStubInfo(locker, profiledBlock, stubInfo, uid);
</span><span class="lines">@@ -112,7 +114,7 @@
</span><span class="cx">     return result;
</span><span class="cx"> #else // ENABLE(JIT)
</span><span class="cx">     UNUSED_PARAM(map);
</span><del>-    return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
</del><ins>+    return PutByIdStatus(NoInformation);
</ins><span class="cx"> #endif // ENABLE(JIT)
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -123,25 +125,22 @@
</span><span class="cx">         return PutByIdStatus();
</span><span class="cx">     
</span><span class="cx">     if (stubInfo-&gt;resetByGC)
</span><del>-        return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(TakesSlowPath);
</ins><span class="cx"> 
</span><span class="cx">     switch (stubInfo-&gt;accessType) {
</span><span class="cx">     case access_unset:
</span><span class="cx">         // If the JIT saw it but didn't optimize it, then assume that this takes slow path.
</span><del>-        return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">         
</span><span class="cx">     case access_put_by_id_replace: {
</span><span class="cx">         PropertyOffset offset =
</span><span class="cx">             stubInfo-&gt;u.putByIdReplace.baseObjectStructure-&gt;getConcurrently(
</span><span class="cx">                 *profiledBlock-&gt;vm(), uid);
</span><span class="cx">         if (isValidOffset(offset)) {
</span><del>-            return PutByIdStatus(
-                SimpleReplace,
-                stubInfo-&gt;u.putByIdReplace.baseObjectStructure.get(),
-                0, 0,
-                offset);
</del><ins>+            return PutByIdVariant::replace(
+                stubInfo-&gt;u.putByIdReplace.baseObjectStructure.get(), offset);
</ins><span class="cx">         }
</span><del>-        return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case access_put_by_id_transition_normal:
</span><span class="lines">@@ -151,8 +150,7 @@
</span><span class="cx">             stubInfo-&gt;u.putByIdTransition.structure-&gt;getConcurrently(
</span><span class="cx">                 *profiledBlock-&gt;vm(), uid);
</span><span class="cx">         if (isValidOffset(offset)) {
</span><del>-            return PutByIdStatus(
-                SimpleTransition,
</del><ins>+            return PutByIdVariant::transition(
</ins><span class="cx">                 stubInfo-&gt;u.putByIdTransition.previousStructure.get(),
</span><span class="cx">                 stubInfo-&gt;u.putByIdTransition.structure.get(),
</span><span class="cx">                 stubInfo-&gt;u.putByIdTransition.chain ? adoptRef(new IntendedStructureChain(
</span><span class="lines">@@ -160,13 +158,51 @@
</span><span class="cx">                     stubInfo-&gt;u.putByIdTransition.chain.get())) : 0,
</span><span class="cx">                 offset);
</span><span class="cx">         }
</span><del>-        return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case access_put_by_id_list: {
+        PolymorphicPutByIdList* list = stubInfo-&gt;u.putByIdList.list;
+        
+        PutByIdStatus result;
+        result.m_state = Simple;
+        
+        for (unsigned i = 0; i &lt; list-&gt;size(); ++i) {
+            const PutByIdAccess&amp; access = list-&gt;at(i);
+            
+            switch (access.type()) {
+            case PutByIdAccess::Replace: {
+                Structure* structure = access.structure();
+                PropertyOffset offset = structure-&gt;getConcurrently(*profiledBlock-&gt;vm(), uid);
+                if (!isValidOffset(offset))
+                    return PutByIdStatus(TakesSlowPath);
+                result.m_variants.append(PutByIdVariant::replace(structure, offset));
+                break;
+            }
+                
+            case PutByIdAccess::Transition: {
+                PropertyOffset offset =
+                    access.newStructure()-&gt;getConcurrently(*profiledBlock-&gt;vm(), uid);
+                if (!isValidOffset(offset))
+                    return PutByIdStatus(TakesSlowPath);
+                result.m_variants.append(PutByIdVariant::transition(
+                    access.oldStructure(), access.newStructure(),
+                    access.chain() ? adoptRef(new IntendedStructureChain(
+                        profiledBlock, access.oldStructure(), access.chain())) : 0,
+                    offset));
+                break;
+            }
+
+            default:
+                return PutByIdStatus(TakesSlowPath);
+            }
+        }
+        
+        return result;
+    }
+        
</ins><span class="cx">     default:
</span><del>-        // FIXME: We should handle polymorphic PutById. We probably have some interesting things
-        // we could do about it.
-        return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
</del><ins>+        return PutByIdStatus(TakesSlowPath);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="lines">@@ -223,7 +259,7 @@
</span><span class="cx">             // the specialized slot.
</span><span class="cx">             return PutByIdStatus(TakesSlowPath);
</span><span class="cx">         }
</span><del>-        return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
</del><ins>+        return PutByIdVariant::replace(structure, offset);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     // Our hypothesis is that we're doing a transition. Before we prove that this is really
</span><span class="lines">@@ -276,8 +312,27 @@
</span><span class="cx">     ASSERT(!transition-&gt;transitionDidInvolveSpecificValue());
</span><span class="cx">     ASSERT(isValidOffset(offset));
</span><span class="cx">     
</span><del>-    return PutByIdStatus(SimpleTransition, structure, transition, chain.release(), offset);
</del><ins>+    return PutByIdVariant::transition(structure, transition, chain.release(), offset);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PutByIdStatus::dump(PrintStream&amp; out) const
+{
+    switch (m_state) {
+    case NoInformation:
+        out.print(&quot;(NoInformation)&quot;);
+        return;
+        
+    case Simple:
+        out.print(&quot;(&quot;, listDump(m_variants), &quot;)&quot;);
+        return;
+        
+    case TakesSlowPath:
+        out.print(&quot;(TakesSlowPath)&quot;);
+        return;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePutByIdStatush"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -27,8 +27,7 @@
</span><span class="cx"> #define PutByIdStatus_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ExitingJITType.h&quot;
</span><del>-#include &quot;IntendedStructureChain.h&quot;
-#include &quot;PropertyOffset.h&quot;
</del><ins>+#include &quot;PutByIdVariant.h&quot;
</ins><span class="cx"> #include &quot;StructureStubInfo.h&quot;
</span><span class="cx"> #include &lt;wtf/text/StringImpl.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -45,51 +44,27 @@
</span><span class="cx">     enum State {
</span><span class="cx">         // It's uncached so we have no information.
</span><span class="cx">         NoInformation,
</span><del>-        // It's cached as a direct store into an object property for cases where the object
-        // already has the property.
-        SimpleReplace,
-        // It's cached as a transition from one structure that lacks the property to one that
-        // includes the property, and a direct store to this new property.
-        SimpleTransition,
</del><ins>+        // It's cached as a simple store of some kind.
+        Simple,
</ins><span class="cx">         // It's known to often take slow path.
</span><span class="cx">         TakesSlowPath
</span><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     PutByIdStatus()
</span><span class="cx">         : m_state(NoInformation)
</span><del>-        , m_oldStructure(0)
-        , m_newStructure(0)
-        , m_structureChain(0)
-        , m_offset(invalidOffset)
</del><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     explicit PutByIdStatus(State state)
</span><span class="cx">         : m_state(state)
</span><del>-        , m_oldStructure(0)
-        , m_newStructure(0)
-        , m_structureChain(0)
-        , m_offset(invalidOffset)
</del><span class="cx">     {
</span><span class="cx">         ASSERT(m_state == NoInformation || m_state == TakesSlowPath);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    PutByIdStatus(
-        State state,
-        Structure* oldStructure,
-        Structure* newStructure,
-        PassRefPtr&lt;IntendedStructureChain&gt; structureChain,
-        PropertyOffset offset)
-        : m_state(state)
-        , m_oldStructure(oldStructure)
-        , m_newStructure(newStructure)
-        , m_structureChain(structureChain)
-        , m_offset(offset)
</del><ins>+    PutByIdStatus(const PutByIdVariant&amp; variant)
+        : m_state(Simple)
</ins><span class="cx">     {
</span><del>-        ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == !m_oldStructure);
-        ASSERT((m_state != SimpleTransition) == !m_newStructure);
-        ASSERT(!((m_state != SimpleTransition) &amp;&amp; m_structureChain));
-        ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == (m_offset == invalidOffset));
</del><ins>+        m_variants.append(variant);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&amp;, unsigned bytecodeIndex, StringImpl* uid);
</span><span class="lines">@@ -101,15 +76,16 @@
</span><span class="cx">     
</span><span class="cx">     bool isSet() const { return m_state != NoInformation; }
</span><span class="cx">     bool operator!() const { return m_state == NoInformation; }
</span><del>-    bool isSimpleReplace() const { return m_state == SimpleReplace; }
-    bool isSimpleTransition() const { return m_state == SimpleTransition; }
</del><ins>+    bool isSimple() const { return m_state == Simple; }
</ins><span class="cx">     bool takesSlowPath() const { return m_state == TakesSlowPath; }
</span><span class="cx">     
</span><del>-    Structure* oldStructure() const { return m_oldStructure; }
-    Structure* newStructure() const { return m_newStructure; }
-    IntendedStructureChain* structureChain() const { return m_structureChain.get(); }
-    PropertyOffset offset() const { return m_offset; }
</del><ins>+    size_t numVariants() const { return m_variants.size(); }
+    const Vector&lt;PutByIdVariant, 1&gt;&amp; variants() const { return m_variants; }
+    const PutByIdVariant&amp; at(size_t index) const { return m_variants[index]; }
+    const PutByIdVariant&amp; operator[](size_t index) const { return at(index); }
</ins><span class="cx">     
</span><ins>+    void dump(PrintStream&amp;) const;
+    
</ins><span class="cx"> private:
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     static bool hasExitSite(const ConcurrentJITLocker&amp;, CodeBlock*, unsigned bytecodeIndex, ExitingJITType = ExitFromAnything);
</span><span class="lines">@@ -120,10 +96,7 @@
</span><span class="cx">     static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid);
</span><span class="cx">     
</span><span class="cx">     State m_state;
</span><del>-    Structure* m_oldStructure;
-    Structure* m_newStructure;
-    RefPtr&lt;IntendedStructureChain&gt; m_structureChain;
-    PropertyOffset m_offset;
</del><ins>+    Vector&lt;PutByIdVariant, 1&gt; m_variants;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePutByIdVariantcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;PutByIdVariant.h&quot;
+
+namespace JSC {
+
+void PutByIdVariant::dump(PrintStream&amp; out) const
+{
+    dumpInContext(out, 0);
+}
+
+void PutByIdVariant::dumpInContext(PrintStream&amp; out, DumpContext* context) const
+{
+    switch (kind()) {
+    case NotSet:
+        out.print(&quot;&lt;empty&gt;&quot;);
+        return;
+        
+    case Replace:
+        out.print(
+            &quot;&lt;Replace: &quot;, pointerDumpInContext(structure(), context), &quot;, &quot;, offset(), &quot;&gt;&quot;);
+        return;
+        
+    case Transition:
+        out.print(
+            &quot;&lt;Transition: &quot;, pointerDumpInContext(oldStructure(), context), &quot; -&gt; &quot;,
+            pointerDumpInContext(newStructure(), context), &quot;, &quot;,
+            pointerDumpInContext(structureChain(), context), &quot;, &quot;, offset(), &quot;&gt;&quot;);
+        return;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodePutByIdVarianth"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.h (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,121 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef PutByIdVariant_h
+#define PutByIdVariant_h
+
+#include &quot;IntendedStructureChain.h&quot;
+#include &quot;PropertyOffset.h&quot;
+
+namespace JSC {
+
+class PutByIdVariant {
+public:
+    enum Kind {
+        NotSet,
+        Replace,
+        Transition
+    };
+    
+    PutByIdVariant()
+        : m_kind(NotSet)
+        , m_oldStructure(0)
+        , m_newStructure(0)
+        , m_offset(invalidOffset)
+    {
+    }
+    
+    static PutByIdVariant replace(Structure* structure, PropertyOffset offset)
+    {
+        PutByIdVariant result;
+        result.m_kind = Replace;
+        result.m_oldStructure = structure;
+        result.m_offset = offset;
+        return result;
+    }
+    
+    static PutByIdVariant transition(
+        Structure* oldStructure, Structure* newStructure,
+        PassRefPtr&lt;IntendedStructureChain&gt; structureChain, PropertyOffset offset)
+    {
+        PutByIdVariant result;
+        result.m_kind = Transition;
+        result.m_oldStructure = oldStructure;
+        result.m_newStructure = newStructure;
+        result.m_structureChain = structureChain;
+        result.m_offset = offset;
+        return result;
+    }
+    
+    Kind kind() const { return m_kind; }
+    
+    bool isSet() const { return kind() != NotSet; }
+    bool operator!() const { return !isSet(); }
+    
+    Structure* structure() const
+    {
+        ASSERT(kind() == Replace);
+        return m_oldStructure;
+    }
+    
+    Structure* oldStructure() const
+    {
+        ASSERT(kind() == Transition || kind() == Replace);
+        return m_oldStructure;
+    }
+    
+    Structure* newStructure() const
+    {
+        ASSERT(kind() == Transition);
+        return m_newStructure;
+    }
+    
+    IntendedStructureChain* structureChain() const
+    {
+        ASSERT(kind() == Transition);
+        return m_structureChain.get();
+    }
+    
+    PropertyOffset offset() const
+    {
+        ASSERT(isSet());
+        return m_offset;
+    }
+    
+    void dump(PrintStream&amp;) const;
+    void dumpInContext(PrintStream&amp;, DumpContext*) const;
+
+private:
+    Kind m_kind;
+    Structure* m_oldStructure;
+    Structure* m_newStructure;
+    RefPtr&lt;IntendedStructureChain&gt; m_structureChain;
+    PropertyOffset m_offset;
+};
+
+} // namespace JSC
+
+#endif // PutByIdVariant_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -1640,7 +1640,7 @@
</span><span class="cx">         for (unsigned i = node-&gt;multiGetByOffsetData().variants.size(); i--;)
</span><span class="cx">             set.addAll(node-&gt;multiGetByOffsetData().variants[i].structureSet());
</span><span class="cx">         
</span><del>-        filter(value, set);
</del><ins>+        filter(node-&gt;child1(), set);
</ins><span class="cx">         forNode(node).makeHeapTop();
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -1648,7 +1648,60 @@
</span><span class="cx">     case PutByOffset: {
</span><span class="cx">         break;
</span><span class="cx">     }
</span><del>-            
</del><ins>+        
+    case MultiPutByOffset: {
+        AbstractValue&amp; value = forNode(node-&gt;child1());
+        ASSERT(!(value.m_type &amp; ~SpecCell)); // Edge filtering should have already ensured this.
+
+        if (Structure* structure = value.bestProvenStructure()) {
+            bool done = false;
+            for (unsigned i = node-&gt;multiPutByOffsetData().variants.size(); i--;) {
+                const PutByIdVariant&amp; variant = node-&gt;multiPutByOffsetData().variants[i];
+                if (variant.oldStructure() != structure)
+                    continue;
+                
+                if (variant.kind() == PutByIdVariant::Replace) {
+                    filter(node-&gt;child1(), structure);
+                    m_state.setFoundConstants(true);
+                    m_state.setHaveStructures(true);
+                    done = true;
+                    break;
+                }
+                
+                ASSERT(variant.kind() == PutByIdVariant::Transition);
+                clobberStructures(clobberLimit);
+                forNode(node-&gt;child1()).set(m_graph, variant.newStructure());
+                m_state.setFoundConstants(true);
+                m_state.setHaveStructures(true);
+                done = true;
+                break;
+            }
+            if (done)
+                break;
+        }
+        
+        clobberStructures(clobberLimit);
+        
+        StructureSet newSet;
+        for (unsigned i = node-&gt;multiPutByOffsetData().variants.size(); i--;) {
+            const PutByIdVariant&amp; variant = node-&gt;multiPutByOffsetData().variants[i];
+            if (variant.kind() == PutByIdVariant::Replace) {
+                if (value.m_currentKnownStructure.contains(variant.structure()))
+                    newSet.addAll(variant.structure());
+                continue;
+            }
+            ASSERT(variant.kind() == PutByIdVariant::Transition);
+            if (value.m_currentKnownStructure.contains(variant.oldStructure()))
+                newSet.addAll(variant.newStructure());
+        }
+        
+        // Use filter(value, set) as a way of setting the structure set. This works because
+        // we would have already made the set be TOP before this. Filtering top is another 
+        // way of setting.
+        filter(node-&gt;child1(), newSet);
+        break;
+    }
+    
</ins><span class="cx">     case CheckFunction: {
</span><span class="cx">         JSValue value = forNode(node-&gt;child1()).value();
</span><span class="cx">         if (value == node-&gt;function()) {
</span><span class="lines">@@ -1685,19 +1738,21 @@
</span><span class="cx">                 structure,
</span><span class="cx">                 m_graph.identifiers()[node-&gt;identifierNumber()],
</span><span class="cx">                 node-&gt;op() == PutByIdDirect);
</span><del>-            if (status.isSimpleReplace()) {
-                filter(node-&gt;child1(), structure);
-                m_state.setFoundConstants(true);
-                m_state.setHaveStructures(true);
-                break;
</del><ins>+            if (status.isSimple() &amp;&amp; status.numVariants() == 1) {
+                if (status[0].kind() == PutByIdVariant::Replace) {
+                    filter(node-&gt;child1(), structure);
+                    m_state.setFoundConstants(true);
+                    m_state.setHaveStructures(true);
+                    break;
+                }
+                if (status[0].kind() == PutByIdVariant::Transition) {
+                    clobberStructures(clobberLimit);
+                    forNode(node-&gt;child1()).set(m_graph, status[0].newStructure());
+                    m_state.setHaveStructures(true);
+                    m_state.setFoundConstants(true);
+                    break;
+                }
</ins><span class="cx">             }
</span><del>-            if (status.isSimpleTransition()) {
-                clobberStructures(clobberLimit);
-                forNode(node-&gt;child1()).set(m_graph, status.newStructure());
-                m_state.setHaveStructures(true);
-                m_state.setFoundConstants(true);
-                break;
-            }
</del><span class="cx">         }
</span><span class="cx">         clobberWorld(node-&gt;origin.semantic, clobberLimit);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -179,7 +179,12 @@
</span><span class="cx">     void handleGetById(
</span><span class="cx">         int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber,
</span><span class="cx">         const GetByIdStatus&amp;);
</span><del>-    Node* emitPrototypeChecks(const GetByIdVariant&amp;);
</del><ins>+    void emitPutById(
+        Node* base, unsigned identifierNumber, Node* value, bool isDirect);
+    void handlePutById(
+        Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&amp;,
+        bool isDirect);
+    Node* emitPrototypeChecks(Structure*, IntendedStructureChain*);
</ins><span class="cx"> 
</span><span class="cx">     Node* getScope(bool skipTop, unsigned skipCount);
</span><span class="cx">     
</span><span class="lines">@@ -1844,15 +1849,16 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Node* ByteCodeParser::emitPrototypeChecks(const GetByIdVariant&amp; variant)
</del><ins>+Node* ByteCodeParser::emitPrototypeChecks(
+    Structure* structure, IntendedStructureChain* chain)
</ins><span class="cx"> {
</span><span class="cx">     Node* base = 0;
</span><del>-    m_graph.chains().addLazily(variant.chain());
-    Structure* currentStructure = variant.structureSet().singletonStructure();
</del><ins>+    m_graph.chains().addLazily(chain);
+    Structure* currentStructure = structure;
</ins><span class="cx">     JSObject* currentObject = 0;
</span><del>-    for (unsigned i = 0; i &lt; variant.chain()-&gt;size(); ++i) {
</del><ins>+    for (unsigned i = 0; i &lt; chain-&gt;size(); ++i) {
</ins><span class="cx">         currentObject = asObject(currentStructure-&gt;prototypeForLookup(m_inlineStackTop-&gt;m_codeBlock));
</span><del>-        currentStructure = variant.chain()-&gt;at(i);
</del><ins>+        currentStructure = chain-&gt;at(i);
</ins><span class="cx">         base = cellConstantWithStructureCheck(currentObject, currentStructure);
</span><span class="cx">     }
</span><span class="cx">     RELEASE_ASSERT(base);
</span><span class="lines">@@ -1878,12 +1884,18 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><ins>+        if (m_graph.compilation())
+            m_graph.compilation()-&gt;noticeInlinedGetById();
+    
</ins><span class="cx">         // 1) Emit prototype structure checks for all chains. This could sort of maybe not be
</span><span class="cx">         //    optimal, if there is some rarely executed case in the chain that requires a lot
</span><span class="cx">         //    of checks and those checks are not watchpointable.
</span><span class="cx">         for (unsigned variantIndex = getByIdStatus.numVariants(); variantIndex--;) {
</span><del>-            if (getByIdStatus[variantIndex].chain())
-                emitPrototypeChecks(getByIdStatus[variantIndex]);
</del><ins>+            if (getByIdStatus[variantIndex].chain()) {
+                emitPrototypeChecks(
+                    getByIdStatus[variantIndex].structureSet().singletonStructure(),
+                    getByIdStatus[variantIndex].chain());
+            }
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // 2) Emit a MultiGetByOffset
</span><span class="lines">@@ -1905,8 +1917,10 @@
</span><span class="cx">                 
</span><span class="cx">     addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base);
</span><span class="cx">     
</span><del>-    if (variant.chain())
-        base = emitPrototypeChecks(variant);
</del><ins>+    if (variant.chain()) {
+        base = emitPrototypeChecks(
+            variant.structureSet().singletonStructure(), variant.chain());
+    }
</ins><span class="cx">     
</span><span class="cx">     // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to
</span><span class="cx">     // ensure that the base of the original get_by_id is kept alive until we're done with
</span><span class="lines">@@ -1928,6 +1942,123 @@
</span><span class="cx">         destinationOperand, prediction, base, identifierNumber, variant.offset());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ByteCodeParser::emitPutById(
+    Node* base, unsigned identifierNumber, Node* value, bool isDirect)
+{
+    if (isDirect)
+        addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value);
+    else
+        addToGraph(PutById, OpInfo(identifierNumber), base, value);
+}
+
+void ByteCodeParser::handlePutById(
+    Node* base, unsigned identifierNumber, Node* value,
+    const PutByIdStatus&amp; putByIdStatus, bool isDirect)
+{
+    if (!putByIdStatus.isSimple()) {
+        if (!putByIdStatus.isSet())
+            addToGraph(ForceOSRExit);
+        emitPutById(base, identifierNumber, value, isDirect);
+        return;
+    }
+    
+    if (putByIdStatus.numVariants() &gt; 1) {
+        if (!isFTL(m_graph.m_plan.mode)) {
+            emitPutById(base, identifierNumber, value, isDirect);
+            return;
+        }
+        
+        if (m_graph.compilation())
+            m_graph.compilation()-&gt;noticeInlinedPutById();
+        
+        if (!isDirect) {
+            for (unsigned variantIndex = putByIdStatus.numVariants(); variantIndex--;) {
+                if (putByIdStatus[variantIndex].kind() != PutByIdVariant::Transition)
+                    continue;
+                if (!putByIdStatus[variantIndex].structureChain())
+                    continue;
+                emitPrototypeChecks(
+                    putByIdStatus[variantIndex].oldStructure(),
+                    putByIdStatus[variantIndex].structureChain());
+            }
+        }
+        
+        MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add();
+        data-&gt;variants = putByIdStatus.variants();
+        data-&gt;identifierNumber = identifierNumber;
+        addToGraph(MultiPutByOffset, OpInfo(data), base, value);
+        return;
+    }
+    
+    ASSERT(putByIdStatus.numVariants() == 1);
+    const PutByIdVariant&amp; variant = putByIdStatus[0];
+    
+    if (variant.kind() == PutByIdVariant::Replace) {
+        addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structure())), base);
+        handlePutByOffset(base, identifierNumber, variant.offset(), value);
+        if (m_graph.compilation())
+            m_graph.compilation()-&gt;noticeInlinedPutById();
+        return;
+    }
+    
+    ASSERT(variant.kind() == PutByIdVariant::Transition);
+    if (variant.structureChain() &amp;&amp; !variant.structureChain()-&gt;isStillValid()) {
+        emitPutById(base, identifierNumber, value, isDirect);
+        return;
+    }
+    
+    m_graph.chains().addLazily(variant.structureChain());
+                
+    addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base);
+    if (!isDirect)
+        emitPrototypeChecks(variant.oldStructure(), variant.structureChain());
+
+    ASSERT(variant.oldStructure()-&gt;transitionWatchpointSetHasBeenInvalidated());
+    
+    Node* propertyStorage;
+    StructureTransitionData* transitionData = m_graph.addStructureTransitionData(
+        StructureTransitionData(variant.oldStructure(), variant.newStructure()));
+
+    if (variant.oldStructure()-&gt;outOfLineCapacity()
+        != variant.newStructure()-&gt;outOfLineCapacity()) {
+
+        // If we're growing the property storage then it must be because we're
+        // storing into the out-of-line storage.
+        ASSERT(!isInlineOffset(variant.offset()));
+
+        if (!variant.oldStructure()-&gt;outOfLineCapacity()) {
+            propertyStorage = addToGraph(
+                AllocatePropertyStorage, OpInfo(transitionData), base);
+        } else {
+            propertyStorage = addToGraph(
+                ReallocatePropertyStorage, OpInfo(transitionData),
+                base, addToGraph(GetButterfly, base));
+        }
+    } else {
+        if (isInlineOffset(variant.offset()))
+            propertyStorage = base;
+        else
+            propertyStorage = addToGraph(GetButterfly, base);
+    }
+
+    addToGraph(PutStructure, OpInfo(transitionData), base);
+
+    addToGraph(
+        PutByOffset,
+        OpInfo(m_graph.m_storageAccessData.size()),
+        propertyStorage,
+        base,
+        value);
+
+    StorageAccessData storageAccessData;
+    storageAccessData.offset = variant.offset();
+    storageAccessData.identifierNumber = identifierNumber;
+    m_graph.m_storageAccessData.append(storageAccessData);
+
+    if (m_graph.compilation())
+        m_graph.compilation()-&gt;noticeInlinedPutById();
+}
+
</ins><span class="cx"> void ByteCodeParser::prepareToParseBlock()
</span><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; i &lt; m_constants.size(); ++i)
</span><span class="lines">@@ -2590,91 +2721,8 @@
</span><span class="cx">                 m_inlineStackTop-&gt;m_profiledBlock, m_dfgCodeBlock,
</span><span class="cx">                 m_inlineStackTop-&gt;m_stubInfos, m_dfgStubInfos,
</span><span class="cx">                 currentCodeOrigin(), m_graph.identifiers()[identifierNumber]);
</span><del>-            bool canCountAsInlined = true;
-            if (!putByIdStatus.isSet()) {
-                addToGraph(ForceOSRExit);
-                canCountAsInlined = false;
-            }
</del><span class="cx">             
</span><del>-            if (putByIdStatus.isSimpleReplace()) {
-                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
-                handlePutByOffset(base, identifierNumber, putByIdStatus.offset(), value);
-            } else if (
-                putByIdStatus.isSimpleTransition()
-                &amp;&amp; (!putByIdStatus.structureChain()
-                    || putByIdStatus.structureChain()-&gt;isStillValid())) {
-                
-                m_graph.chains().addLazily(putByIdStatus.structureChain());
-                
-                addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
-                if (!direct) {
-                    if (!putByIdStatus.oldStructure()-&gt;storedPrototype().isNull()) {
-                        cellConstantWithStructureCheck(
-                            putByIdStatus.oldStructure()-&gt;storedPrototype().asCell());
-                    }
-                    
-                    for (unsigned i = 0; i &lt; putByIdStatus.structureChain()-&gt;size(); ++i) {
-                        JSValue prototype = putByIdStatus.structureChain()-&gt;at(i)-&gt;storedPrototype();
-                        if (prototype.isNull())
-                            continue;
-                        cellConstantWithStructureCheck(prototype.asCell());
-                    }
-                }
-                ASSERT(putByIdStatus.oldStructure()-&gt;transitionWatchpointSetHasBeenInvalidated());
-                
-                Node* propertyStorage;
-                StructureTransitionData* transitionData =
-                    m_graph.addStructureTransitionData(
-                        StructureTransitionData(
-                            putByIdStatus.oldStructure(),
-                            putByIdStatus.newStructure()));
-
-                if (putByIdStatus.oldStructure()-&gt;outOfLineCapacity()
-                    != putByIdStatus.newStructure()-&gt;outOfLineCapacity()) {
-                    
-                    // If we're growing the property storage then it must be because we're
-                    // storing into the out-of-line storage.
-                    ASSERT(!isInlineOffset(putByIdStatus.offset()));
-                    
-                    if (!putByIdStatus.oldStructure()-&gt;outOfLineCapacity()) {
-                        propertyStorage = addToGraph(
-                            AllocatePropertyStorage, OpInfo(transitionData), base);
-                    } else {
-                        propertyStorage = addToGraph(
-                            ReallocatePropertyStorage, OpInfo(transitionData),
-                            base, addToGraph(GetButterfly, base));
-                    }
-                } else {
-                    if (isInlineOffset(putByIdStatus.offset()))
-                        propertyStorage = base;
-                    else
-                        propertyStorage = addToGraph(GetButterfly, base);
-                }
-                
-                addToGraph(PutStructure, OpInfo(transitionData), base);
-                
-                addToGraph(
-                    PutByOffset,
-                    OpInfo(m_graph.m_storageAccessData.size()),
-                    propertyStorage,
-                    base,
-                    value);
-                
-                StorageAccessData storageAccessData;
-                storageAccessData.offset = putByIdStatus.offset();
-                storageAccessData.identifierNumber = identifierNumber;
-                m_graph.m_storageAccessData.append(storageAccessData);
-            } else {
-                if (direct)
-                    addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value);
-                else
-                    addToGraph(PutById, OpInfo(identifierNumber), base, value);
-                canCountAsInlined = false;
-            }
-            
-            if (canCountAsInlined &amp;&amp; m_graph.compilation())
-                m_graph.compilation()-&gt;noticeInlinedPutById();
-
</del><ins>+            handlePutById(base, identifierNumber, value, putByIdStatus, direct);
</ins><span class="cx">             NEXT_OPCODE(op_put_by_id);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3269,11 +3317,11 @@
</span><span class="cx">             case GlobalProperty:
</span><span class="cx">             case GlobalPropertyWithVarInjectionChecks: {
</span><span class="cx">                 PutByIdStatus status = PutByIdStatus::computeFor(*m_vm, globalObject, structure, uid, false);
</span><del>-                if (!status.isSimpleReplace()) {
</del><ins>+                if (status.numVariants() != 1 || status[0].kind() != PutByIdVariant::Replace) {
</ins><span class="cx">                     addToGraph(PutById, OpInfo(identifierNumber), get(VirtualRegister(scope)), get(VirtualRegister(value)));
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><del>-                Node* base = cellConstantWithStructureCheck(globalObject, status.oldStructure());
</del><ins>+                Node* base = cellConstantWithStructureCheck(globalObject, status[0].structure());
</ins><span class="cx">                 addToGraph(Phantom, get(VirtualRegister(scope)));
</span><span class="cx">                 handlePutByOffset(base, identifierNumber, static_cast&lt;PropertyOffset&gt;(operand), get(VirtualRegister(value)));
</span><span class="cx">                 // Keep scope alive until after put.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCSEPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -495,7 +495,12 @@
</span><span class="cx">             case PutByOffset:
</span><span class="cx">                 // Setting a property cannot change the structure.
</span><span class="cx">                 break;
</span><del>-                    
</del><ins>+                
+            case MultiPutByOffset:
+                if (node-&gt;multiPutByOffsetData().writesStructures())
+                    return false;
+                break;
+                
</ins><span class="cx">             case PutByValDirect:
</span><span class="cx">             case PutByVal:
</span><span class="cx">             case PutByValAlias:
</span><span class="lines">@@ -544,6 +549,11 @@
</span><span class="cx">                 // Setting a property cannot change the structure.
</span><span class="cx">                 break;
</span><span class="cx">                     
</span><ins>+            case MultiPutByOffset:
+                if (node-&gt;multiPutByOffsetData().writesStructures())
+                    return false;
+                break;
+                
</ins><span class="cx">             case PutByValDirect:
</span><span class="cx">             case PutByVal:
</span><span class="cx">             case PutByValAlias:
</span><span class="lines">@@ -617,6 +627,7 @@
</span><span class="cx">             case NewStringObject:
</span><span class="cx">             case MakeRope:
</span><span class="cx">             case NewTypedArray:
</span><ins>+            case MultiPutByOffset:
</ins><span class="cx">                 return 0;
</span><span class="cx">                 
</span><span class="cx">             // This either exits, causes a GC (lazy string allocation), or clobbers
</span><span class="lines">@@ -668,6 +679,14 @@
</span><span class="cx">                     return 0;
</span><span class="cx">                 }
</span><span class="cx">                 break;
</span><ins>+                
+            case MultiPutByOffset:
+                if (node-&gt;multiPutByOffsetData().identifierNumber == identifierNumber) {
+                    if (node-&gt;child1() == base)
+                        return node-&gt;child2().node();
+                    return 0;
+                }
+                break;
</ins><span class="cx">                     
</span><span class="cx">             case PutByValDirect:
</span><span class="cx">             case PutByVal:
</span><span class="lines">@@ -709,7 +728,12 @@
</span><span class="cx">                     return 0;
</span><span class="cx">                 }
</span><span class="cx">                 break;
</span><del>-                    
</del><ins>+                
+            case MultiPutByOffset:
+                if (node-&gt;multiPutByOffsetData().identifierNumber == identifierNumber)
+                    return 0;
+                break;
+                
</ins><span class="cx">             case PutByValDirect:
</span><span class="cx">             case PutByVal:
</span><span class="cx">             case PutByValAlias:
</span><span class="lines">@@ -774,6 +798,11 @@
</span><span class="cx">                 // But that seems like it would take Effort.
</span><span class="cx">                 return 0;
</span><span class="cx">                 
</span><ins>+            case MultiPutByOffset:
+                //if (node-&gt;multiPutByOffsetData().reallocatesStorage())
+                //    return 0;
+                break;
+                
</ins><span class="cx">             default:
</span><span class="cx">                 if (m_graph.clobbersWorld(node))
</span><span class="cx">                     return 0;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -469,9 +469,23 @@
</span><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case MultiGetByOffset:
</span><ins>+        read(JSCell_structure);
+        read(JSObject_butterfly);
</ins><span class="cx">         read(AbstractHeap(NamedProperties, node-&gt;multiGetByOffsetData().identifierNumber));
</span><span class="cx">         return;
</span><span class="cx">         
</span><ins>+    case MultiPutByOffset:
+        read(JSCell_structure);
+        read(JSObject_butterfly);
+        write(AbstractHeap(NamedProperties, node-&gt;multiPutByOffsetData().identifierNumber));
+        if (node-&gt;multiPutByOffsetData().writesStructures())
+            write(JSCell_structure);
+        if (node-&gt;multiPutByOffsetData().reallocatesStorage()) {
+            write(JSObject_butterfly);
+            clobberizeForAllocation(read, write);
+        }
+        return;
+        
</ins><span class="cx">     case PutByOffset:
</span><span class="cx">         write(AbstractHeap(NamedProperties, graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber));
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -174,6 +174,27 @@
</span><span class="cx">                 }
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+                
+            case MultiPutByOffset: {
+                Edge childEdge = node-&gt;child1();
+                Node* child = childEdge.node();
+                MultiPutByOffsetData&amp; data = node-&gt;multiPutByOffsetData();
+
+                Structure* structure = m_state.forNode(child).bestProvenStructure();
+                if (!structure)
+                    break;
+                
+                for (unsigned i = data.variants.size(); i--;) {
+                    const PutByIdVariant&amp; variant = data.variants[i];
+                    if (variant.oldStructure() != structure)
+                        continue;
+                    
+                    emitPutByOffset(indexInBlock, node, structure, variant, data.identifierNumber);
+                    eliminated = true;
+                    break;
+                }
+                break;
+            }
</ins><span class="cx">         
</span><span class="cx">             case GetById:
</span><span class="cx">             case GetByIdFlush: {
</span><span class="lines">@@ -187,7 +208,7 @@
</span><span class="cx">                 Structure* structure = m_state.forNode(child).bestProvenStructure();
</span><span class="cx">                 if (!structure)
</span><span class="cx">                     break;
</span><del>-                
</del><ins>+
</ins><span class="cx">                 GetByIdStatus status = GetByIdStatus::computeFor(
</span><span class="cx">                     vm(), structure, m_graph.identifiers()[identifierNumber]);
</span><span class="cx">                 
</span><span class="lines">@@ -215,9 +236,6 @@
</span><span class="cx">                 if (!structure)
</span><span class="cx">                     break;
</span><span class="cx">                 
</span><del>-                bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
-                bool needsCellCheck = m_state.forNode(child).m_type &amp; ~SpecCell;
-                
</del><span class="cx">                 PutByIdStatus status = PutByIdStatus::computeFor(
</span><span class="cx">                     vm(),
</span><span class="cx">                     m_graph.globalObjectFor(origin.semantic),
</span><span class="lines">@@ -225,96 +243,13 @@
</span><span class="cx">                     m_graph.identifiers()[identifierNumber],
</span><span class="cx">                     node-&gt;op() == PutByIdDirect);
</span><span class="cx">                 
</span><del>-                if (!status.isSimpleReplace() &amp;&amp; !status.isSimpleTransition())
</del><ins>+                if (!status.isSimple())
</ins><span class="cx">                     break;
</span><ins>+                if (status.numVariants() != 1)
+                    break;
</ins><span class="cx">                 
</span><del>-                ASSERT(status.oldStructure() == structure);
-                
-                // 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>+                emitPutByOffset(indexInBlock, node, structure, status[0], identifierNumber);
</ins><span class="cx">                 eliminated = true;
</span><del>-                
-                if (needsWatchpoint) {
-                    m_insertionSet.insertNode(
-                        indexInBlock, SpecNone, StructureTransitionWatchpoint, origin,
-                        OpInfo(structure), childEdge);
-                } else if (needsCellCheck) {
-                    m_insertionSet.insertNode(
-                        indexInBlock, SpecNone, Phantom, origin, childEdge);
-                }
-                
-                childEdge.setUseKind(KnownCellUse);
-                
-                StructureTransitionData* transitionData = 0;
-                if (status.isSimpleTransition()) {
-                    transitionData = m_graph.addStructureTransitionData(
-                        StructureTransitionData(structure, status.newStructure()));
-                    
-                    if (node-&gt;op() == PutById) {
-                        if (!structure-&gt;storedPrototype().isNull()) {
-                            addStructureTransitionCheck(
-                                origin, indexInBlock,
-                                structure-&gt;storedPrototype().asCell());
-                        }
-                        
-                        m_graph.chains().addLazily(status.structureChain());
-                        
-                        for (unsigned i = 0; i &lt; status.structureChain()-&gt;size(); ++i) {
-                            JSValue prototype = status.structureChain()-&gt;at(i)-&gt;storedPrototype();
-                            if (prototype.isNull())
-                                continue;
-                            ASSERT(prototype.isCell());
-                            addStructureTransitionCheck(
-                                origin, indexInBlock, prototype.asCell());
-                        }
-                    }
-                }
-                
-                Edge propertyStorage;
-                
-                if (isInlineOffset(status.offset()))
-                    propertyStorage = childEdge;
-                else if (status.isSimpleReplace() || structure-&gt;outOfLineCapacity() == status.newStructure()-&gt;outOfLineCapacity()) {
-                    propertyStorage = Edge(m_insertionSet.insertNode(
-                        indexInBlock, SpecNone, GetButterfly, origin, childEdge));
-                } else if (!structure-&gt;outOfLineCapacity()) {
-                    ASSERT(status.newStructure()-&gt;outOfLineCapacity());
-                    ASSERT(!isInlineOffset(status.offset()));
-                    Node* allocatePropertyStorage = m_insertionSet.insertNode(
-                        indexInBlock, SpecNone, AllocatePropertyStorage,
-                        origin, OpInfo(transitionData), childEdge);
-                    m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
-                    propertyStorage = Edge(allocatePropertyStorage);
-                } else {
-                    ASSERT(structure-&gt;outOfLineCapacity());
-                    ASSERT(status.newStructure()-&gt;outOfLineCapacity() &gt; structure-&gt;outOfLineCapacity());
-                    ASSERT(!isInlineOffset(status.offset()));
-                    
-                    Node* reallocatePropertyStorage = m_insertionSet.insertNode(
-                        indexInBlock, SpecNone, ReallocatePropertyStorage, origin,
-                        OpInfo(transitionData), childEdge,
-                        Edge(m_insertionSet.insertNode(
-                            indexInBlock, SpecNone, GetButterfly, origin, childEdge)));
-                    m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
-                    propertyStorage = Edge(reallocatePropertyStorage);
-                }
-                
-                if (status.isSimpleTransition()) {
-                    Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transitionData), childEdge);
-                    m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
-                    m_insertionSet.insert(indexInBlock, putStructure);
-                }
-
-                node-&gt;convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
-                m_insertionSet.insertNode(indexInBlock, SpecNone, ConditionalStoreBarrier, origin, 
-                    Edge(node-&gt;child2().node(), KnownCellUse), Edge(node-&gt;child3().node(), UntypedUse));
-                
-                StorageAccessData storageAccessData;
-                storageAccessData.offset = status.offset();
-                storageAccessData.identifierNumber = identifierNumber;
-                m_graph.m_storageAccessData.append(storageAccessData);
</del><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -445,6 +380,107 @@
</span><span class="cx">         m_graph.m_storageAccessData.append(storageAccessData);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void emitPutByOffset(unsigned indexInBlock, Node* node, Structure* structure, const PutByIdVariant&amp; variant, unsigned identifierNumber)
+    {
+        NodeOrigin origin = node-&gt;origin;
+        Edge childEdge = node-&gt;child1();
+        Node* child = childEdge.node();
+
+        ASSERT(variant.oldStructure() == structure);
+        
+        bool needsWatchpoint = !m_state.forNode(child).m_currentKnownStructure.hasSingleton();
+        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);
+
+        if (needsWatchpoint) {
+            m_insertionSet.insertNode(
+                indexInBlock, SpecNone, StructureTransitionWatchpoint, origin,
+                OpInfo(structure), childEdge);
+        } else if (needsCellCheck) {
+            m_insertionSet.insertNode(
+                indexInBlock, SpecNone, Phantom, origin, childEdge);
+        }
+
+        childEdge.setUseKind(KnownCellUse);
+
+        StructureTransitionData* transitionData = 0;
+        if (variant.kind() == PutByIdVariant::Transition) {
+            transitionData = m_graph.addStructureTransitionData(
+                StructureTransitionData(structure, variant.newStructure()));
+
+            if (node-&gt;op() == PutById) {
+                if (!structure-&gt;storedPrototype().isNull()) {
+                    addStructureTransitionCheck(
+                        origin, indexInBlock,
+                        structure-&gt;storedPrototype().asCell());
+                }
+
+                m_graph.chains().addLazily(variant.structureChain());
+
+                for (unsigned i = 0; i &lt; variant.structureChain()-&gt;size(); ++i) {
+                    JSValue prototype = variant.structureChain()-&gt;at(i)-&gt;storedPrototype();
+                    if (prototype.isNull())
+                        continue;
+                    ASSERT(prototype.isCell());
+                    addStructureTransitionCheck(
+                        origin, indexInBlock, prototype.asCell());
+                }
+            }
+        }
+
+        Edge propertyStorage;
+
+        if (isInlineOffset(variant.offset()))
+            propertyStorage = childEdge;
+        else if (
+            variant.kind() == PutByIdVariant::Replace
+            || structure-&gt;outOfLineCapacity() == variant.newStructure()-&gt;outOfLineCapacity()) {
+            propertyStorage = Edge(m_insertionSet.insertNode(
+                indexInBlock, SpecNone, GetButterfly, origin, childEdge));
+        } else if (!structure-&gt;outOfLineCapacity()) {
+            ASSERT(variant.newStructure()-&gt;outOfLineCapacity());
+            ASSERT(!isInlineOffset(variant.offset()));
+            Node* allocatePropertyStorage = m_insertionSet.insertNode(
+                indexInBlock, SpecNone, AllocatePropertyStorage,
+                origin, OpInfo(transitionData), childEdge);
+            m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
+            propertyStorage = Edge(allocatePropertyStorage);
+        } else {
+            ASSERT(structure-&gt;outOfLineCapacity());
+            ASSERT(variant.newStructure()-&gt;outOfLineCapacity() &gt; structure-&gt;outOfLineCapacity());
+            ASSERT(!isInlineOffset(variant.offset()));
+
+            Node* reallocatePropertyStorage = m_insertionSet.insertNode(
+                indexInBlock, SpecNone, ReallocatePropertyStorage, origin,
+                OpInfo(transitionData), childEdge,
+                Edge(m_insertionSet.insertNode(
+                    indexInBlock, SpecNone, GetButterfly, origin, childEdge)));
+            m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
+            propertyStorage = Edge(reallocatePropertyStorage);
+        }
+
+        if (variant.kind() == PutByIdVariant::Transition) {
+            Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transitionData), childEdge);
+            m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
+            m_insertionSet.insert(indexInBlock, putStructure);
+        }
+
+        node-&gt;convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
+        m_insertionSet.insertNode(
+            indexInBlock, SpecNone, ConditionalStoreBarrier, origin, 
+            Edge(node-&gt;child2().node(), KnownCellUse),
+            Edge(node-&gt;child3().node(), UntypedUse));
+
+        StorageAccessData storageAccessData;
+        storageAccessData.offset = variant.offset();
+        storageAccessData.identifierNumber = identifierNumber;
+        m_graph.m_storageAccessData.append(storageAccessData);
+    }
+
</ins><span class="cx">     void addStructureTransitionCheck(NodeOrigin origin, unsigned indexInBlock, JSCell* cell)
</span><span class="cx">     {
</span><span class="cx">         Node* weakConstant = m_insertionSet.insertNode(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -891,6 +891,12 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><ins>+        case MultiPutByOffset: {
+            fixEdge&lt;CellUse&gt;(node-&gt;child1());
+            insertStoreBarrier(m_indexInBlock, node-&gt;child1(), node-&gt;child2());
+            break;
+        }
+            
</ins><span class="cx">         case InstanceOf: {
</span><span class="cx">             // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
</span><span class="cx">             // check. https://bugs.webkit.org/show_bug.cgi?id=107479
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -251,6 +251,12 @@
</span><span class="cx">         for (unsigned i = 0; i &lt; data.variants.size(); ++i)
</span><span class="cx">             out.print(comma, inContext(data.variants[i], context));
</span><span class="cx">     }
</span><ins>+    if (node-&gt;hasMultiPutByOffsetData()) {
+        MultiPutByOffsetData&amp; data = node-&gt;multiPutByOffsetData();
+        out.print(comma, &quot;id&quot;, data.identifierNumber, &quot;{&quot;, identifiers()[data.identifierNumber], &quot;}&quot;);
+        for (unsigned i = 0; i &lt; data.variants.size(); ++i)
+            out.print(comma, inContext(data.variants[i], context));
+    }
</ins><span class="cx">     ASSERT(node-&gt;hasVariableAccessData(*this) == node-&gt;hasLocal(*this));
</span><span class="cx">     if (node-&gt;hasVariableAccessData(*this)) {
</span><span class="cx">         VariableAccessData* variableAccessData = node-&gt;tryGetVariableAccessData();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -830,6 +830,7 @@
</span><span class="cx">     Bag&lt;BranchData&gt; m_branchData;
</span><span class="cx">     Bag&lt;SwitchData&gt; m_switchData;
</span><span class="cx">     Bag&lt;MultiGetByOffsetData&gt; m_multiGetByOffsetData;
</span><ins>+    Bag&lt;MultiPutByOffsetData&gt; m_multiPutByOffsetData;
</ins><span class="cx">     Vector&lt;InlineVariableData, 4&gt; m_inlineVariableData;
</span><span class="cx">     OwnPtr&lt;InlineCallFrameSet&gt; m_inlineCallFrames;
</span><span class="cx">     HashMap&lt;CodeBlock*, std::unique_ptr&lt;FullBytecodeLiveness&gt;&gt; m_bytecodeLiveness;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -34,6 +34,30 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><ins>+bool MultiPutByOffsetData::writesStructures() const
+{
+    for (unsigned i = variants.size(); i--;) {
+        if (variants[i].kind() == PutByIdVariant::Transition)
+            return true;
+    }
+    return false;
+}
+
+bool MultiPutByOffsetData::reallocatesStorage() const
+{
+    for (unsigned i = variants.size(); i--;) {
+        if (variants[i].kind() != PutByIdVariant::Transition)
+            continue;
+        
+        if (variants[i].oldStructure()-&gt;outOfLineCapacity() ==
+            variants[i].newStructure()-&gt;outOfLineCapacity())
+            continue;
+        
+        return true;
+    }
+    return false;
+}
+
</ins><span class="cx"> void BranchTarget::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><span class="cx">     if (!block)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> #include &quot;GetByIdVariant.h&quot;
</span><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><span class="cx"> #include &quot;Operands.h&quot;
</span><ins>+#include &quot;PutByIdVariant.h&quot;
</ins><span class="cx"> #include &quot;SpeculatedType.h&quot;
</span><span class="cx"> #include &quot;StructureSet.h&quot;
</span><span class="cx"> #include &quot;ValueProfile.h&quot;
</span><span class="lines">@@ -57,6 +58,14 @@
</span><span class="cx">     Vector&lt;GetByIdVariant, 2&gt; variants;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+struct MultiPutByOffsetData {
+    unsigned identifierNumber;
+    Vector&lt;PutByIdVariant, 2&gt; variants;
+    
+    bool writesStructures() const;
+    bool reallocatesStorage() const;
+};
+
</ins><span class="cx"> struct StructureTransitionData {
</span><span class="cx">     Structure* previousStructure;
</span><span class="cx">     Structure* newStructure;
</span><span class="lines">@@ -460,7 +469,7 @@
</span><span class="cx">     
</span><span class="cx">     void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage)
</span><span class="cx">     {
</span><del>-        ASSERT(m_op == PutById || m_op == PutByIdDirect);
</del><ins>+        ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == MultiPutByOffset);
</ins><span class="cx">         m_opInfo = storageAccessDataIndex;
</span><span class="cx">         children.setChild3(children.child2());
</span><span class="cx">         children.setChild2(children.child1());
</span><span class="lines">@@ -1091,6 +1100,16 @@
</span><span class="cx">         return *reinterpret_cast&lt;MultiGetByOffsetData*&gt;(m_opInfo);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    bool hasMultiPutByOffsetData()
+    {
+        return op() == MultiPutByOffset;
+    }
+    
+    MultiPutByOffsetData&amp; multiPutByOffsetData()
+    {
+        return *reinterpret_cast&lt;MultiPutByOffsetData*&gt;(m_opInfo);
+    }
+    
</ins><span class="cx">     bool hasFunctionDeclIndex()
</span><span class="cx">     {
</span><span class="cx">         return op() == NewFunction
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -175,6 +175,7 @@
</span><span class="cx">     macro(GetByOffset, NodeResultJS) \
</span><span class="cx">     macro(MultiGetByOffset, NodeResultJS) \
</span><span class="cx">     macro(PutByOffset, NodeMustGenerate) \
</span><ins>+    macro(MultiPutByOffset, NodeMustGenerate) \
</ins><span class="cx">     macro(GetArrayLength, NodeResultInt32) \
</span><span class="cx">     macro(GetTypedArrayByteOffset, NodeResultInt32) \
</span><span class="cx">     macro(GetScope, NodeResultJS) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -552,6 +552,7 @@
</span><span class="cx">         case PutById:
</span><span class="cx">         case PutByIdDirect:
</span><span class="cx">         case PutByOffset:
</span><ins>+        case MultiPutByOffset:
</ins><span class="cx">         case DFG::Jump:
</span><span class="cx">         case Branch:
</span><span class="cx">         case Switch:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -252,6 +252,7 @@
</span><span class="cx">     case ConstantStoragePointer:
</span><span class="cx">     case Check:
</span><span class="cx">     case MultiGetByOffset:
</span><ins>+    case MultiPutByOffset:
</ins><span class="cx">         return true;
</span><span class="cx">         
</span><span class="cx">     case GetByVal:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -4689,6 +4689,7 @@
</span><span class="cx">     case CheckInBounds:
</span><span class="cx">     case ArithIMul:
</span><span class="cx">     case MultiGetByOffset:
</span><ins>+    case MultiPutByOffset:
</ins><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -5006,6 +5006,7 @@
</span><span class="cx">     case CheckInBounds:
</span><span class="cx">     case ArithIMul:
</span><span class="cx">     case MultiGetByOffset:
</span><ins>+    case MultiPutByOffset:
</ins><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGTypeCheckHoistingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/dfg/DFGTypeCheckHoistingPhase.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -246,6 +246,7 @@
</span><span class="cx">                 case HardPhantom:
</span><span class="cx">                 case MovHint:
</span><span class="cx">                 case MultiGetByOffset:
</span><ins>+                case MultiPutByOffset:
</ins><span class="cx">                     // Don't count these uses.
</span><span class="cx">                     break;
</span><span class="cx">                     
</span><span class="lines">@@ -346,6 +347,7 @@
</span><span class="cx">                 case HardPhantom:
</span><span class="cx">                 case MovHint:
</span><span class="cx">                 case MultiGetByOffset:
</span><ins>+                case MultiPutByOffset:
</ins><span class="cx">                     // Don't count these uses.
</span><span class="cx">                     break;
</span><span class="cx">                     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -138,6 +138,7 @@
</span><span class="cx">     case GetById:
</span><span class="cx">     case ToThis:
</span><span class="cx">     case MultiGetByOffset:
</span><ins>+    case MultiPutByOffset:
</ins><span class="cx">     case ToPrimitive:
</span><span class="cx">         // These are OK.
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (164619 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-02-25 01:59:17 UTC (rev 164619)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -474,6 +474,9 @@
</span><span class="cx">         case PutByOffset:
</span><span class="cx">             compilePutByOffset();
</span><span class="cx">             break;
</span><ins>+        case MultiPutByOffset:
+            compileMultiPutByOffset();
+            break;
</ins><span class="cx">         case GetGlobalVar:
</span><span class="cx">             compileGetGlobalVar();
</span><span class="cx">             break;
</span><span class="lines">@@ -1656,8 +1659,8 @@
</span><span class="cx">     {
</span><span class="cx">         m_ftlState.jitCode-&gt;common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
</span><span class="cx">         
</span><del>-        m_out.store64(
-            m_out.constIntPtr(m_node-&gt;structureTransitionData().newStructure),
</del><ins>+        m_out.storePtr(
+            weakPointer(m_node-&gt;structureTransitionData().newStructure),
</ins><span class="cx">             lowCell(m_node-&gt;child1()), m_heaps.JSCell_structure);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -2708,105 +2711,22 @@
</span><span class="cx">     void compileAllocatePropertyStorage()
</span><span class="cx">     {
</span><span class="cx">         StructureTransitionData&amp; data = m_node-&gt;structureTransitionData();
</span><del>-        
</del><span class="cx">         LValue object = lowCell(m_node-&gt;child1());
</span><span class="cx">         
</span><del>-        if (data.previousStructure-&gt;couldHaveIndexingHeader()) {
-            setStorage(vmCall(
-                m_out.operation(
-                    operationReallocateButterflyToHavePropertyStorageWithInitialCapacity),
-                m_callFrame, object));
-            return;
-        }
-        
-        LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, (&quot;AllocatePropertyStorage slow path&quot;));
-        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;AllocatePropertyStorage continuation&quot;));
-        
-        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
-        
-        LValue endOfStorage = allocateBasicStorageAndGetEnd(
-            m_out.constIntPtr(initialOutOfLineCapacity * sizeof(JSValue)), slowPath);
-        
-        ValueFromBlock fastButterfly = m_out.anchor(
-            m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
-        
-        m_out.jump(continuation);
-        
-        m_out.appendTo(slowPath, continuation);
-        
-        ValueFromBlock slowButterfly = m_out.anchor(vmCall(
-            m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), m_callFrame));
-        
-        m_out.jump(continuation);
-        
-        m_out.appendTo(continuation, lastNext);
-        
-        LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
-        m_out.storePtr(result, object, m_heaps.JSObject_butterfly);
-        
-        setStorage(result);
</del><ins>+        setStorage(allocatePropertyStorage(object, data.previousStructure));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void compileReallocatePropertyStorage()
</span><span class="cx">     {
</span><span class="cx">         StructureTransitionData&amp; data = m_node-&gt;structureTransitionData();
</span><del>-        
-        Structure* previous = data.previousStructure;
</del><span class="cx">         LValue object = lowCell(m_node-&gt;child1());
</span><del>-
-        size_t oldSize = previous-&gt;outOfLineCapacity() * sizeof(JSValue);
-        size_t newSize = oldSize * outOfLineGrowthFactor; 
-
-        ASSERT(newSize == data.newStructure-&gt;outOfLineCapacity() * sizeof(JSValue));
</del><ins>+        LValue oldStorage = lowStorage(m_node-&gt;child2());
</ins><span class="cx">         
</span><del>-        if (previous-&gt;couldHaveIndexingHeader()) {
-            LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue));                    
-            LValue result = vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize);
-            setStorage(result);
-            return;
-        }
-        
-        LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, (&quot;ReallocatePropertyStorage slow path&quot;));
-        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;ReallocatePropertyStorage continuation&quot;));
-        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
-        
-        LValue endOfStorage = 
-            allocateBasicStorageAndGetEnd(m_out.constIntPtr(newSize), slowPath);
-        
-        ValueFromBlock fastButterfly = m_out.anchor(m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
-        
-        m_out.jump(continuation);
-        
-        m_out.appendTo(slowPath, continuation);
-        
-        LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue));       
-        
-        LValue storageLocation = vmCall(m_out.operation(operationAllocatePropertyStorage), m_callFrame, newAllocSize);
-        
-        ValueFromBlock slowButterfly = m_out.anchor(storageLocation);
-        
-        m_out.jump(continuation);
-        
-        m_out.appendTo(continuation, lastNext);
-        
-        LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
-        LValue oldStorage = m_out.loadPtr(object, m_heaps.JSObject_butterfly);
-
-        ptrdiff_t headerSize = -sizeof(JSValue) - sizeof(void *);
-        ptrdiff_t endStorage = headerSize - static_cast&lt;ptrdiff_t&gt;(oldSize);
-
-        for (ptrdiff_t offset = headerSize; offset &gt; endStorage; offset -= sizeof(void*)) {
-            LValue loaded = 
-                m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset));
-            m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset));
-        } 
-        
-        m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly));
-        
-        setStorage(result); 
</del><ins>+        setStorage(
+            reallocatePropertyStorage(
+                object, oldStorage, data.previousStructure, data.newStructure));
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    
</del><span class="cx">     void compileToString()
</span><span class="cx">     {
</span><span class="cx">         switch (m_node-&gt;child1().useKind()) {
</span><span class="lines">@@ -3140,12 +3060,8 @@
</span><span class="cx">         StorageAccessData&amp; data =
</span><span class="cx">             m_graph.m_storageAccessData[m_node-&gt;storageAccessDataIndex()];
</span><span class="cx">         
</span><del>-        setJSValue(
-            m_out.load64(
-                m_out.address(
-                    m_heaps.properties[data.identifierNumber],
-                    lowStorage(m_node-&gt;child1()),
-                    offsetRelativeToBase(data.offset))));
</del><ins>+        setJSValue(loadProperty(
+            lowStorage(m_node-&gt;child1()), data.identifierNumber, data.offset));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileMultiGetByOffset()
</span><span class="lines">@@ -3189,11 +3105,7 @@
</span><span class="cx">                     propertyBase = base;
</span><span class="cx">                 if (!isInlineOffset(variant.offset()))
</span><span class="cx">                     propertyBase = m_out.loadPtr(propertyBase, m_heaps.JSObject_butterfly);
</span><del>-                result = m_out.load64(
-                    m_out.address(
-                        m_heaps.properties[data.identifierNumber],
-                        propertyBase,
-                        offsetRelativeToBase(variant.offset())));
</del><ins>+                result = loadProperty(propertyBase, data.identifierNumber, variant.offset());
</ins><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             results.append(m_out.anchor(result));
</span><span class="lines">@@ -3213,14 +3125,68 @@
</span><span class="cx">         StorageAccessData&amp; data =
</span><span class="cx">             m_graph.m_storageAccessData[m_node-&gt;storageAccessDataIndex()];
</span><span class="cx">         
</span><del>-        m_out.store64(
</del><ins>+        storeProperty(
</ins><span class="cx">             lowJSValue(m_node-&gt;child3()),
</span><del>-            m_out.address(
-                m_heaps.properties[data.identifierNumber],
-                lowStorage(m_node-&gt;child1()),
-                offsetRelativeToBase(data.offset)));
</del><ins>+            lowStorage(m_node-&gt;child1()), data.identifierNumber, data.offset);
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void compileMultiPutByOffset()
+    {
+        LValue base = lowCell(m_node-&gt;child1());
+        LValue value = lowJSValue(m_node-&gt;child2());
+        
+        MultiPutByOffsetData&amp; data = m_node-&gt;multiPutByOffsetData();
+        
+        Vector&lt;LBasicBlock, 2&gt; blocks(data.variants.size());
+        for (unsigned i = data.variants.size(); i--;)
+            blocks[i] = FTL_NEW_BLOCK(m_out, (&quot;MultiPutByOffset case &quot;, i));
+        LBasicBlock exit = FTL_NEW_BLOCK(m_out, (&quot;MultiPutByOffset fail&quot;));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;MultiPutByOffset continuation&quot;));
+        
+        Vector&lt;SwitchCase, 2&gt; cases;
+        for (unsigned i = data.variants.size(); i--;) {
+            PutByIdVariant variant = data.variants[i];
+            cases.append(
+                SwitchCase(weakPointer(variant.oldStructure()), blocks[i], Weight(1)));
+        }
+        m_out.switchInstruction(
+            m_out.loadPtr(base, m_heaps.JSCell_structure), cases, exit, Weight(0));
+        
+        LBasicBlock lastNext = m_out.m_nextBlock;
+        
+        for (unsigned i = data.variants.size(); i--;) {
+            m_out.appendTo(blocks[i], i  + 1 &lt; data.variants.size() ? blocks[i + 1] : exit);
+            
+            PutByIdVariant variant = data.variants[i];
+            
+            LValue storage;
+            if (variant.kind() == PutByIdVariant::Replace) {
+                if (isInlineOffset(variant.offset()))
+                    storage = base;
+                else
+                    storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly);
+            } else {
+                m_graph.m_plan.transitions.addLazily(
+                    codeBlock(), m_node-&gt;origin.semantic.codeOriginOwner(),
+                    variant.oldStructure(), variant.newStructure());
+                
+                storage = storageForTransition(
+                    base, variant.offset(), variant.oldStructure(), variant.newStructure());
+                m_out.storePtr(
+                    weakPointer(variant.newStructure()), base, m_heaps.JSCell_structure);
+            }
+            
+            storeProperty(value, storage, data.identifierNumber, variant.offset());
+            m_out.jump(continuation);
+        }
+        
+        m_out.appendTo(exit, continuation);
+        terminate(BadCache);
+        m_out.unreachable();
+        
+        m_out.appendTo(continuation, lastNext);
+    }
+    
</ins><span class="cx">     void compileGetGlobalVar()
</span><span class="cx">     {
</span><span class="cx">         setJSValue(m_out.load64(m_out.absolute(m_node-&gt;registerPointer())));
</span><span class="lines">@@ -3748,6 +3714,137 @@
</span><span class="cx">         return m_out.booleanFalse;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    LValue loadProperty(LValue storage, unsigned identifierNumber, PropertyOffset offset)
+    {
+        return m_out.load64(addressOfProperty(storage, identifierNumber, offset));
+    }
+    
+    void storeProperty(
+        LValue value, LValue storage, unsigned identifierNumber, PropertyOffset offset)
+    {
+        m_out.store64(value, addressOfProperty(storage, identifierNumber, offset));
+    }
+    
+    TypedPointer addressOfProperty(
+        LValue storage, unsigned identifierNumber, PropertyOffset offset)
+    {
+        return m_out.address(
+            m_heaps.properties[identifierNumber], storage, offsetRelativeToBase(offset));
+    }
+    
+    LValue storageForTransition(
+        LValue object, PropertyOffset offset,
+        Structure* previousStructure, Structure* nextStructure)
+    {
+        if (isInlineOffset(offset))
+            return object;
+        
+        if (previousStructure-&gt;outOfLineCapacity() == nextStructure-&gt;outOfLineCapacity())
+            return m_out.loadPtr(object, m_heaps.JSObject_butterfly);
+        
+        LValue result;
+        if (!previousStructure-&gt;outOfLineCapacity())
+            result = allocatePropertyStorage(object, previousStructure);
+        else {
+            result = reallocatePropertyStorage(
+                object, m_out.loadPtr(object, m_heaps.JSObject_butterfly),
+                previousStructure, nextStructure);
+        }
+        
+        emitStoreBarrier(object);
+        
+        return result;
+    }
+    
+    LValue allocatePropertyStorage(LValue object, Structure* previousStructure)
+    {
+        if (previousStructure-&gt;couldHaveIndexingHeader()) {
+            return vmCall(
+                m_out.operation(
+                    operationReallocateButterflyToHavePropertyStorageWithInitialCapacity),
+                m_callFrame, object);
+        }
+        
+        LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, (&quot;allocatePropertyStorage slow path&quot;));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;allocatePropertyStorage continuation&quot;));
+        
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
+        
+        LValue endOfStorage = allocateBasicStorageAndGetEnd(
+            m_out.constIntPtr(initialOutOfLineCapacity * sizeof(JSValue)), slowPath);
+        
+        ValueFromBlock fastButterfly = m_out.anchor(
+            m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
+        
+        m_out.jump(continuation);
+        
+        m_out.appendTo(slowPath, continuation);
+        
+        ValueFromBlock slowButterfly = m_out.anchor(vmCall(
+            m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), m_callFrame));
+        
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        
+        LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
+        m_out.storePtr(result, object, m_heaps.JSObject_butterfly);
+        
+        return result;
+    }
+    
+    LValue reallocatePropertyStorage(
+        LValue object, LValue oldStorage, Structure* previous, Structure* next)
+    {
+        size_t oldSize = previous-&gt;outOfLineCapacity() * sizeof(JSValue);
+        size_t newSize = oldSize * outOfLineGrowthFactor; 
+
+        ASSERT_UNUSED(next, newSize == next-&gt;outOfLineCapacity() * sizeof(JSValue));
+        
+        if (previous-&gt;couldHaveIndexingHeader()) {
+            LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue));                    
+            return vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize);
+        }
+        
+        LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, (&quot;reallocatePropertyStorage slow path&quot;));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;reallocatePropertyStorage continuation&quot;));
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
+        
+        LValue endOfStorage = 
+            allocateBasicStorageAndGetEnd(m_out.constIntPtr(newSize), slowPath);
+        
+        ValueFromBlock fastButterfly = m_out.anchor(m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage));
+        
+        m_out.jump(continuation);
+        
+        m_out.appendTo(slowPath, continuation);
+        
+        LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue));       
+        
+        LValue storageLocation = vmCall(m_out.operation(operationAllocatePropertyStorage), m_callFrame, newAllocSize);
+        
+        ValueFromBlock slowButterfly = m_out.anchor(storageLocation);
+        
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        
+        LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly);
+
+        ptrdiff_t headerSize = -sizeof(JSValue) - sizeof(void *);
+        ptrdiff_t endStorage = headerSize - static_cast&lt;ptrdiff_t&gt;(oldSize);
+
+        for (ptrdiff_t offset = headerSize; offset &gt; endStorage; offset -= sizeof(void*)) {
+            LValue loaded = 
+                m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset));
+            m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset));
+        }
+        
+        m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly));
+        
+        return result;
+    }
+    
</ins><span class="cx">     LValue getById(LValue base)
</span><span class="cx">     {
</span><span class="cx">         StringImpl* uid = m_graph.identifiers()[m_node-&gt;identifierNumber()];
</span><span class="lines">@@ -5185,7 +5282,7 @@
</span><span class="cx">         return m_out.load8(m_out.baseIndex(m_heaps.MarkedBlock_markBits, markedBlock, markByteIndex, ScaleOne, MarkedBlock::offsetOfMarks()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void emitStoreBarrier(LValue base, LValue value, Edge&amp; valueEdge)
</del><ins>+    void emitStoreBarrier(LValue base, LValue value, Edge valueEdge)
</ins><span class="cx">     {
</span><span class="cx"> #if ENABLE(GGC)
</span><span class="cx">         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, (&quot;Store barrier continuation&quot;));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressfoldmultiputbyoffsettoputbyoffsetjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset.js (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/fold-multi-put-by-offset-to-put-by-offset.js        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+function foo(o) {
+    o.f = (o.f | 0) + 42;
+}
+
+function callFoo(o) {
+    return foo(o);
+}
+
+noInline(callFoo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var object;
+    if ((i % 3) == 0)
+        object = {g:3};
+    else if ((i % 3) == 1)
+        object = {f:1, g:2};
+    else if ((i % 3) == 2)
+        object = {g:1, f:2};
+    callFoo(object);
+    if (object.f != 42 + (i % 3))
+        throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + object.f;
+}
+
+function bar(o) {
+    var result = o.f;
+    foo(o);
+    return result;
+}
+
+noInline(bar);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {f:42};
+    var result = bar(o);
+    if (result != 42)
+        throw &quot;Error: bad result at end: &quot; + result;
+    if (o.f != 42 + 42)
+        throw &quot;Error: bad o.f: &quot; + o.f;
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressmultiputbyoffsetreallocationbutterflycsejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-butterfly-cse.js        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,102 @@
</span><ins>+var foos = [
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; },
+    function(o) { o[0] = 5; o.ff = 42; o[0] = 6; }
+];
+
+if (foos.length != 8)
+    throw &quot;Error&quot;;
+
+function bar(o, n) {
+    if (n == 0)
+        return;
+    o.na = 1;
+    if (n == 1)
+        return;
+    o.nb = 2;
+    if (n == 2)
+        return;
+    o.nc = 3;
+    if (n == 3)
+        return;
+    o.nd = 4;
+    if (n == 4)
+        return;
+    o.ne = 5;
+    if (n == 5)
+        return;
+    o.nf = 6;
+    if (n == 6)
+        return;
+    o.ng = 7;
+    if (n == 7)
+        return;
+    o.nh = 8;
+}
+
+function baz(o, n) {
+    if (n == 0)
+        return;
+    if (o.na != 1)
+        throw &quot;Memory corruption; have o.na = &quot; + o.na;
+    if (n == 1)
+        return;
+    if (o.nb != 2)
+        throw &quot;Memory corruption&quot;;
+    if (n == 2)
+        return;
+    if (o.nc != 3)
+        throw &quot;Memory corruption&quot;;
+    if (n == 3)
+        return;
+    if (o.nd != 4)
+        throw &quot;Memory corruption&quot;;
+    if (n == 4)
+        return;
+    if (o.ne != 5)
+        throw &quot;Memory corruption&quot;;
+    if (n == 5)
+        return;
+    if (o.nf != 6)
+        throw &quot;Memory corruption&quot;;
+    if (n == 6)
+        return;
+    if (o.ng != 7)
+        throw &quot;Memory corruption&quot;;
+    if (n == 7)
+        return;
+    if (o.nh != 8)
+        throw &quot;Memory corruption&quot;;
+}
+
+for (var i = 0; i &lt; 8; ++i)
+    noInline(foos[i]);
+noInline(bar);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {};
+    var p = {a:1, b:2, c:3, d:4, e:5, f:6};
+    o[0] = 0;
+    p[0] = 0;
+    bar(o, i % 8);
+    bar(p, i % 8);
+    
+    foos[i % 8](o);
+    foos[i % 8](p);
+    
+    if (o.ff != 42)
+        throw &quot;Bad result in o: &quot; + o.ff;
+    if (p.ff != 42)
+        throw &quot;Bad result in o: &quot; + p.ff;
+    
+    if (p.a != 1 || p.b != 2 || p.c != 3 || p.d != 4 || p.e != 5 || p.f != 6)
+        throw &quot;Memory corruption&quot;
+    baz(o, i % 8);
+    baz(p, i % 8);
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressmultiputbyoffsetreallocationcasesjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-cases.js (0 => 164620)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-cases.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/multi-put-by-offset-reallocation-cases.js        2014-02-25 02:02:50 UTC (rev 164620)
</span><span class="lines">@@ -0,0 +1,100 @@
</span><ins>+var foos = [
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; },
+    function(o) { o.ff = 42; }
+];
+
+if (foos.length != 8)
+    throw &quot;Error&quot;;
+
+function bar(o, n) {
+    if (n == 0)
+        return;
+    o.na = 1;
+    if (n == 1)
+        return;
+    o.nb = 2;
+    if (n == 2)
+        return;
+    o.nc = 3;
+    if (n == 3)
+        return;
+    o.nd = 4;
+    if (n == 4)
+        return;
+    o.ne = 5;
+    if (n == 5)
+        return;
+    o.nf = 6;
+    if (n == 6)
+        return;
+    o.ng = 7;
+    if (n == 7)
+        return;
+    o.nh = 8;
+}
+
+function baz(o, n) {
+    if (n == 0)
+        return;
+    if (o.na != 1)
+        throw &quot;Memory corruption&quot;;
+    if (n == 1)
+        return;
+    if (o.nb != 2)
+        throw &quot;Memory corruption&quot;;
+    if (n == 2)
+        return;
+    if (o.nc != 3)
+        throw &quot;Memory corruption&quot;;
+    if (n == 3)
+        return;
+    if (o.nd != 4)
+        throw &quot;Memory corruption&quot;;
+    if (n == 4)
+        return;
+    if (o.ne != 5)
+        throw &quot;Memory corruption&quot;;
+    if (n == 5)
+        return;
+    if (o.nf != 6)
+        throw &quot;Memory corruption&quot;;
+    if (n == 6)
+        return;
+    if (o.ng != 7)
+        throw &quot;Memory corruption&quot;;
+    if (n == 7)
+        return;
+    if (o.nh != 8)
+        throw &quot;Memory corruption&quot;;
+}
+
+for (var i = 0; i &lt; 8; ++i)
+    noInline(foos[i]);
+noInline(bar);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = {};
+    var p = {a:1, b:2, c:3, d:4, e:5, f:6};
+    bar(o, i % 8);
+    bar(p, i % 8);
+    
+    foos[i % 8](o);
+    foos[i % 8](p);
+    
+    if (o.ff != 42)
+        throw &quot;Bad result in o: &quot; + o.ff;
+    if (p.ff != 42)
+        throw &quot;Bad result in o: &quot; + p.ff;
+    
+    if (p.a != 1 || p.b != 2 || p.c != 3 || p.d != 4 || p.e != 5 || p.f != 6)
+        throw &quot;Memory corruption&quot;
+    baz(o, i % 8);
+    baz(p, i % 8);
+}
+
</ins></span></pre>
</div>
</div>

</body>
</html>