<!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>[208377] 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/208377">208377</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2016-11-03 23:18:01 -0700 (Thu, 03 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>ClonedArguments need to also support haveABadTime mode.
https://bugs.webkit.org/show_bug.cgi?id=164200
&lt;rdar://problem/27211336&gt;

Reviewed by Geoffrey Garen.

JSTests:

* stress/have-a-bad-time-with-arguments.js: Added.

Source/JavaScriptCore:

For those who are not familiar with the parlance, &quot;have a bad time&quot; in the VM
means that Object.prototype has been modified in such a way that we can no longer
trivially do indexed property accesses without consulting the Object.prototype.
This defeats JIT indexed put optimizations, and hence, makes the VM &quot;have a
bad time&quot;.

Once the VM enters haveABadTime mode, all existing objects are converted to use
slow put storage.  Thereafter, JSArrays are always created with slow put storage.
JSObjects are always created with a blank indexing type.  When a new indexed
property is put into the new object, its indexing type will be converted to the
slow put array indexing type just before we perform the put operation.  This is
how we ensure that the objects will also use slow put storage.

However, ClonedArguments is an object which was previously created unconditionally
to use contiguous storage.  Subsequently, if we try to call Object.preventExtensions()
on that ClonedArguments object, Object.preventExtensions() will:
1. make the ClonedArguments enter dictionary indexing mode, which means it will
2. first ensure that the ClonedArguments is using slow put array storage via
   JSObject::ensureArrayStorageSlow().

However, JSObject::ensureArrayStorageSlow() expects that we never see an object
with contiguous storage once we're in haveABadTime mode.  Our ClonedArguments
object did not obey this invariant.

The fix is to make the ClonedArguments factories create objects that use slow put
array storage when in haveABadTime mode.  This means:

1. JSGlobalObject::haveABadTime() now changes m_clonedArgumentsStructure to use
   its slow put version.

   Also the caching of the slow put version of m_regExpMatchesArrayStructure,
   because we only need to create it when we are having a bad time. 

2. The ClonedArguments factories now allocates a butterfly with slow put array
   storage if we're in haveABadTime mode.

   Also added some assertions in ClonedArguments' factory methods to ensure that
   the created object has the slow put indexing type when it needsSlowPutIndexing().

3. DFGFixupPhase now watches the havingABadTimeWatchpoint because ClonedArguments'
   structure will change when having a bad time.

4. DFGArgumentEliminationPhase and DFGVarargsForwardingPhase need not be changed
   because it is still valid to eliminate the creation of the arguments object
   even having a bad time, as long as the arguments object does not escape.

5. The DFGAbstractInterpreterInlines now checks for haveABadTime, and sets the
   predicted type to be SpecObject.

