<!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>[181817] trunk/Source/JavaScriptCore</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/181817">181817</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-03-20 16:26:26 -0700 (Fri, 20 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Observably effectful nodes in DFG IR should come last in their bytecode instruction (i.e. forExit section), except for Hint nodes
https://bugs.webkit.org/show_bug.cgi?id=142920

Reviewed by Oliver Hunt, Geoffrey Garen, and Mark Lam.
        
Observably effectful, n.: If we reexecute the bytecode instruction after this node has
executed, then something other than the bytecode instruction's specified outcome will
happen.

We almost never had observably effectful nodes except at the end of the bytecode
instruction.  The exception is a lowered transitioning PutById:

PutStructure(@o, S1 -&gt; S2)
PutByOffset(@o, @o, @v)

The PutStructure is observably effectful: if you try to reexecute the bytecode after
doing the PutStructure, then we'll most likely crash.  The generic PutById handling means
first checking what the old structure of the object is; but if we reexecute, the old
structure will seem to be the new structure.  But the property ensured by the new
structure hasn't been stored yet, so any attempt to load it or scan it will crash.

Intriguingly, however, none of the other operations involved in the PutById are
observably effectful.  Consider this example:

PutByOffset(@o, @o, @v)
PutStructure(@o, S1 -&gt; S2)

Note that the PutStructure node doesn't reallocate property storage; see further below
for an example that does that. Because no property storage is happening, we know that we
already had room for the new property.  This means that the PutByOffset is no observable
until the PutStructure executes and &quot;reveals&quot; the property.  Hence, PutByOffset is not
observably effectful.

Now consider this:

b: AllocatePropertyStorage(@o)
PutByOffset(@b, @o, @v)
PutStructure(@o, S1 -&gt; S2)

Surprisingly, this is also safe, because the AllocatePropertyStorage is not observably
effectful. It *does* reallocate the property storage and the new property storage pointer
is stored into the object. But until the PutStructure occurs, the world will just think
that the reallocation didn't happen, in the sense that we'll think that the property
storage is using less memory than what we just allocated. That's harmless.

The AllocatePropertyStorage is safe in other ways, too. Even if we GC'd after the
AllocatePropertyStorage but before the PutByOffset (or before the PutStructure),
everything could be expected to be fine, so long as all of @o, @v and @b are on the
stack. If they are all on the stack, then the GC will leave the property storage alone
(so the extra memory we just allocated would be safe). The GC will not scan the part of
the property storage that contains @v, but that's fine, so long as @v is on the stack.
        
The better long-term solution is probably bug 142921.
        
But for now, this:
        
- Fixes an object materialization bug, exemplified by the two tests, that previously
  crashed 100% of the time with FTL enabled and concurrent JIT disabled.
        
