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