<!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<AbstractStateType>::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 <fpizlo@apple.com>
+
+ 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 <samuel_white@apple.com>
</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 "PASS" messages, followed by "TEST COMPLETE".
+
+
+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>+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/polymorphic-put-by-id.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
</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 < 100; ++i)
+ o.f = (o.f | 0) + 42;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 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 "Error: bad result for i = " + i + ": " + object.f;
+}
+
+var r = {g:3, h:4, f:5};
+foo(r);
+if (r.f != 5 + 42 * 100)
+ throw "Error: bad result at end: " + 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 <fpizlo@apple.com>
+
+ 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<AbstractStateType>::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 <peavo@outlook.com>
</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"> <ClCompile Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.cpp" />
</span><span class="cx"> <ClCompile Include="..\bytecode\PreciseJumpTargets.cpp" />
</span><span class="cx"> <ClCompile Include="..\bytecode\PutByIdStatus.cpp" />
</span><ins>+ <ClCompile Include="..\bytecode\PutByIdVariant.cpp" />
</ins><span class="cx"> <ClCompile Include="..\bytecode\ReduceWhitespace.cpp" />
</span><span class="cx"> <ClCompile Include="..\bytecode\SamplingTool.cpp" />
</span><span class="cx"> <ClCompile Include="..\bytecode\SpecialPointer.cpp" />
</span><span class="lines">@@ -858,6 +859,7 @@
</span><span class="cx"> <ClInclude Include="..\bytecode\ProfiledCodeBlockJettisoningWatchpoint.h" />
</span><span class="cx"> <ClInclude Include="..\bytecode\PreciseJumpTargets.h" />
</span><span class="cx"> <ClInclude Include="..\bytecode\PutByIdStatus.h" />
</span><ins>+ <ClInclude Include="..\bytecode\PutByIdVariant.h" />
</ins><span class="cx"> <ClInclude Include="..\bytecode\PutKind.h" />
</span><span class="cx"> <ClInclude Include="..\bytecode\ReduceWhitespace.h" />
</span><span class="cx"> <ClInclude Include="..\bytecode\SamplingTool.h" />
</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 = "<group>"; };
</span><span class="cx">                 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdStatus.h; sourceTree = "<group>"; };
</span><span class="cx">                 0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = "<group>"; };
</span><ins>+                0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdVariant.cpp; sourceTree = "<group>"; };
+                0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdVariant.h; sourceTree = "<group>"; };
</ins><span class="cx">                 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = "<group>"; };
</span><span class="cx">                 0F96EBB116676EF4008BADE3 /* CodeBlockWithJITType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockWithJITType.h; sourceTree = "<group>"; };
</span><span class="cx">                 0F97496F1687ADE200A4FF6A /* JSCellInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCellInlines.h; sourceTree = "<group>"; };
</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 "LLIntData.h"
</span><span class="cx"> #include "LowLevelInterpreter.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><ins>+#include "PolymorphicPutByIdList.h"
</ins><span class="cx"> #include "Structure.h"
</span><span class="cx"> #include "StructureChain.h"
</span><ins>+#include <wtf/ListDump.h>
</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->getConcurrently(*profiledBlock->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->transitionWatchpointSetHasBeenInvalidated());
</span><span class="lines">@@ -81,14 +83,14 @@
</span><span class="cx">
</span><span class="cx"> PropertyOffset offset = newStructure->getConcurrently(*profiledBlock->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->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->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->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->u.putByIdReplace.baseObjectStructure->getConcurrently(
</span><span class="cx"> *profiledBlock->vm(), uid);
</span><span class="cx"> if (isValidOffset(offset)) {
</span><del>- return PutByIdStatus(
- SimpleReplace,
- stubInfo->u.putByIdReplace.baseObjectStructure.get(),
- 0, 0,
- offset);
</del><ins>+ return PutByIdVariant::replace(
+ stubInfo->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->u.putByIdTransition.structure->getConcurrently(
</span><span class="cx"> *profiledBlock->vm(), uid);
</span><span class="cx"> if (isValidOffset(offset)) {
</span><del>- return PutByIdStatus(
- SimpleTransition,
</del><ins>+ return PutByIdVariant::transition(
</ins><span class="cx"> stubInfo->u.putByIdTransition.previousStructure.get(),
</span><span class="cx"> stubInfo->u.putByIdTransition.structure.get(),
</span><span class="cx"> stubInfo->u.putByIdTransition.chain ? adoptRef(new IntendedStructureChain(
</span><span class="lines">@@ -160,13 +158,51 @@
</span><span class="cx"> stubInfo->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->u.putByIdList.list;
+
+ PutByIdStatus result;
+ result.m_state = Simple;
+
+ for (unsigned i = 0; i < list->size(); ++i) {
+ const PutByIdAccess& access = list->at(i);
+
+ switch (access.type()) {
+ case PutByIdAccess::Replace: {
+ Structure* structure = access.structure();
+ PropertyOffset offset = structure->getConcurrently(*profiledBlock->vm(), uid);
+ if (!isValidOffset(offset))
+ return PutByIdStatus(TakesSlowPath);
+ result.m_variants.append(PutByIdVariant::replace(structure, offset));
+ break;
+ }
+
+ case PutByIdAccess::Transition: {
+ PropertyOffset offset =
+ access.newStructure()->getConcurrently(*profiledBlock->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->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& out) const
+{
+ switch (m_state) {
+ case NoInformation:
+ out.print("(NoInformation)");
+ return;
+
+ case Simple:
+ out.print("(", listDump(m_variants), ")");
+ return;
+
+ case TakesSlowPath:
+ out.print("(TakesSlowPath)");
+ 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 "ExitingJITType.h"
</span><del>-#include "IntendedStructureChain.h"
-#include "PropertyOffset.h"
</del><ins>+#include "PutByIdVariant.h"
</ins><span class="cx"> #include "StructureStubInfo.h"
</span><span class="cx"> #include <wtf/text/StringImpl.h>
</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<IntendedStructureChain> structureChain,
- PropertyOffset offset)
- : m_state(state)
- , m_oldStructure(oldStructure)
- , m_newStructure(newStructure)
- , m_structureChain(structureChain)
- , m_offset(offset)
</del><ins>+ PutByIdStatus(const PutByIdVariant& 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) && 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&, 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<PutByIdVariant, 1>& variants() const { return m_variants; }
+ const PutByIdVariant& at(size_t index) const { return m_variants[index]; }
+ const PutByIdVariant& operator[](size_t index) const { return at(index); }
</ins><span class="cx">
</span><ins>+ void dump(PrintStream&) const;
+
</ins><span class="cx"> private:
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx"> static bool hasExitSite(const ConcurrentJITLocker&, 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<IntendedStructureChain> m_structureChain;
- PropertyOffset m_offset;
</del><ins>+ Vector<PutByIdVariant, 1> 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 "config.h"
+#include "PutByIdVariant.h"
+
+namespace JSC {
+
+void PutByIdVariant::dump(PrintStream& out) const
+{
+ dumpInContext(out, 0);
+}
+
+void PutByIdVariant::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+ switch (kind()) {
+ case NotSet:
+ out.print("<empty>");
+ return;
+
+ case Replace:
+ out.print(
+ "<Replace: ", pointerDumpInContext(structure(), context), ", ", offset(), ">");
+ return;
+
+ case Transition:
+ out.print(
+ "<Transition: ", pointerDumpInContext(oldStructure(), context), " -> ",
+ pointerDumpInContext(newStructure(), context), ", ",
+ pointerDumpInContext(structureChain(), context), ", ", offset(), ">");
+ 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 "IntendedStructureChain.h"
+#include "PropertyOffset.h"
+
+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<IntendedStructureChain> 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&) const;
+ void dumpInContext(PrintStream&, DumpContext*) const;
+
+private:
+ Kind m_kind;
+ Structure* m_oldStructure;
+ Structure* m_newStructure;
+ RefPtr<IntendedStructureChain> 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->multiGetByOffsetData().variants.size(); i--;)
</span><span class="cx"> set.addAll(node->multiGetByOffsetData().variants[i].structureSet());
</span><span class="cx">
</span><del>- filter(value, set);
</del><ins>+ filter(node->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& value = forNode(node->child1());
+ ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
+
+ if (Structure* structure = value.bestProvenStructure()) {
+ bool done = false;
+ for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
+ const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
+ if (variant.oldStructure() != structure)
+ continue;
+
+ if (variant.kind() == PutByIdVariant::Replace) {
+ filter(node->child1(), structure);
+ m_state.setFoundConstants(true);
+ m_state.setHaveStructures(true);
+ done = true;
+ break;
+ }
+
+ ASSERT(variant.kind() == PutByIdVariant::Transition);
+ clobberStructures(clobberLimit);
+ forNode(node->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->multiPutByOffsetData().variants.size(); i--;) {
+ const PutByIdVariant& variant = node->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->child1(), newSet);
+ break;
+ }
+
</ins><span class="cx"> case CheckFunction: {
</span><span class="cx"> JSValue value = forNode(node->child1()).value();
</span><span class="cx"> if (value == node->function()) {
</span><span class="lines">@@ -1685,19 +1738,21 @@
</span><span class="cx"> structure,
</span><span class="cx"> m_graph.identifiers()[node->identifierNumber()],
</span><span class="cx"> node->op() == PutByIdDirect);
</span><del>- if (status.isSimpleReplace()) {
- filter(node->child1(), structure);
- m_state.setFoundConstants(true);
- m_state.setHaveStructures(true);
- break;
</del><ins>+ if (status.isSimple() && status.numVariants() == 1) {
+ if (status[0].kind() == PutByIdVariant::Replace) {
+ filter(node->child1(), structure);
+ m_state.setFoundConstants(true);
+ m_state.setHaveStructures(true);
+ break;
+ }
+ if (status[0].kind() == PutByIdVariant::Transition) {
+ clobberStructures(clobberLimit);
+ forNode(node->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->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->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&);
</span><del>- Node* emitPrototypeChecks(const GetByIdVariant&);
</del><ins>+ void emitPutById(
+ Node* base, unsigned identifierNumber, Node* value, bool isDirect);
+ void handlePutById(
+ Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&,
+ 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& 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 < variant.chain()->size(); ++i) {
</del><ins>+ for (unsigned i = 0; i < chain->size(); ++i) {
</ins><span class="cx"> currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock));
</span><del>- currentStructure = variant.chain()->at(i);
</del><ins>+ currentStructure = chain->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()->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& putByIdStatus, bool isDirect)
+{
+ if (!putByIdStatus.isSimple()) {
+ if (!putByIdStatus.isSet())
+ addToGraph(ForceOSRExit);
+ emitPutById(base, identifierNumber, value, isDirect);
+ return;
+ }
+
+ if (putByIdStatus.numVariants() > 1) {
+ if (!isFTL(m_graph.m_plan.mode)) {
+ emitPutById(base, identifierNumber, value, isDirect);
+ return;
+ }
+
+ if (m_graph.compilation())
+ m_graph.compilation()->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->variants = putByIdStatus.variants();
+ data->identifierNumber = identifierNumber;
+ addToGraph(MultiPutByOffset, OpInfo(data), base, value);
+ return;
+ }
+
+ ASSERT(putByIdStatus.numVariants() == 1);
+ const PutByIdVariant& 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()->noticeInlinedPutById();
+ return;
+ }
+
+ ASSERT(variant.kind() == PutByIdVariant::Transition);
+ if (variant.structureChain() && !variant.structureChain()->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()->transitionWatchpointSetHasBeenInvalidated());
+
+ Node* propertyStorage;
+ StructureTransitionData* transitionData = m_graph.addStructureTransitionData(
+ StructureTransitionData(variant.oldStructure(), variant.newStructure()));
+
+ if (variant.oldStructure()->outOfLineCapacity()
+ != variant.newStructure()->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()->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()->noticeInlinedPutById();
+}
+
</ins><span class="cx"> void ByteCodeParser::prepareToParseBlock()
</span><span class="cx"> {
</span><span class="cx"> for (unsigned i = 0; i < m_constants.size(); ++i)
</span><span class="lines">@@ -2590,91 +2721,8 @@
</span><span class="cx"> m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock,
</span><span class="cx"> m_inlineStackTop->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()
- && (!putByIdStatus.structureChain()
- || putByIdStatus.structureChain()->isStillValid())) {
-
- m_graph.chains().addLazily(putByIdStatus.structureChain());
-
- addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
- if (!direct) {
- if (!putByIdStatus.oldStructure()->storedPrototype().isNull()) {
- cellConstantWithStructureCheck(
- putByIdStatus.oldStructure()->storedPrototype().asCell());
- }
-
- for (unsigned i = 0; i < putByIdStatus.structureChain()->size(); ++i) {
- JSValue prototype = putByIdStatus.structureChain()->at(i)->storedPrototype();
- if (prototype.isNull())
- continue;
- cellConstantWithStructureCheck(prototype.asCell());
- }
- }
- ASSERT(putByIdStatus.oldStructure()->transitionWatchpointSetHasBeenInvalidated());
-
- Node* propertyStorage;
- StructureTransitionData* transitionData =
- m_graph.addStructureTransitionData(
- StructureTransitionData(
- putByIdStatus.oldStructure(),
- putByIdStatus.newStructure()));
-
- if (putByIdStatus.oldStructure()->outOfLineCapacity()
- != putByIdStatus.newStructure()->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()->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 && m_graph.compilation())
- m_graph.compilation()->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<PropertyOffset>(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->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->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->multiPutByOffsetData().identifierNumber == identifierNumber) {
+ if (node->child1() == base)
+ return node->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->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->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->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->multiPutByOffsetData().identifierNumber));
+ if (node->multiPutByOffsetData().writesStructures())
+ write(JSCell_structure);
+ if (node->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->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->child1();
+ Node* child = childEdge.node();
+ MultiPutByOffsetData& data = node->multiPutByOffsetData();
+
+ Structure* structure = m_state.forNode(child).bestProvenStructure();
+ if (!structure)
+ break;
+
+ for (unsigned i = data.variants.size(); i--;) {
+ const PutByIdVariant& 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 & ~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->op() == PutByIdDirect);
</span><span class="cx">
</span><del>- if (!status.isSimpleReplace() && !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->op() == PutById) {
- if (!structure->storedPrototype().isNull()) {
- addStructureTransitionCheck(
- origin, indexInBlock,
- structure->storedPrototype().asCell());
- }
-
- m_graph.chains().addLazily(status.structureChain());
-
- for (unsigned i = 0; i < status.structureChain()->size(); ++i) {
- JSValue prototype = status.structureChain()->at(i)->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->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
- propertyStorage = Edge(m_insertionSet.insertNode(
- indexInBlock, SpecNone, GetButterfly, origin, childEdge));
- } else if (!structure->outOfLineCapacity()) {
- ASSERT(status.newStructure()->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->child1().node(), KnownCellUse));
- propertyStorage = Edge(allocatePropertyStorage);
- } else {
- ASSERT(structure->outOfLineCapacity());
- ASSERT(status.newStructure()->outOfLineCapacity() > structure->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->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->child1().node(), KnownCellUse));
- m_insertionSet.insert(indexInBlock, putStructure);
- }
-
- node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
- m_insertionSet.insertNode(indexInBlock, SpecNone, ConditionalStoreBarrier, origin,
- Edge(node->child2().node(), KnownCellUse), Edge(node->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& variant, unsigned identifierNumber)
+ {
+ NodeOrigin origin = node->origin;
+ Edge childEdge = node->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 & ~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->op() == PutById) {
+ if (!structure->storedPrototype().isNull()) {
+ addStructureTransitionCheck(
+ origin, indexInBlock,
+ structure->storedPrototype().asCell());
+ }
+
+ m_graph.chains().addLazily(variant.structureChain());
+
+ for (unsigned i = 0; i < variant.structureChain()->size(); ++i) {
+ JSValue prototype = variant.structureChain()->at(i)->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->outOfLineCapacity() == variant.newStructure()->outOfLineCapacity()) {
+ propertyStorage = Edge(m_insertionSet.insertNode(
+ indexInBlock, SpecNone, GetButterfly, origin, childEdge));
+ } else if (!structure->outOfLineCapacity()) {
+ ASSERT(variant.newStructure()->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->child1().node(), KnownCellUse));
+ propertyStorage = Edge(allocatePropertyStorage);
+ } else {
+ ASSERT(structure->outOfLineCapacity());
+ ASSERT(variant.newStructure()->outOfLineCapacity() > structure->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->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->child1().node(), KnownCellUse));
+ m_insertionSet.insert(indexInBlock, putStructure);
+ }
+
+ node->convertToPutByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
+ m_insertionSet.insertNode(
+ indexInBlock, SpecNone, ConditionalStoreBarrier, origin,
+ Edge(node->child2().node(), KnownCellUse),
+ Edge(node->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<CellUse>(node->child1());
+ insertStoreBarrier(m_indexInBlock, node->child1(), node->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 < data.variants.size(); ++i)
</span><span class="cx"> out.print(comma, inContext(data.variants[i], context));
</span><span class="cx"> }
</span><ins>+ if (node->hasMultiPutByOffsetData()) {
+ MultiPutByOffsetData& data = node->multiPutByOffsetData();
+ out.print(comma, "id", data.identifierNumber, "{", identifiers()[data.identifierNumber], "}");
+ for (unsigned i = 0; i < data.variants.size(); ++i)
+ out.print(comma, inContext(data.variants[i], context));
+ }
</ins><span class="cx"> ASSERT(node->hasVariableAccessData(*this) == node->hasLocal(*this));
</span><span class="cx"> if (node->hasVariableAccessData(*this)) {
</span><span class="cx"> VariableAccessData* variableAccessData = node->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<BranchData> m_branchData;
</span><span class="cx"> Bag<SwitchData> m_switchData;
</span><span class="cx"> Bag<MultiGetByOffsetData> m_multiGetByOffsetData;
</span><ins>+ Bag<MultiPutByOffsetData> m_multiPutByOffsetData;
</ins><span class="cx"> Vector<InlineVariableData, 4> m_inlineVariableData;
</span><span class="cx"> OwnPtr<InlineCallFrameSet> m_inlineCallFrames;
</span><span class="cx"> HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> 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()->outOfLineCapacity() ==
+ variants[i].newStructure()->outOfLineCapacity())
+ continue;
+
+ return true;
+ }
+ return false;
+}
+
</ins><span class="cx"> void BranchTarget::dump(PrintStream& 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 "GetByIdVariant.h"
</span><span class="cx"> #include "JSCJSValue.h"
</span><span class="cx"> #include "Operands.h"
</span><ins>+#include "PutByIdVariant.h"
</ins><span class="cx"> #include "SpeculatedType.h"
</span><span class="cx"> #include "StructureSet.h"
</span><span class="cx"> #include "ValueProfile.h"
</span><span class="lines">@@ -57,6 +58,14 @@
</span><span class="cx"> Vector<GetByIdVariant, 2> variants;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+struct MultiPutByOffsetData {
+ unsigned identifierNumber;
+ Vector<PutByIdVariant, 2> 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<MultiGetByOffsetData*>(m_opInfo);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool hasMultiPutByOffsetData()
+ {
+ return op() == MultiPutByOffset;
+ }
+
+ MultiPutByOffsetData& multiPutByOffsetData()
+ {
+ return *reinterpret_cast<MultiPutByOffsetData*>(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->common.notifyCompilingStructureTransition(m_graph.m_plan, codeBlock(), m_node);
</span><span class="cx">
</span><del>- m_out.store64(
- m_out.constIntPtr(m_node->structureTransitionData().newStructure),
</del><ins>+ m_out.storePtr(
+ weakPointer(m_node->structureTransitionData().newStructure),
</ins><span class="cx"> lowCell(m_node->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& data = m_node->structureTransitionData();
</span><del>-
</del><span class="cx"> LValue object = lowCell(m_node->child1());
</span><span class="cx">
</span><del>- if (data.previousStructure->couldHaveIndexingHeader()) {
- setStorage(vmCall(
- m_out.operation(
- operationReallocateButterflyToHavePropertyStorageWithInitialCapacity),
- m_callFrame, object));
- return;
- }
-
- LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("AllocatePropertyStorage slow path"));
- LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("AllocatePropertyStorage continuation"));
-
- 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& data = m_node->structureTransitionData();
</span><del>-
- Structure* previous = data.previousStructure;
</del><span class="cx"> LValue object = lowCell(m_node->child1());
</span><del>-
- size_t oldSize = previous->outOfLineCapacity() * sizeof(JSValue);
- size_t newSize = oldSize * outOfLineGrowthFactor;
-
- ASSERT(newSize == data.newStructure->outOfLineCapacity() * sizeof(JSValue));
</del><ins>+ LValue oldStorage = lowStorage(m_node->child2());
</ins><span class="cx">
</span><del>- if (previous->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, ("ReallocatePropertyStorage slow path"));
- LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ReallocatePropertyStorage continuation"));
- 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<ptrdiff_t>(oldSize);
-
- for (ptrdiff_t offset = headerSize; offset > 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->child1().useKind()) {
</span><span class="lines">@@ -3140,12 +3060,8 @@
</span><span class="cx"> StorageAccessData& data =
</span><span class="cx"> m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
</span><span class="cx">
</span><del>- setJSValue(
- m_out.load64(
- m_out.address(
- m_heaps.properties[data.identifierNumber],
- lowStorage(m_node->child1()),
- offsetRelativeToBase(data.offset))));
</del><ins>+ setJSValue(loadProperty(
+ lowStorage(m_node->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& data =
</span><span class="cx"> m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
</span><span class="cx">
</span><del>- m_out.store64(
</del><ins>+ storeProperty(
</ins><span class="cx"> lowJSValue(m_node->child3()),
</span><del>- m_out.address(
- m_heaps.properties[data.identifierNumber],
- lowStorage(m_node->child1()),
- offsetRelativeToBase(data.offset)));
</del><ins>+ lowStorage(m_node->child1()), data.identifierNumber, data.offset);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ void compileMultiPutByOffset()
+ {
+ LValue base = lowCell(m_node->child1());
+ LValue value = lowJSValue(m_node->child2());
+
+ MultiPutByOffsetData& data = m_node->multiPutByOffsetData();
+
+ Vector<LBasicBlock, 2> blocks(data.variants.size());
+ for (unsigned i = data.variants.size(); i--;)
+ blocks[i] = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset case ", i));
+ LBasicBlock exit = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset fail"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MultiPutByOffset continuation"));
+
+ Vector<SwitchCase, 2> 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 < 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->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->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->outOfLineCapacity() == nextStructure->outOfLineCapacity())
+ return m_out.loadPtr(object, m_heaps.JSObject_butterfly);
+
+ LValue result;
+ if (!previousStructure->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->couldHaveIndexingHeader()) {
+ return vmCall(
+ m_out.operation(
+ operationReallocateButterflyToHavePropertyStorageWithInitialCapacity),
+ m_callFrame, object);
+ }
+
+ LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage slow path"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage continuation"));
+
+ 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->outOfLineCapacity() * sizeof(JSValue);
+ size_t newSize = oldSize * outOfLineGrowthFactor;
+
+ ASSERT_UNUSED(next, newSize == next->outOfLineCapacity() * sizeof(JSValue));
+
+ if (previous->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, ("reallocatePropertyStorage slow path"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage continuation"));
+ 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<ptrdiff_t>(oldSize);
+
+ for (ptrdiff_t offset = headerSize; offset > 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->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& 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, ("Store barrier continuation"));
</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 < 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 "Error: bad result for i = " + i + ": " + object.f;
+}
+
+function bar(o) {
+ var result = o.f;
+ foo(o);
+ return result;
+}
+
+noInline(bar);
+
+for (var i = 0; i < 100000; ++i) {
+ var o = {f:42};
+ var result = bar(o);
+ if (result != 42)
+ throw "Error: bad result at end: " + result;
+ if (o.f != 42 + 42)
+ throw "Error: bad o.f: " + 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 "Error";
+
+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 "Memory corruption; have o.na = " + o.na;
+ if (n == 1)
+ return;
+ if (o.nb != 2)
+ throw "Memory corruption";
+ if (n == 2)
+ return;
+ if (o.nc != 3)
+ throw "Memory corruption";
+ if (n == 3)
+ return;
+ if (o.nd != 4)
+ throw "Memory corruption";
+ if (n == 4)
+ return;
+ if (o.ne != 5)
+ throw "Memory corruption";
+ if (n == 5)
+ return;
+ if (o.nf != 6)
+ throw "Memory corruption";
+ if (n == 6)
+ return;
+ if (o.ng != 7)
+ throw "Memory corruption";
+ if (n == 7)
+ return;
+ if (o.nh != 8)
+ throw "Memory corruption";
+}
+
+for (var i = 0; i < 8; ++i)
+ noInline(foos[i]);
+noInline(bar);
+
+for (var i = 0; i < 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 "Bad result in o: " + o.ff;
+ if (p.ff != 42)
+ throw "Bad result in o: " + p.ff;
+
+ if (p.a != 1 || p.b != 2 || p.c != 3 || p.d != 4 || p.e != 5 || p.f != 6)
+ throw "Memory corruption"
+ 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 "Error";
+
+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 "Memory corruption";
+ if (n == 1)
+ return;
+ if (o.nb != 2)
+ throw "Memory corruption";
+ if (n == 2)
+ return;
+ if (o.nc != 3)
+ throw "Memory corruption";
+ if (n == 3)
+ return;
+ if (o.nd != 4)
+ throw "Memory corruption";
+ if (n == 4)
+ return;
+ if (o.ne != 5)
+ throw "Memory corruption";
+ if (n == 5)
+ return;
+ if (o.nf != 6)
+ throw "Memory corruption";
+ if (n == 6)
+ return;
+ if (o.ng != 7)
+ throw "Memory corruption";
+ if (n == 7)
+ return;
+ if (o.nh != 8)
+ throw "Memory corruption";
+}
+
+for (var i = 0; i < 8; ++i)
+ noInline(foos[i]);
+noInline(bar);
+
+for (var i = 0; i < 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 "Bad result in o: " + o.ff;
+ if (p.ff != 42)
+ throw "Bad result in o: " + p.ff;
+
+ if (p.a != 1 || p.b != 2 || p.c != 3 || p.d != 4 || p.e != 5 || p.f != 6)
+ throw "Memory corruption"
+ baz(o, i % 8);
+ baz(p, i % 8);
+}
+
</ins></span></pre>
</div>
</div>
</body>
</html>