<!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>[164738] 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/164738">164738</a></dd>
<dt>Author</dt> <dd>oliver@apple.com</dd>
<dt>Date</dt> <dd>2014-02-26 12:40:46 -0800 (Wed, 26 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Function.prototype.apply has a bad time with the spread operator
https://bugs.webkit.org/show_bug.cgi?id=129381

Reviewed by Mark Hahnenberg.

Source/JavaScriptCore:

Make sure our apply logic handle the spread operator correctly.
To do this we simply emit the enumeration logic that we'd normally
use for other enumerations, but only store the first two results
to registers.  Then perform a varargs call.

* bytecompiler/NodesCodegen.cpp:
(JSC::ApplyFunctionCallDotNode::emitBytecode):

LayoutTests:

Add tests

* js/regress/call-spread-apply-expected.txt: Added.
* js/regress/call-spread-apply.html: Added.
* js/regress/script-tests/call-spread-apply.js: Added.
(testFunction):
(test2):
(test3):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregresscallspreadapplyexpectedtxt">trunk/LayoutTests/js/regress/call-spread-apply-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregresscallspreadapplyhtml">trunk/LayoutTests/js/regress/call-spread-apply.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestscallspreadapplyjs">trunk/LayoutTests/js/regress/script-tests/call-spread-apply.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (164737 => 164738)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-26 20:39:06 UTC (rev 164737)
+++ trunk/LayoutTests/ChangeLog        2014-02-26 20:40:46 UTC (rev 164738)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2014-02-26  Oliver Hunt  &lt;oliver@apple.com&gt;
+
+        Function.prototype.apply has a bad time with the spread operator
+        https://bugs.webkit.org/show_bug.cgi?id=129381
+
+        Reviewed by Mark Hahnenberg.
+
+        Add tests
+
+        * js/regress/call-spread-apply-expected.txt: Added.
+        * js/regress/call-spread-apply.html: Added.
+        * js/regress/script-tests/call-spread-apply.js: Added.
+        (testFunction):
+        (test2):
+        (test3):
+
</ins><span class="cx"> 2014-02-26  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Remove console.profiles from window.console API
</span></span></pre></div>
<a id="trunkLayoutTestsjsregresscallspreadapplyexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/call-spread-apply-expected.txt (0 => 164738)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/call-spread-apply-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/call-spread-apply-expected.txt        2014-02-26 20:40:46 UTC (rev 164738)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/call-spread-apply
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregresscallspreadapplyhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/call-spread-apply.html (0 => 164738)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/call-spread-apply.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/call-spread-apply.html        2014-02-26 20:40:46 UTC (rev 164738)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/call-spread-call.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestscallspreadapplyjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/call-spread-apply.js (0 => 164738)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/call-spread-apply.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/call-spread-apply.js        2014-02-26 20:40:46 UTC (rev 164738)
</span><span class="lines">@@ -0,0 +1,48 @@
</span><ins>+
+Function.prototype.a = Function.prototype.apply;
+
+function testFunction(a, b)
+{
+    &quot;use strict&quot;
+    return this * 10000 + a * 1000 + b * 100 + arguments[2] * 10 + arguments.length;
+}
+
+var arrayArguments = [1, [2, 3, 4]]
+
+for (var i = 0; i &lt; 10000; i++) {
+    var result1 = testFunction.apply(...arrayArguments);
+    var result2 = testFunction.a(...arrayArguments);
+    if (result1 != result2) 
+        throw &quot;Call with spread array failed at iteration &quot; + i + &quot;: &quot; + result1 + &quot; vs &quot; + result2;
+}
+
+for (var i = 0; i &lt; 10000; i++) {
+    var result1 = testFunction.apply(...[1, [2, 3, 4]]);
+    var result2 = testFunction.a(...[1, [2, 3, 4]]);
+    if (result1 != result2) 
+        throw &quot;Call with spread array failed at iteration &quot; + i + &quot;: &quot; + result1 + &quot; vs &quot; + result2;
+}
+
+function test2() {
+    for (var i = 0; i &lt; 10000; i++) {
+        var result1 = testFunction.apply(...arguments);
+        var result2 = testFunction.a(...arguments);
+        if (result1 != result2)
+           throw &quot;Call with spread arguments failed at iteration &quot; + i + &quot;: &quot; + result1 + &quot; vs &quot; + result2;
+    }
+}
+
+test2(1,[2,3,4])
+
+
+function test3() {
+    aliasedArguments = arguments;
+    for (var i = 0; i &lt; 10000; i++) {
+        var result1 = testFunction.apply(...aliasedArguments);
+        var result2 = testFunction.a(...aliasedArguments);
+        if (result1 != result2)
+           throw &quot;Call with spread arguments failed at iteration &quot; + i + &quot;: &quot; + result1 + &quot; vs &quot; + result2;
+    }
+}
+
+test3(1,[2,3,4])
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (164737 => 164738)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-02-26 20:39:06 UTC (rev 164737)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-02-26 20:40:46 UTC (rev 164738)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2014-02-26  Oliver Hunt  &lt;oliver@apple.com&gt;
+
+        Function.prototype.apply has a bad time with the spread operator
+        https://bugs.webkit.org/show_bug.cgi?id=129381
+
+        Reviewed by Mark Hahnenberg.
+
+        Make sure our apply logic handle the spread operator correctly.
+        To do this we simply emit the enumeration logic that we'd normally
+        use for other enumerations, but only store the first two results
+        to registers.  Then perform a varargs call.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ApplyFunctionCallDotNode::emitBytecode):
+
</ins><span class="cx"> 2014-02-26  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Compilation policy management belongs in operationOptimize(), not the DFG Driver.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (164737 => 164738)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2014-02-26 20:39:06 UTC (rev 164737)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2014-02-26 20:40:46 UTC (rev 164738)
</span><span class="lines">@@ -626,7 +626,36 @@
</span><span class="cx">     if (mayBeCall) {
</span><span class="cx">         if (m_args-&gt;m_listNode &amp;&amp; m_args-&gt;m_listNode-&gt;m_expr) {
</span><span class="cx">             ArgumentListNode* oldList = m_args-&gt;m_listNode;
</span><del>-            if (m_args-&gt;m_listNode-&gt;m_next) {
</del><ins>+            if (m_args-&gt;m_listNode-&gt;m_expr-&gt;isSpreadExpression()) {
+                SpreadExpressionNode* spread = static_cast&lt;SpreadExpressionNode*&gt;(m_args-&gt;m_listNode-&gt;m_expr);
+                RefPtr&lt;RegisterID&gt; profileHookRegister;
+                if (generator.shouldEmitProfileHooks())
+                    profileHookRegister = generator.newTemporary();
+                RefPtr&lt;RegisterID&gt; realFunction = generator.emitMove(generator.newTemporary(), base.get());
+                RefPtr&lt;RegisterID&gt; index = generator.emitLoad(generator.newTemporary(), jsNumber(0));
+                RefPtr&lt;RegisterID&gt; thisRegister = generator.emitLoad(generator.newTemporary(), jsUndefined());
+                RefPtr&lt;RegisterID&gt; argumentsRegister = generator.emitLoad(generator.newTemporary(), jsUndefined());
+                
+                auto extractor = [&amp;thisRegister, &amp;argumentsRegister, &amp;index](BytecodeGenerator&amp; generator, RegisterID* value)
+                {
+                    RefPtr&lt;Label&gt; haveThis = generator.newLabel();
+                    RefPtr&lt;Label&gt; end = generator.newLabel();
+                    RefPtr&lt;RegisterID&gt; compareResult = generator.newTemporary();
+                    RefPtr&lt;RegisterID&gt; indexZeroCompareResult = generator.emitBinaryOp(op_eq, compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(0)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32()));
+                    generator.emitJumpIfFalse(indexZeroCompareResult.get(), haveThis.get());
+                    generator.emitMove(thisRegister.get(), value);
+                    generator.emitLoad(index.get(), jsNumber(1));
+                    generator.emitJump(end.get());
+                    generator.emitLabel(haveThis.get());
+                    RefPtr&lt;RegisterID&gt; indexOneCompareResult = generator.emitBinaryOp(op_eq, compareResult.get(), index.get(), generator.emitLoad(0, jsNumber(1)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32()));
+                    generator.emitJumpIfFalse(indexOneCompareResult.get(), end.get());
+                    generator.emitMove(argumentsRegister.get(), value);
+                    generator.emitLoad(index.get(), jsNumber(2));
+                    generator.emitLabel(end.get());
+                };
+                generator.emitEnumeration(this, spread-&gt;expression(), extractor);
+                generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd());
+            } else if (m_args-&gt;m_listNode-&gt;m_next) {
</ins><span class="cx">                 ASSERT(m_args-&gt;m_listNode-&gt;m_next-&gt;m_expr-&gt;isSimpleArray());
</span><span class="cx">                 ASSERT(!m_args-&gt;m_listNode-&gt;m_next-&gt;m_next);
</span><span class="cx">                 m_args-&gt;m_listNode = static_cast&lt;ArrayNode*&gt;(m_args-&gt;m_listNode-&gt;m_next-&gt;m_expr)-&gt;toArgumentList(generator.vm(), 0, 0);
</span></span></pre>
</div>
</div>

</body>
</html>