Note: this issue does not apply to DirectArguments and ScopedArguments because
they use a blank indexing type (just like JSObject).

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::dump):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* runtime/ClonedArguments.cpp:
(JSC::ClonedArguments::createEmpty):
(JSC::ClonedArguments::createWithInlineFrame):
(JSC::ClonedArguments::createWithMachineFrame):
(JSC::ClonedArguments::createByCopyingFrom):
(JSC::ClonedArguments::createStructure):
(JSC::ClonedArguments::createSlowPutStructure):
* runtime/ClonedArguments.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::haveABadTime):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGArrayModecpp">trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeClonedArgumentscpp">trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeClonedArgumentsh">trunk/Source/JavaScriptCore/runtime/ClonedArguments.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjecth">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstresshaveabadtimewithargumentsjs">trunk/JSTests/stress/have-a-bad-time-with-arguments.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/JSTests/ChangeLog        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-11-03  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        ClonedArguments need to also support haveABadTime mode.
+        https://bugs.webkit.org/show_bug.cgi?id=164200
+        &lt;rdar://problem/27211336&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        * stress/have-a-bad-time-with-arguments.js: Added.
+
</ins><span class="cx"> 2016-11-03  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         DFG plays fast and loose with the shadow values of a Phi
</span></span></pre></div>
<a id="trunkJSTestsstresshaveabadtimewithargumentsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/have-a-bad-time-with-arguments.js (0 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/have-a-bad-time-with-arguments.js                                (rev 0)
+++ trunk/JSTests/stress/have-a-bad-time-with-arguments.js        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -0,0 +1,140 @@
</span><ins>+//@ runFTLNoCJIT
+
+// Tests accessing an element in arguments before and after having a bad time.
+// This test should not crash.
+
+let verbose = false;
+
+var utilities =                 'function shouldEqual(testId, actual, expected) {' + '\n' +
+                                '    if (actual != expected)' + '\n' +
+                                '        throw testId + &quot;: ERROR: expect &quot; + expected + &quot;, actual &quot; + actual;' + '\n' +
+                                '}' + '\n';
+
+var haveABadTime =              'Object.defineProperty(Object.prototype, 20, { get() { return 20; } });' + '\n';
+
+var directArgumentsDecl =       '    var args = arguments;' + '\n';
+
+var scopedArgumentsDecl =       '    var args = arguments;' + '\n' +
+                                '    function closure() { return x; }' + '\n';
+
+var clonedArgumentsDecl =       '    &quot;use strict&quot;;' + '\n' +
+                                '    var args = arguments;' + '\n';
+
+function testFunction(argsDecl, insertElementAction, indexToReturn) {
+    var script =                'function test(x) {' + '\n' +
+                                     argsDecl +
+                                     insertElementAction +
+                                '    return args[' + indexToReturn + '];' + '\n' +
+                                '}' + '\n' +
+                                'noInline(test);' + '\n';
+    return script;
+}
+
+function warmupFunction(tierWarmupCount, testArgs) {
+    var script =                'function warmup() {' + '\n' +
+                                '    for (var i = 0; i &lt; ' + tierWarmupCount + '; i++) {' + '\n' +
+                                '        test(' + testArgs + ');' + '\n' +
+                                '    }' + '\n' +
+                                '}' + '\n';
+    return script;
+}
+
+let argumentsDecls = {
+    direct: directArgumentsDecl,
+    scoped: scopedArgumentsDecl,
+    cloned: clonedArgumentsDecl
+};
+
+let indicesToReturn = {
+    inBounds: 0,
+    outOfBoundsInsertedElement: 10,
+    outOfBoundsInPrototype: 20
+};
+
+let tierWarmupCounts = {
+    llint: 1,
+    baseline: 50,
+    dfg: 1000,
+    ftl: 10000
+};
+
+let testArgsList = {
+    noArgs:   {
+        args: '',
+        result: {
+            inBounds: { beforeBadTime: 'undefined', afterBadTime: 'undefined', },
+            outOfBoundsInsertedElement: { beforeBadTime: '10', afterBadTime: '10', },
+            outOfBoundsInPrototype: { beforeBadTime: 'undefined', afterBadTime: '20', },
+        }
+    },
+    someArgs: {
+        args: '1, 2, 3',
+        result: {
+            inBounds: { beforeBadTime: '1', afterBadTime: '1', },
+            outOfBoundsInsertedElement: { beforeBadTime: '10', afterBadTime: '10', },
+            outOfBoundsInPrototype: { beforeBadTime: 'undefined', afterBadTime: '20', },
+        }
+    }
+};
+
+let insertElementActions = {
+    insertElement:      '    args[10] = 10;' + '\n',
+    dontInsertElement:  ''
+};
+
+for (let argsDeclIndex in argumentsDecls) {
+    let argsDecl = argumentsDecls[argsDeclIndex];
+
+    for (let indexToReturnIndex in indicesToReturn) {
+        let indexToReturn = indicesToReturn[indexToReturnIndex];
+
+        for (let insertElementActionIndex in insertElementActions) {
+            let insertElementAction = insertElementActions[insertElementActionIndex];
+
+            for (let tierWarmupCountIndex in tierWarmupCounts) {
+                let tierWarmupCount = tierWarmupCounts[tierWarmupCountIndex];
+
+                for (let testArgsIndex in testArgsList) {
+                    let testArgs = testArgsList[testArgsIndex].args;
+                    let expectedResult = testArgsList[testArgsIndex].result[indexToReturnIndex];
+
+                    if (indexToReturnIndex == 'outOfBoundsInsertedElement'
+                        &amp;&amp; insertElementActionIndex == 'dontInsertElement')
+                        expectedResult = 'undefined';
+
+                    let testName =
+                        argsDeclIndex + '-' +
+                        indexToReturnIndex + '-' +
+                        insertElementActionIndex + '-' +
+                        tierWarmupCountIndex + '-' +
+                        testArgsIndex;
+
+
+                    let script = utilities +
+                                 testFunction(argsDecl, insertElementAction, indexToReturn) +
+                                 warmupFunction(tierWarmupCount, testArgs) +
+                                 'warmup()' + '\n' +
+                                 'shouldEqual(10000, test(' + testArgs + '), ' + expectedResult['beforeBadTime'] + ');' + '\n';
+                                 haveABadTime +
+                                 'shouldEqual(20000, test(' + testArgs + '), ' + expectedResult['afterBadTime'] + ');' + '\n';
+
+                    if (verbose) {
+                        print('Running test configuration: ' + testName);
+                        print(
+                            'Test script: ====================================================\n' +
+                            script +
+                            '=== END script ==================================================');
+                    }
+
+                    try {
+                        runString(script);
+                    } catch (e) {
+                        print('FAILED test configuration: ' + testName);
+                        print('FAILED test script:\n' + script);
+                        throw e;
+                    }
+                }
+            }
+        }
+    }
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -1,3 +1,83 @@
</span><ins>+2016-11-03  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        ClonedArguments need to also support haveABadTime mode.
+        https://bugs.webkit.org/show_bug.cgi?id=164200
+        &lt;rdar://problem/27211336&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        For those who are not familiar with the parlance, &quot;have a bad time&quot; in the VM
+        means that Object.prototype has been modified in such a way that we can no longer
+        trivially do indexed property accesses without consulting the Object.prototype.
+        This defeats JIT indexed put optimizations, and hence, makes the VM &quot;have a
+        bad time&quot;.
+
+        Once the VM enters haveABadTime mode, all existing objects are converted to use
+        slow put storage.  Thereafter, JSArrays are always created with slow put storage.
+        JSObjects are always created with a blank indexing type.  When a new indexed
+        property is put into the new object, its indexing type will be converted to the
+        slow put array indexing type just before we perform the put operation.  This is
+        how we ensure that the objects will also use slow put storage.
+
+        However, ClonedArguments is an object which was previously created unconditionally
+        to use contiguous storage.  Subsequently, if we try to call Object.preventExtensions()
+        on that ClonedArguments object, Object.preventExtensions() will:
+        1. make the ClonedArguments enter dictionary indexing mode, which means it will
+        2. first ensure that the ClonedArguments is using slow put array storage via
+           JSObject::ensureArrayStorageSlow().
+
+        However, JSObject::ensureArrayStorageSlow() expects that we never see an object
+        with contiguous storage once we're in haveABadTime mode.  Our ClonedArguments
+        object did not obey this invariant.
+
+        The fix is to make the ClonedArguments factories create objects that use slow put
+        array storage when in haveABadTime mode.  This means:
+
+        1. JSGlobalObject::haveABadTime() now changes m_clonedArgumentsStructure to use
+           its slow put version.
+
+           Also the caching of the slow put version of m_regExpMatchesArrayStructure,
+           because we only need to create it when we are having a bad time. 
+
+        2. The ClonedArguments factories now allocates a butterfly with slow put array
+           storage if we're in haveABadTime mode.
+
+           Also added some assertions in ClonedArguments' factory methods to ensure that
+           the created object has the slow put indexing type when it needsSlowPutIndexing().
+
+        3. DFGFixupPhase now watches the havingABadTimeWatchpoint because ClonedArguments'
+           structure will change when having a bad time.
+
+        4. DFGArgumentEliminationPhase and DFGVarargsForwardingPhase need not be changed
+           because it is still valid to eliminate the creation of the arguments object
+           even having a bad time, as long as the arguments object does not escape.
+
+        5. The DFGAbstractInterpreterInlines now checks for haveABadTime, and sets the
+           predicted type to be SpecObject.
+
+        Note: this issue does not apply to DirectArguments and ScopedArguments because
+        they use a blank indexing type (just like JSObject).
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::dump):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * runtime/ClonedArguments.cpp:
+        (JSC::ClonedArguments::createEmpty):
+        (JSC::ClonedArguments::createWithInlineFrame):
+        (JSC::ClonedArguments::createWithMachineFrame):
+        (JSC::ClonedArguments::createByCopyingFrom):
+        (JSC::ClonedArguments::createStructure):
+        (JSC::ClonedArguments::createSlowPutStructure):
+        * runtime/ClonedArguments.h:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::haveABadTime):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+
</ins><span class="cx"> 2016-11-03  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         DFG plays fast and loose with the shadow values of a Phi
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -1981,6 +1981,10 @@
</span><span class="cx">         break;
</span><span class="cx">         
</span><span class="cx">     case CreateClonedArguments:
</span><ins>+        if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
+            forNode(node).setType(m_graph, SpecObject);
+            break;
+        }
</ins><span class="cx">         forNode(node).set(m_graph, m_codeBlock-&gt;globalObjectFor(node-&gt;origin.semantic)-&gt;clonedArgumentsStructure());
</span><span class="cx">         break;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGArrayModecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -734,7 +734,7 @@
</span><span class="cx"> 
</span><span class="cx"> void ArrayMode::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><del>-    out.print(type(), arrayClass(), speculation(), conversion());
</del><ins>+    out.print(type(), &quot;+&quot;, arrayClass(), &quot;+&quot;, speculation(), &quot;+&quot;, conversion());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -1550,6 +1550,11 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case CreateClonedArguments: {
+            watchHavingABadTime(node);
+            break;
+        }
+
</ins><span class="cx">         case CreateScopedArguments:
</span><span class="cx">         case CreateActivation:
</span><span class="cx">         case NewFunction:
</span><span class="lines">@@ -1776,7 +1781,6 @@
</span><span class="cx">         case IsObjectOrNull:
</span><span class="cx">         case IsFunction:
</span><span class="cx">         case CreateDirectArguments:
</span><del>-        case CreateClonedArguments:
</del><span class="cx">         case Jump:
</span><span class="cx">         case Return:
</span><span class="cx">         case TailCall:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -32,7 +32,6 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;BatchedTransitionOptimizer.h&quot;
</span><span class="cx"> #include &quot;CallFrameClosure.h&quot;
</span><del>-#include &quot;ClonedArguments.h&quot;
</del><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;DirectArguments.h&quot;
</span><span class="cx"> #include &quot;Heap.h&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeClonedArgumentscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/runtime/ClonedArguments.cpp        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -48,16 +48,23 @@
</span><span class="cx">     if (vectorLength &gt; MAX_STORAGE_VECTOR_LENGTH)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    void* temp = vm.heap.tryAllocateAuxiliary(nullptr, Butterfly::totalSize(0, structure-&gt;outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)));
-    if (!temp)
-        return 0;
-    Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure-&gt;outOfLineCapacity());
-    butterfly-&gt;setVectorLength(vectorLength);
-    butterfly-&gt;setPublicLength(length);
</del><ins>+    Butterfly* butterfly;
+    if (UNLIKELY(structure-&gt;needsSlowPutIndexing())) {
+        butterfly = createArrayStorageButterfly(vm, nullptr, structure, length, vectorLength);
+        butterfly-&gt;arrayStorage()-&gt;m_numValuesInVector = vectorLength;
+
+    } else {
+        void* temp = vm.heap.tryAllocateAuxiliary(nullptr, Butterfly::totalSize(0, structure-&gt;outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)));
+        if (!temp)
+            return 0;
+        butterfly = Butterfly::fromBase(temp, 0, structure-&gt;outOfLineCapacity());
+        butterfly-&gt;setVectorLength(vectorLength);
+        butterfly-&gt;setPublicLength(length);
+        
+        for (unsigned i = length; i &lt; vectorLength; ++i)
+            butterfly-&gt;contiguous()[i].clear();
+    }
</ins><span class="cx">     
</span><del>-    for (unsigned i = length; i &lt; vectorLength; ++i)
-        butterfly-&gt;contiguous()[i].clear();
-
</del><span class="cx">     ClonedArguments* result =
</span><span class="cx">         new (NotNull, allocateCell&lt;ClonedArguments&gt;(vm.heap))
</span><span class="cx">         ClonedArguments(vm, structure, butterfly);
</span><span class="lines">@@ -70,9 +77,12 @@
</span><span class="cx"> 
</span><span class="cx"> ClonedArguments* ClonedArguments::createEmpty(ExecState* exec, JSFunction* callee, unsigned length)
</span><span class="cx"> {
</span><ins>+    VM&amp; vm = exec-&gt;vm();
</ins><span class="cx">     // NB. Some clients might expect that the global object of of this object is the global object
</span><span class="cx">     // of the callee. We don't do this for now, but maybe we should.
</span><del>-    return createEmpty(exec-&gt;vm(), exec-&gt;lexicalGlobalObject()-&gt;clonedArgumentsStructure(), callee, length);
</del><ins>+    ClonedArguments* result = createEmpty(vm, exec-&gt;lexicalGlobalObject()-&gt;clonedArgumentsStructure(), callee, length);
+    ASSERT(!result-&gt;structure(vm)-&gt;needsSlowPutIndexing() || shouldUseSlowPut(result-&gt;structure(vm)-&gt;indexingType()));
+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ClonedArguments* ClonedArguments::createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode)
</span><span class="lines">@@ -117,12 +127,15 @@
</span><span class="cx">     } }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(myFrame-&gt;lexicalGlobalObject()-&gt;clonedArgumentsStructure() == result-&gt;structure());
</span><ins>+    ASSERT(!result-&gt;structure(vm)-&gt;needsSlowPutIndexing() || shouldUseSlowPut(result-&gt;structure(vm)-&gt;indexingType()));
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ClonedArguments* ClonedArguments::createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode mode)
</span><span class="cx"> {
</span><del>-    return createWithInlineFrame(myFrame, targetFrame, nullptr, mode);
</del><ins>+    ClonedArguments* result = createWithInlineFrame(myFrame, targetFrame, nullptr, mode);
+    ASSERT(!result-&gt;structure()-&gt;needsSlowPutIndexing() || shouldUseSlowPut(result-&gt;structure()-&gt;indexingType()));
+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ClonedArguments* ClonedArguments::createByCopyingFrom(
</span><span class="lines">@@ -134,15 +147,13 @@
</span><span class="cx">     
</span><span class="cx">     for (unsigned i = length; i--;)
</span><span class="cx">         result-&gt;initializeIndex(vm, i, argumentStart[i].jsValue());
</span><del>-
</del><ins>+    ASSERT(!result-&gt;structure(vm)-&gt;needsSlowPutIndexing() || shouldUseSlowPut(result-&gt;structure(vm)-&gt;indexingType()));
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Structure* ClonedArguments::createStructure(VM&amp; vm, JSGlobalObject* globalObject, JSValue prototype)
</del><ins>+Structure* ClonedArguments::createStructure(VM&amp; vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
</ins><span class="cx"> {
</span><del>-    // We use contiguous storage because optimizations in the FTL assume that cloned arguments creation always produces the same initial structure.
-
-    Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), NonArrayWithContiguous);
</del><ins>+    Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), indexingType);
</ins><span class="cx">     PropertyOffset offset;
</span><span class="cx">     structure = structure-&gt;addPropertyTransition(vm, structure, vm.propertyNames-&gt;length, DontEnum, offset);
</span><span class="cx">     ASSERT(offset == clonedArgumentsLengthPropertyOffset);
</span><span class="lines">@@ -149,6 +160,17 @@
</span><span class="cx">     return structure;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Structure* ClonedArguments::createStructure(VM&amp; vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    // We use contiguous storage because optimizations in the FTL assume that cloned arguments creation always produces the same initial structure.
+    return createStructure(vm, globalObject, prototype, NonArrayWithContiguous);
+}
+
+Structure* ClonedArguments::createSlowPutStructure(VM&amp; vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return createStructure(vm, globalObject, prototype, NonArrayWithSlowPutArrayStorage);
+}
+
</ins><span class="cx"> bool ClonedArguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot&amp; slot)
</span><span class="cx"> {
</span><span class="cx">     ClonedArguments* thisObject = jsCast&lt;ClonedArguments*&gt;(object);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeClonedArgumentsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ClonedArguments.h (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ClonedArguments.h        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/runtime/ClonedArguments.h        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 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">@@ -53,6 +53,7 @@
</span><span class="cx">     static ClonedArguments* createByCopyingFrom(ExecState*, Structure*, Register* argumentsStart, unsigned length, JSFunction* callee);
</span><span class="cx">     
</span><span class="cx">     static Structure* createStructure(VM&amp;, JSGlobalObject*, JSValue prototype);
</span><ins>+    static Structure* createSlowPutStructure(VM&amp;, JSGlobalObject*, JSValue prototype);
</ins><span class="cx"> 
</span><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -59,6 +60,8 @@
</span><span class="cx">     DECLARE_INFO;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    static Structure* createStructure(VM&amp;, JSGlobalObject*, JSValue prototype, IndexingType);
+
</ins><span class="cx">     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&amp;);
</span><span class="cx">     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&amp;, EnumerationMode);
</span><span class="cx">     static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -537,7 +537,6 @@
</span><span class="cx">     m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, this, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get())));
</span><span class="cx">     m_regExpStructure.set(vm, this, RegExpObject::createStructure(vm, this, m_regExpPrototype.get()));
</span><span class="cx">     m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, this));
</span><del>-    m_regExpMatchesArraySlowPutStructure.set(vm, this, createRegExpMatchesArraySlowPutStructure(vm, this));
</del><span class="cx"> 
</span><span class="cx">     m_moduleRecordStructure.set(vm, this, JSModuleRecord::createStructure(vm, this, m_objectPrototype.get()));
</span><span class="cx">     m_moduleNamespaceObjectStructure.set(vm, this, JSModuleNamespaceObject::createStructure(vm, this, jsNull()));
</span><span class="lines">@@ -1052,8 +1051,12 @@
</span><span class="cx">         m_arrayStructureForIndexingShapeDuringAllocation[i].set(vm, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage));
</span><span class="cx"> 
</span><span class="cx">     // Same for any special array structures.
</span><del>-    m_regExpMatchesArrayStructure.set(vm, this, m_regExpMatchesArraySlowPutStructure.get());
-    
</del><ins>+    Structure* slowPutStructure;
+    slowPutStructure = createRegExpMatchesArraySlowPutStructure(vm, this);
+    m_regExpMatchesArrayStructure.set(vm, this, slowPutStructure);
+    slowPutStructure = ClonedArguments::createSlowPutStructure(vm, this, m_objectPrototype.get());
+    m_clonedArgumentsStructure.set(vm, this, slowPutStructure);
+
</ins><span class="cx">     // Make sure that all objects that have indexed storage switch to the slow kind of
</span><span class="cx">     // indexed storage.
</span><span class="cx">     MarkedArgumentBuffer foundObjects; // Use MarkedArgumentBuffer because switchToSlowPutArrayStorage() may GC.
</span><span class="lines">@@ -1191,7 +1194,6 @@
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_generatorFunctionStructure);
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_iteratorResultObjectStructure);
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_regExpMatchesArrayStructure);
</span><del>-    visitor.append(&amp;thisObject-&gt;m_regExpMatchesArraySlowPutStructure);
</del><span class="cx">     visitor.append(&amp;thisObject-&gt;m_moduleRecordStructure);
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_moduleNamespaceObjectStructure);
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_dollarVMStructure);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -320,7 +320,6 @@
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_dollarVMStructure;
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_iteratorResultObjectStructure;
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_regExpMatchesArrayStructure;
</span><del>-    WriteBarrier&lt;Structure&gt; m_regExpMatchesArraySlowPutStructure;
</del><span class="cx">     WriteBarrier&lt;Structure&gt; m_moduleRecordStructure;
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_moduleNamespaceObjectStructure;
</span><span class="cx">     WriteBarrier&lt;Structure&gt; m_proxyObjectStructure;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -768,14 +768,10 @@
</span><span class="cx">     return newButterfly-&gt;contiguous();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ArrayStorage* JSObject::createArrayStorage(VM&amp; vm, unsigned length, unsigned vectorLength)
</del><ins>+Butterfly* JSObject::createArrayStorageButterfly(VM&amp; vm, JSCell* intendedOwner, Structure* structure, unsigned length, unsigned vectorLength, Butterfly* oldButterfly)
</ins><span class="cx"> {
</span><del>-    DeferGC deferGC(vm.heap);
-    Structure* structure = this-&gt;structure(vm);
-    IndexingType oldType = indexingType();
-    ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
</del><span class="cx">     Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
</span><del>-        m_butterfly.get(), vm, this, structure, structure-&gt;outOfLineCapacity(), false, 0,
</del><ins>+        oldButterfly, vm, intendedOwner, structure, structure-&gt;outOfLineCapacity(), false, 0,
</ins><span class="cx">         ArrayStorage::sizeFor(vectorLength));
</span><span class="cx">     RELEASE_ASSERT(newButterfly);
</span><span class="cx"> 
</span><span class="lines">@@ -787,6 +783,19 @@
</span><span class="cx">     result-&gt;m_indexBias = 0;
</span><span class="cx">     for (size_t i = vectorLength; i--;)
</span><span class="cx">         result-&gt;m_vector[i].setWithoutWriteBarrier(JSValue());
</span><ins>+
+    return newButterfly;
+}
+
+ArrayStorage* JSObject::createArrayStorage(VM&amp; vm, unsigned length, unsigned vectorLength)
+{
+    DeferGC deferGC(vm.heap);
+    Structure* structure = this-&gt;structure(vm);
+    IndexingType oldType = indexingType();
+    ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
+
+    Butterfly* newButterfly = createArrayStorageButterfly(vm, this, structure, length, vectorLength, m_butterfly.get());
+    ArrayStorage* result = newButterfly-&gt;arrayStorage();
</ins><span class="cx">     Structure* newStructure = Structure::nonPropertyTransition(vm, structure, structure-&gt;suggestedArrayStorageTransition());
</span><span class="cx">     setStructureAndButterfly(vm, newStructure, newButterfly);
</span><span class="cx">     return result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (208376 => 208377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-11-04 05:33:49 UTC (rev 208376)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-11-04 06:18:01 UTC (rev 208377)
</span><span class="lines">@@ -902,6 +902,7 @@
</span><span class="cx">     void createInitialForValueAndSet(VM&amp;, unsigned index, JSValue);
</span><span class="cx">     void convertInt32ForValue(VM&amp;, JSValue);
</span><span class="cx">         
</span><ins>+    static Butterfly* createArrayStorageButterfly(VM&amp;, JSCell* intendedOwner, Structure*, unsigned length, unsigned vectorLength, Butterfly* oldButterfly = nullptr);
</ins><span class="cx">     ArrayStorage* createArrayStorage(VM&amp;, unsigned length, unsigned vectorLength);
</span><span class="cx">     ArrayStorage* createInitialArrayStorage(VM&amp;);
</span><span class="cx">         
</span></span></pre>
</div>
</div>

</body>
</html>