Title: [164738] trunk
Revision
164738
Author
[email protected]
Date
2014-02-26 12:40:46 -0800 (Wed, 26 Feb 2014)

Log Message

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/_javascript_Core:

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):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (164737 => 164738)


--- trunk/LayoutTests/ChangeLog	2014-02-26 20:39:06 UTC (rev 164737)
+++ trunk/LayoutTests/ChangeLog	2014-02-26 20:40:46 UTC (rev 164738)
@@ -1,3 +1,19 @@
+2014-02-26  Oliver Hunt  <[email protected]>
+
+        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):
+
 2014-02-26  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Remove console.profiles from window.console API

Added: trunk/LayoutTests/js/regress/call-spread-apply-expected.txt (0 => 164738)


--- 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)
@@ -0,0 +1,10 @@
+JSRegress/call-spread-apply
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/call-spread-apply.html (0 => 164738)


--- 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)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/script-tests/call-spread-apply.js (0 => 164738)


--- 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)
@@ -0,0 +1,48 @@
+
+Function.prototype.a = Function.prototype.apply;
+
+function testFunction(a, b)
+{
+    "use strict"
+    return this * 10000 + a * 1000 + b * 100 + arguments[2] * 10 + arguments.length;
+}
+
+var arrayArguments = [1, [2, 3, 4]]
+
+for (var i = 0; i < 10000; i++) {
+    var result1 = testFunction.apply(...arrayArguments);
+    var result2 = testFunction.a(...arrayArguments);
+    if (result1 != result2) 
+        throw "Call with spread array failed at iteration " + i + ": " + result1 + " vs " + result2;
+}
+
+for (var i = 0; i < 10000; i++) {
+    var result1 = testFunction.apply(...[1, [2, 3, 4]]);
+    var result2 = testFunction.a(...[1, [2, 3, 4]]);
+    if (result1 != result2) 
+        throw "Call with spread array failed at iteration " + i + ": " + result1 + " vs " + result2;
+}
+
+function test2() {
+    for (var i = 0; i < 10000; i++) {
+        var result1 = testFunction.apply(...arguments);
+        var result2 = testFunction.a(...arguments);
+        if (result1 != result2)
+           throw "Call with spread arguments failed at iteration " + i + ": " + result1 + " vs " + result2;
+    }
+}
+
+test2(1,[2,3,4])
+
+
+function test3() {
+    aliasedArguments = arguments;
+    for (var i = 0; i < 10000; i++) {
+        var result1 = testFunction.apply(...aliasedArguments);
+        var result2 = testFunction.a(...aliasedArguments);
+        if (result1 != result2)
+           throw "Call with spread arguments failed at iteration " + i + ": " + result1 + " vs " + result2;
+    }
+}
+
+test3(1,[2,3,4])
\ No newline at end of file

Modified: trunk/Source/_javascript_Core/ChangeLog (164737 => 164738)


--- trunk/Source/_javascript_Core/ChangeLog	2014-02-26 20:39:06 UTC (rev 164737)
+++ trunk/Source/_javascript_Core/ChangeLog	2014-02-26 20:40:46 UTC (rev 164738)
@@ -1,3 +1,18 @@
+2014-02-26  Oliver Hunt  <[email protected]>
+
+        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):
+
 2014-02-26  Mark Lam  <[email protected]>
 
         Compilation policy management belongs in operationOptimize(), not the DFG Driver.

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (164737 => 164738)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2014-02-26 20:39:06 UTC (rev 164737)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2014-02-26 20:40:46 UTC (rev 164738)
@@ -626,7 +626,36 @@
     if (mayBeCall) {
         if (m_args->m_listNode && m_args->m_listNode->m_expr) {
             ArgumentListNode* oldList = m_args->m_listNode;
-            if (m_args->m_listNode->m_next) {
+            if (m_args->m_listNode->m_expr->isSpreadExpression()) {
+                SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr);
+                RefPtr<RegisterID> profileHookRegister;
+                if (generator.shouldEmitProfileHooks())
+                    profileHookRegister = generator.newTemporary();
+                RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get());
+                RefPtr<RegisterID> index = generator.emitLoad(generator.newTemporary(), jsNumber(0));
+                RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsUndefined());
+                RefPtr<RegisterID> argumentsRegister = generator.emitLoad(generator.newTemporary(), jsUndefined());
+                
+                auto extractor = [&thisRegister, &argumentsRegister, &index](BytecodeGenerator& generator, RegisterID* value)
+                {
+                    RefPtr<Label> haveThis = generator.newLabel();
+                    RefPtr<Label> end = generator.newLabel();
+                    RefPtr<RegisterID> compareResult = generator.newTemporary();
+                    RefPtr<RegisterID> 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<RegisterID> 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->_expression_(), extractor);
+                generator.emitCallVarargs(returnValue.get(), realFunction.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 0, profileHookRegister.get(), divot(), divotStart(), divotEnd());
+            } else if (m_args->m_listNode->m_next) {
                 ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray());
                 ASSERT(!m_args->m_listNode->m_next->m_next);
                 m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.vm(), 0, 0);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to