- Allows us to remove the workaround introduced in <a href="http://trac.webkit.org/projects/webkit/changeset/174856">r174856</a>.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handlePutById):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::insertCheck):
(JSC::DFG::FixupPhase::indexOfNode): Deleted.
(JSC::DFG::FixupPhase::indexOfFirstNodeOfExitOrigin): Deleted.
* dfg/DFGInsertionSet.h:
(JSC::DFG::InsertionSet::insertOutOfOrder): Deleted.
(JSC::DFG::InsertionSet::insertOutOfOrderNode): Deleted.
* tests/stress/materialize-past-butterfly-allocation.js: Added.
(bar):
(foo0):
(foo1):
(foo2):
(foo3):
(foo4):
* tests/stress/materialize-past-put-structure.js: Added.
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</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="#trunkSourceJavaScriptCoredfgDFGInsertionSeth">trunk/Source/JavaScriptCore/dfg/DFGInsertionSet.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressmaterializepastbutterflyallocationjs">trunk/Source/JavaScriptCore/tests/stress/materialize-past-butterfly-allocation.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressmaterializepastputstructurejs">trunk/Source/JavaScriptCore/tests/stress/materialize-past-put-structure.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (181816 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-03-20 23:09:56 UTC (rev 181816)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -1,3 +1,87 @@
</span><ins>+2015-03-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Observably effectful nodes in DFG IR should come last in their bytecode instruction (i.e. forExit section), except for Hint nodes
+        https://bugs.webkit.org/show_bug.cgi?id=142920
+
+        Reviewed by Oliver Hunt, Geoffrey Garen, and Mark Lam.
+        
+        Observably effectful, n.: If we reexecute the bytecode instruction after this node has
+        executed, then something other than the bytecode instruction's specified outcome will
+        happen.
+
+        We almost never had observably effectful nodes except at the end of the bytecode
+        instruction.  The exception is a lowered transitioning PutById:
+
+        PutStructure(@o, S1 -&gt; S2)
+        PutByOffset(@o, @o, @v)
+
+        The PutStructure is observably effectful: if you try to reexecute the bytecode after
+        doing the PutStructure, then we'll most likely crash.  The generic PutById handling means
+        first checking what the old structure of the object is; but if we reexecute, the old
+        structure will seem to be the new structure.  But the property ensured by the new
+        structure hasn't been stored yet, so any attempt to load it or scan it will crash.
+
+        Intriguingly, however, none of the other operations involved in the PutById are
+        observably effectful.  Consider this example:
+
+        PutByOffset(@o, @o, @v)
+        PutStructure(@o, S1 -&gt; S2)
+
+        Note that the PutStructure node doesn't reallocate property storage; see further below
+        for an example that does that. Because no property storage is happening, we know that we
+        already had room for the new property.  This means that the PutByOffset is no observable
+        until the PutStructure executes and &quot;reveals&quot; the property.  Hence, PutByOffset is not
+        observably effectful.
+
+        Now consider this:
+
+        b: AllocatePropertyStorage(@o)
+        PutByOffset(@b, @o, @v)
+        PutStructure(@o, S1 -&gt; S2)
+
+        Surprisingly, this is also safe, because the AllocatePropertyStorage is not observably
+        effectful. It *does* reallocate the property storage and the new property storage pointer
+        is stored into the object. But until the PutStructure occurs, the world will just think
+        that the reallocation didn't happen, in the sense that we'll think that the property
+        storage is using less memory than what we just allocated. That's harmless.
+
+        The AllocatePropertyStorage is safe in other ways, too. Even if we GC'd after the
+        AllocatePropertyStorage but before the PutByOffset (or before the PutStructure),
+        everything could be expected to be fine, so long as all of @o, @v and @b are on the
+        stack. If they are all on the stack, then the GC will leave the property storage alone
+        (so the extra memory we just allocated would be safe). The GC will not scan the part of
+        the property storage that contains @v, but that's fine, so long as @v is on the stack.
+        
+        The better long-term solution is probably bug 142921.
+        
+        But for now, this:
+        
+        - Fixes an object materialization bug, exemplified by the two tests, that previously
+          crashed 100% of the time with FTL enabled and concurrent JIT disabled.
+        
+        - Allows us to remove the workaround introduced in r174856.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handlePutById):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::emitPutByOffset):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::insertCheck):
+        (JSC::DFG::FixupPhase::indexOfNode): Deleted.
+        (JSC::DFG::FixupPhase::indexOfFirstNodeOfExitOrigin): Deleted.
+        * dfg/DFGInsertionSet.h:
+        (JSC::DFG::InsertionSet::insertOutOfOrder): Deleted.
+        (JSC::DFG::InsertionSet::insertOutOfOrderNode): Deleted.
+        * tests/stress/materialize-past-butterfly-allocation.js: Added.
+        (bar):
+        (foo0):
+        (foo1):
+        (foo2):
+        (foo3):
+        (foo4):
+        * tests/stress/materialize-past-put-structure.js: Added.
+        (foo):
+
</ins><span class="cx"> 2015-03-20  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r179429): Potential Use after free in JavaScriptCore`WTF::StringImpl::ref + 83
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (181816 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-03-20 23:09:56 UTC (rev 181816)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -2422,8 +2422,6 @@
</span><span class="cx">                 propertyStorage = addToGraph(GetButterfly, base);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        addToGraph(PutStructure, OpInfo(transition), base);
-
</del><span class="cx">         StorageAccessData* data = m_graph.m_storageAccessData.add();
</span><span class="cx">         data-&gt;offset = variant.offset();
</span><span class="cx">         data-&gt;identifierNumber = identifierNumber;
</span><span class="lines">@@ -2435,6 +2433,11 @@
</span><span class="cx">             base,
</span><span class="cx">             value);
</span><span class="cx"> 
</span><ins>+        // FIXME: PutStructure goes last until we fix either
+        // https://bugs.webkit.org/show_bug.cgi?id=142921 or
+        // https://bugs.webkit.org/show_bug.cgi?id=142924.
+        addToGraph(PutStructure, OpInfo(transition), base);
+
</ins><span class="cx">         if (m_graph.compilation())
</span><span class="cx">             m_graph.compilation()-&gt;noticeInlinedPutById();
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (181816 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2015-03-20 23:09:56 UTC (rev 181816)
+++ trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -568,20 +568,19 @@
</span><span class="cx">             propertyStorage = Edge(reallocatePropertyStorage);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (variant.kind() == PutByIdVariant::Transition) {
-            Node* putStructure = m_graph.addNode(SpecNone, PutStructure, origin, OpInfo(transition), childEdge);
-            m_insertionSet.insertNode(indexInBlock, SpecNone, StoreBarrier, origin, Edge(node-&gt;child1().node(), KnownCellUse));
-            m_insertionSet.insert(indexInBlock, putStructure);
-        }
-
</del><span class="cx">         StorageAccessData&amp; data = *m_graph.m_storageAccessData.add();
</span><span class="cx">         data.offset = variant.offset();
</span><span class="cx">         data.identifierNumber = identifierNumber;
</span><span class="cx">         
</span><span class="cx">         node-&gt;convertToPutByOffset(data, propertyStorage);
</span><del>-        m_insertionSet.insertNode(
-            indexInBlock, SpecNone, StoreBarrier, origin, 
-            Edge(node-&gt;child2().node(), KnownCellUse));
</del><ins>+
+        if (variant.kind() == PutByIdVariant::Transition) {
+            // FIXME: PutStructure goes last until we fix either
+            // https://bugs.webkit.org/show_bug.cgi?id=142921 or
+            // https://bugs.webkit.org/show_bug.cgi?id=142924.
+            m_insertionSet.insertNode(
+                indexInBlock + 1, SpecNone, PutStructure, origin, OpInfo(transition), childEdge);
+        }
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void addBaseCheck(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (181816 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-03-20 23:09:56 UTC (rev 181816)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -89,33 +89,6 @@
</span><span class="cx">         m_insertionSet.execute(block);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    inline unsigned indexOfNode(Node* node, unsigned indexToSearchFrom)
-    {
-        unsigned index = indexToSearchFrom;
-        while (index) {
-            if (m_block-&gt;at(index) == node)
-                break;
-            index--;
-        }
-        ASSERT(m_block-&gt;at(index) == node);
-        return index;
-    }
-
-    inline unsigned indexOfFirstNodeOfExitOrigin(CodeOrigin&amp; originForExit, unsigned indexToSearchFrom)
-    {
-        unsigned index = indexToSearchFrom;
-        ASSERT(m_block-&gt;at(index)-&gt;origin.forExit == originForExit);
-        while (index) {
-            index--;
-            if (m_block-&gt;at(index)-&gt;origin.forExit != originForExit) {
-                index++;
-                break;
-            }
-        }
-        ASSERT(m_block-&gt;at(index)-&gt;origin.forExit == originForExit);
-        return index;
-    }
-    
</del><span class="cx">     void fixupNode(Node* node)
</span><span class="cx">     {
</span><span class="cx">         NodeType op = node-&gt;op();
</span><span class="lines">@@ -1782,19 +1755,7 @@
</span><span class="cx">     void insertCheck(unsigned indexInBlock, Node* node)
</span><span class="cx">     {
</span><span class="cx">         observeUseKindOnNode&lt;useKind&gt;(node);
</span><del>-        CodeOrigin&amp; checkedNodeOrigin = node-&gt;origin.forExit;
-        CodeOrigin&amp; currentNodeOrigin = m_currentNode-&gt;origin.forExit;
-        if (currentNodeOrigin == checkedNodeOrigin) {
-            // The checked node is within the same bytecode. Hence, the earliest
-            // position we can insert the check is right after the checked node.
-            indexInBlock = indexOfNode(node, indexInBlock) + 1;
-        } else {
-            // The checked node is from a preceding bytecode. Hence, the earliest
-            // position we can insert the check is at the start of the current
-            // bytecode.
-            indexInBlock = indexOfFirstNodeOfExitOrigin(currentNodeOrigin, indexInBlock);
-        }
-        m_insertionSet.insertOutOfOrderNode(
</del><ins>+        m_insertionSet.insertNode(
</ins><span class="cx">             indexInBlock, SpecNone, Check, m_currentNode-&gt;origin, Edge(node, useKind));
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGInsertionSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGInsertionSet.h (181816 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGInsertionSet.h        2015-03-20 23:09:56 UTC (rev 181816)
+++ trunk/Source/JavaScriptCore/dfg/DFGInsertionSet.h        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -125,32 +125,6 @@
</span><span class="cx">         return insertConstantForUse(index, origin, jsUndefined(), useKind);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* insertOutOfOrder(const Insertion&amp; insertion)
-    {
-        size_t targetIndex = insertion.index();
-        size_t entry = m_insertions.size();
-        while (entry) {
-            entry--;
-            if (m_insertions[entry].index() &lt;= targetIndex) {
-                entry++;
-                break;
-            }
-        }
-        m_insertions.insert(entry, insertion);
-        return insertion.element();
-    }
-    
-    Node* insertOutOfOrder(size_t index, Node* element)
-    {
-        return insertOutOfOrder(Insertion(index, element));
-    }
-
-    template&lt;typename... Params&gt;
-    Node* insertOutOfOrderNode(size_t index, SpeculatedType type, Params... params)
-    {
-        return insertOutOfOrder(index, m_graph.addNode(type, params...));
-    }
-
</del><span class="cx">     void execute(BasicBlock* block)
</span><span class="cx">     {
</span><span class="cx">         executeInsertions(*block, m_insertions);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressmaterializepastbutterflyallocationjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/materialize-past-butterfly-allocation.js (0 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/materialize-past-butterfly-allocation.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/materialize-past-butterfly-allocation.js        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -0,0 +1,89 @@
</span><ins>+function bar() {
+    return {f:42};
+}
+
+noInline(bar);
+
+function foo0(b) {
+    var o = {f:42};
+    if (b) {
+        var p = bar();
+        p.g = o;
+        return p;
+    }
+}
+
+function foo1(b) {
+    var o = {f:42};
+    if (b) {
+        var p = bar();
+        p.f1 = 1;
+        p.g = o;
+        return p;
+    }
+}
+
+function foo2(b) {
+    var o = {f:42};
+    if (b) {
+        var p = bar();
+        p.f1 = 1;
+        p.f2 = 2;
+        p.g = o;
+        return p;
+    }
+}
+
+function foo3(b) {
+    var o = {f:42};
+    if (b) {
+        var p = bar();
+        p.f1 = 1;
+        p.f2 = 2;
+        p.f3 = 3;
+        p.g = o;
+        return p;
+    }
+}
+
+function foo4(b) {
+    var o = {f:42};
+    if (b) {
+        var p = bar();
+        p.f1 = 1;
+        p.f2 = 2;
+        p.f3 = 3;
+        p.f4 = 4;
+        p.g = o;
+        return p;
+    }
+}
+
+noInline(foo0);
+noInline(foo1);
+noInline(foo2);
+noInline(foo3);
+noInline(foo4);
+
+var array = new Array(1000);
+for (var i = 0; i &lt; 4000000; ++i) {
+    var o = foo0(true);
+    array[i % array.length] = o;
+}
+for (var i = 0; i &lt; 4000000; ++i) {
+    var o = foo1(true);
+    array[i % array.length] = o;
+}
+for (var i = 0; i &lt; 4000000; ++i) {
+    var o = foo2(true);
+    array[i % array.length] = o;
+}
+for (var i = 0; i &lt; 4000000; ++i) {
+    var o = foo3(true);
+    array[i % array.length] = o;
+}
+for (var i = 0; i &lt; 4000000; ++i) {
+    var o = foo4(true);
+    array[i % array.length] = o;
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressmaterializepastputstructurejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/materialize-past-put-structure.js (0 => 181817)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/materialize-past-put-structure.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/materialize-past-put-structure.js        2015-03-20 23:26:26 UTC (rev 181817)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+function foo(p) {
+    var o = {f:42};
+    if (p)
+        return {f:42, g:o};
+}
+
+noInline(foo);
+
+var array = new Array(1000);
+for (var i = 0; i &lt; 4000000; ++i) {
+    var o = foo(true);
+    array[i % array.length] = o;
+}
+
</ins></span></pre>
</div>
</div>

</body>
</html>