Title: [192671] trunk
Revision
192671
Author
sbar...@apple.com
Date
2015-11-19 18:37:47 -0800 (Thu, 19 Nov 2015)

Log Message

[ES6] Add support for rest parameters
https://bugs.webkit.org/show_bug.cgi?id=38408

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

This patch implements rest parameters from the ES6 spec.
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-function-definitions

We implement the rest parameter as a new AST node. This AST node
lowers to "op_new_array X, op_copy_rest X". Note
that the op_copy_rest opcode does not have a result.
The bulk of this patch is implementing op_copy_rest.
This patch implements this in all four tiers in a straight forward way.
The opcode is implemented as a C call that will read the pertinent
arguments from the call frame and fill them into the array.

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/Instruction.h:
(JSC::Instruction::Instruction):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
(JSC::BytecodeGenerator::invalidateForInContextForLocal):
(JSC::BytecodeGenerator::emitRestParameter):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::AssignmentElementNode::toString):
(JSC::RestParameterNode::collectBoundIdentifiers):
(JSC::RestParameterNode::toString):
(JSC::RestParameterNode::bindValue):
(JSC::RestParameterNode::emit):
(JSC::SpreadExpressionNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::setEpoch):
(JSC::DFG::Node::numberOfArgumentsToSkip):
(JSC::DFG::Node::dumpChildren):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCreateClonedArguments):
(JSC::DFG::SpeculativeJIT::compileCopyRest):
(JSC::DFG::SpeculativeJIT::compileNotifyWrite):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCreateClonedArguments):
(JSC::FTL::DFG::LowerDFGToLLVM::compileCopyRest):
(JSC::FTL::DFG::LowerDFGToLLVM::compileNewObject):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_create_out_of_band_arguments):
(JSC::JIT::emit_op_copy_rest):
* jit/JITOperations.h:
* llint/LowLevelInterpreter.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createBindingLocation):
(JSC::ASTBuilder::createRestParameter):
(JSC::ASTBuilder::createAssignmentElement):
* parser/NodeConstructors.h:
(JSC::AssignmentElementNode::AssignmentElementNode):
(JSC::RestParameterNode::RestParameterNode):
(JSC::DestructuringAssignmentNode::DestructuringAssignmentNode):
* parser/Nodes.h:
(JSC::DestructuringPatternNode::isBindingNode):
(JSC::DestructuringPatternNode::isRestParameter):
(JSC::DestructuringPatternNode::emitDirectBinding):
(JSC::RestParameterNode::name):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseVariableDeclarationList):
(JSC::Parser<LexerType>::declareRestOrNormalParameter):
(JSC::Parser<LexerType>::createBindingPattern):
(JSC::Parser<LexerType>::parseFormalParameters):
* parser/Parser.h:
(JSC::Parser::strictMode):
(JSC::Parser::isValidStrictMode):
(JSC::Parser::declareParameter):
(JSC::Parser::breakIsValid):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::operatorStackPop):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* tests/es6.yaml:
* tests/stress/rest-parameter-and-default-arguments.js: Added.
(assert):
(shouldThrowTDZ):
(foo):
(baz):
(i.shouldThrowTDZ):
* tests/stress/rest-parameter-basics.js: Added.
(assert):
(foo):
(bar):
(capture):
(baz):
(jaz):
(kaz):
(raz):
(restLength):
(testArgumentsObject):
(strictModeLikeArgumentsObject):
* tests/stress/rest-parameter-inlined.js: Added.
(assert):
(bar):
(foo):
(baz):
(jaz):

LayoutTests:

* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:
(catch):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (192670 => 192671)


--- trunk/LayoutTests/ChangeLog	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/LayoutTests/ChangeLog	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1,3 +1,14 @@
+2015-11-19  Saam barati  <sbar...@apple.com>
+
+        [ES6] Add support for rest parameters
+        https://bugs.webkit.org/show_bug.cgi?id=38408
+
+        Reviewed by Geoffrey Garen.
+
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/parser-syntax-check.js:
+        (catch):
+
 2015-11-19  Ryan Haddad  <ryanhad...@apple.com>
 
         Marking imported/w3c/html-templates/parsing-html-templates/creating-an-element-for-the-token/template-owner-document.html as flaky crasher

Modified: trunk/LayoutTests/js/parser-syntax-check-expected.txt (192670 => 192671)


--- trunk/LayoutTests/js/parser-syntax-check-expected.txt	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt	2015-11-20 02:37:47 UTC (rev 192671)
@@ -929,6 +929,49 @@
 --"
 PASS Invalid: "function f() { 1 % 
 -- }"
+Rest parameter
+PASS Valid:   "function foo(...a) { }"
+PASS Valid:   "function f() { function foo(...a) { } }"
+PASS Valid:   "function foo(a, ...b) { }"
+PASS Valid:   "function f() { function foo(a, ...b) { } }"
+PASS Valid:   "function foo(a = 20, ...b) { }"
+PASS Valid:   "function f() { function foo(a = 20, ...b) { } }"
+PASS Valid:   "function foo(a, b, c, d, e, f, g, ...h) { }"
+PASS Valid:   "function f() { function foo(a, b, c, d, e, f, g, ...h) { } }"
+PASS Invalid: "function foo(a, ...b, c) { }"
+PASS Invalid: "function f() { function foo(a, ...b, c) { } }"
+PASS Invalid: "function foo(a, ...b, ) { }"
+PASS Invalid: "function f() { function foo(a, ...b, ) { } }"
+PASS Invalid: "function foo(a, ...a) { }"
+PASS Invalid: "function f() { function foo(a, ...a) { } }"
+PASS Invalid: "function foo(...a, ...b) { }"
+PASS Invalid: "function f() { function foo(...a, ...b) { } }"
+PASS Invalid: "function foo(...b, ...b) { }"
+PASS Invalid: "function f() { function foo(...b, ...b) { } }"
+PASS Invalid: "function foo(...b  ...b) { }"
+PASS Invalid: "function f() { function foo(...b  ...b) { } }"
+PASS Invalid: "function foo(a, a, ...b) { }"
+PASS Invalid: "function f() { function foo(a, a, ...b) { } }"
+PASS Invalid: "function foo(...{b}) { }"
+PASS Invalid: "function f() { function foo(...{b}) { } }"
+PASS Invalid: "function foo(...[b]) { }"
+PASS Invalid: "function f() { function foo(...[b]) { } }"
+PASS Invalid: "function foo(...123) { }"
+PASS Invalid: "function f() { function foo(...123) { } }"
+PASS Invalid: "function foo(...123abc) { }"
+PASS Invalid: "function f() { function foo(...123abc) { } }"
+PASS Valid:   "function foo(...abc123) { }"
+PASS Valid:   "function f() { function foo(...abc123) { } }"
+PASS Valid:   "function foo(...let) { }"
+PASS Valid:   "function f() { function foo(...let) { } }"
+PASS Invalid: "'use strict'; function foo(...let) { }"
+PASS Invalid: "function f() { 'use strict'; function foo(...let) { } }"
+PASS Valid:   "function foo(...yield) { }"
+PASS Valid:   "function f() { function foo(...yield) { } }"
+PASS Invalid: "'use strict'; function foo(...yield) { }"
+PASS Invalid: "function f() { 'use strict'; function foo(...yield) { } }"
+PASS Invalid: "function foo(...if) { }"
+PASS Invalid: "function f() { function foo(...if) { } }"
 PASS e.line is 1
 PASS foo is 'PASS'
 PASS bar is 'PASS'

Modified: trunk/LayoutTests/js/script-tests/parser-syntax-check.js (192670 => 192671)


--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2015-11-20 02:37:47 UTC (rev 192671)
@@ -556,8 +556,31 @@
 invalid("1 % \n++");
 invalid("1 % \n--");
 
+debug("Rest parameter");
+valid("function foo(...a) { }");
+valid("function foo(a, ...b) { }");
+valid("function foo(a = 20, ...b) { }");
+valid("function foo(a, b, c, d, e, f, g, ...h) { }");
+invalid("function foo(a, ...b, c) { }")
+invalid("function foo(a, ...b, ) { }")
+invalid("function foo(a, ...a) { }");
+invalid("function foo(...a, ...b) { }");
+invalid("function foo(...b, ...b) { }");
+invalid("function foo(...b  ...b) { }");
+invalid("function foo(a, a, ...b) { }");
+invalid("function foo(...{b}) { }");
+invalid("function foo(...[b]) { }");
+invalid("function foo(...123) { }");
+invalid("function foo(...123abc) { }");
+valid("function foo(...abc123) { }");
+valid("function foo(...let) { }");
+invalid("'use strict'; function foo(...let) { }");
+valid("function foo(...yield) { }");
+invalid("'use strict'; function foo(...yield) { }");
+invalid("function foo(...if) { }");
 
 
+
 try { eval("a.b.c = {};"); } catch(e1) { e=e1; shouldBe("e.line", "1") }
 foo = 'FAIL';
 bar = 'PASS';

Modified: trunk/Source/_javascript_Core/ChangeLog (192670 => 192671)


--- trunk/Source/_javascript_Core/ChangeLog	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1,3 +1,146 @@
+2015-11-19  Saam barati  <sbar...@apple.com>
+
+        [ES6] Add support for rest parameters
+        https://bugs.webkit.org/show_bug.cgi?id=38408
+
+        Reviewed by Geoffrey Garen.
+
+        This patch implements rest parameters from the ES6 spec.
+        http://www.ecma-international.org/ecma-262/6.0/index.html#sec-function-definitions
+
+        We implement the rest parameter as a new AST node. This AST node
+        lowers to "op_new_array X, op_copy_rest X". Note
+        that the op_copy_rest opcode does not have a result.
+        The bulk of this patch is implementing op_copy_rest.
+        This patch implements this in all four tiers in a straight forward way.
+        The opcode is implemented as a C call that will read the pertinent
+        arguments from the call frame and fill them into the array.
+
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/Instruction.h:
+        (JSC::Instruction::Instruction):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
+        (JSC::BytecodeGenerator::invalidateForInContextForLocal):
+        (JSC::BytecodeGenerator::emitRestParameter):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::AssignmentElementNode::toString):
+        (JSC::RestParameterNode::collectBoundIdentifiers):
+        (JSC::RestParameterNode::toString):
+        (JSC::RestParameterNode::bindValue):
+        (JSC::RestParameterNode::emit):
+        (JSC::SpreadExpressionNode::emitBytecode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::setEpoch):
+        (JSC::DFG::Node::numberOfArgumentsToSkip):
+        (JSC::DFG::Node::dumpChildren):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCreateClonedArguments):
+        (JSC::DFG::SpeculativeJIT::compileCopyRest):
+        (JSC::DFG::SpeculativeJIT::compileNotifyWrite):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLIntrinsicRepository.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCreateClonedArguments):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileCopyRest):
+        (JSC::FTL::DFG::LowerDFGToLLVM::compileNewObject):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_create_out_of_band_arguments):
+        (JSC::JIT::emit_op_copy_rest):
+        * jit/JITOperations.h:
+        * llint/LowLevelInterpreter.asm:
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createBindingLocation):
+        (JSC::ASTBuilder::createRestParameter):
+        (JSC::ASTBuilder::createAssignmentElement):
+        * parser/NodeConstructors.h:
+        (JSC::AssignmentElementNode::AssignmentElementNode):
+        (JSC::RestParameterNode::RestParameterNode):
+        (JSC::DestructuringAssignmentNode::DestructuringAssignmentNode):
+        * parser/Nodes.h:
+        (JSC::DestructuringPatternNode::isBindingNode):
+        (JSC::DestructuringPatternNode::isRestParameter):
+        (JSC::DestructuringPatternNode::emitDirectBinding):
+        (JSC::RestParameterNode::name):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseVariableDeclarationList):
+        (JSC::Parser<LexerType>::declareRestOrNormalParameter):
+        (JSC::Parser<LexerType>::createBindingPattern):
+        (JSC::Parser<LexerType>::parseFormalParameters):
+        * parser/Parser.h:
+        (JSC::Parser::strictMode):
+        (JSC::Parser::isValidStrictMode):
+        (JSC::Parser::declareParameter):
+        (JSC::Parser::breakIsValid):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::operatorStackPop):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        * tests/es6.yaml:
+        * tests/stress/rest-parameter-and-default-arguments.js: Added.
+        (assert):
+        (shouldThrowTDZ):
+        (foo):
+        (baz):
+        (i.shouldThrowTDZ):
+        * tests/stress/rest-parameter-basics.js: Added.
+        (assert):
+        (foo):
+        (bar):
+        (capture):
+        (baz):
+        (jaz):
+        (kaz):
+        (raz):
+        (restLength):
+        (testArgumentsObject):
+        (strictModeLikeArgumentsObject):
+        * tests/stress/rest-parameter-inlined.js: Added.
+        (assert):
+        (bar):
+        (foo):
+        (baz):
+        (jaz):
+
 2015-11-19  Filip Pizlo  <fpi...@apple.com>
 
         B3 should have a story for Ext/Trunc strength reduction

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2015-11-20 02:37:47 UTC (rev 192671)
@@ -128,7 +128,8 @@
             { "name" : "op_enumerator_generic_pname", "length" : 4 },
             { "name" : "op_to_index_string", "length" : 3 },
             { "name" : "op_load_arrowfunction_this", "length" : 2 },
-            { "name" : "op_assert", "length" : 3 }
+            { "name" : "op_assert", "length" : 3 },
+            { "name" : "op_copy_rest", "length": 3 }
         ]
     },
     {

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -70,7 +70,8 @@
     case op_jeq_null:
     case op_jneq_null:
     case op_dec:
-    case op_inc: {
+    case op_inc: 
+    case op_copy_rest: {
         functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
         return;
     }
@@ -247,6 +248,7 @@
     OpcodeID opcodeID = interpreter->getOpcodeID(instruction->u.opcode);
     switch (opcodeID) {
     // These don't define anything.
+    case op_copy_rest:
     case op_put_to_scope:
     case op_end:
     case op_profile_will_call:

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -781,6 +781,14 @@
             out.printf("%s", registerName(r0).data());
             break;
         }
+        case op_copy_rest: {
+            int r0 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "copy_rest");
+            out.printf("%s, ", registerName(r0).data());
+            unsigned argumentOffset = (++it)->u.unsignedValue;
+            out.printf("ArgumentsOffset: %u", argumentOffset);
+            break;
+        }
         case op_create_this: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;

Modified: trunk/Source/_javascript_Core/bytecode/Instruction.h (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecode/Instruction.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecode/Instruction.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -75,6 +75,13 @@
         u.jsCell.clear();
         u.operand = operand;
     }
+    Instruction(unsigned unsignedValue)
+    {
+        // We have to initialize one of the pointer members to ensure that
+        // the entire struct is initialized in 64-bit.
+        u.jsCell.clear();
+        u.unsignedValue = unsignedValue;
+    }
 
     Instruction(PutByIdFlags flags)
     {
@@ -112,6 +119,7 @@
     union {
         Opcode opcode;
         int operand;
+        unsigned unsignedValue;
         WriteBarrierBase<Structure> structure;
         StructureID structureID;
         WriteBarrierBase<SymbolTable> symbolTable;

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -70,6 +70,9 @@
     if (m_needToInitializeArguments)
         initializeVariable(variable(propertyNames().arguments), m_argumentsRegister);
 
+    if (m_restParameter)
+        m_restParameter->emit(*this);
+
     {
         RefPtr<RegisterID> temp = newTemporary();
         RefPtr<RegisterID> globalScope;
@@ -272,8 +275,14 @@
     // needing destructuring are noted.
     m_parameters.grow(parameters.size() + 1); // reserve space for "this"
     m_thisRegister.setIndex(initializeNextParameter()->index()); // this
-    for (unsigned i = 0; i < parameters.size(); ++i)
-        initializeNextParameter();
+    for (unsigned i = 0; i < parameters.size(); ++i) {
+        auto pattern = parameters.at(i).first;
+        if (pattern->isRestParameter()) {
+            RELEASE_ASSERT(!m_restParameter);
+            m_restParameter = static_cast<RestParameterNode*>(pattern);
+        } else
+            initializeNextParameter();
+    }
     
     // Figure out some interesting facts about our arguments.
     bool capturesAnyArgumentByName = false;
@@ -307,7 +316,14 @@
         m_argumentsRegister->ref();
     }
     
-    if (needsArguments && !codeBlock->isStrictMode() && !parameters.hasDefaultParameterValues()) {
+    // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-functiondeclarationinstantiation
+    // This implements IsSimpleParameterList in the Ecma 2015 spec.
+    // If IsSimpleParameterList is false, we will create a strict-mode like arguments object.
+    // IsSimpleParameterList is false if the argument list contains any default parameter values,
+    // a rest parameter, or any destructuring patterns.
+    // FIXME: Take into account destructuring to make isSimpleParameterList false. https://bugs.webkit.org/show_bug.cgi?id=151450
+    bool isSimpleParameterList = !parameters.hasDefaultParameterValues() && !m_restParameter;
+    if (needsArguments && !codeBlock->isStrictMode() && isSimpleParameterList) {
         // If we captured any formal parameter by name, then we use ScopedArguments. Otherwise we
         // use DirectArguments. With ScopedArguments, we lift all of our arguments into the
         // activation.
@@ -389,7 +405,7 @@
         }
     }
     
-    if (needsArguments && (codeBlock->isStrictMode() || parameters.hasDefaultParameterValues())) {
+    if (needsArguments && (codeBlock->isStrictMode() || !isSimpleParameterList)) {
         // Allocate an out-of-bands arguments object.
         emitOpcode(op_create_out_of_band_arguments);
         instructions().append(m_argumentsRegister->index());
@@ -707,6 +723,8 @@
         RefPtr<RegisterID> temp = newTemporary();
         for (unsigned i = 0; i < parameters.size(); i++) {
             std::pair<DestructuringPatternNode*, ExpressionNode*> parameter = parameters.at(i);
+            if (parameter.first->isRestParameter())
+                continue;
             RefPtr<RegisterID> parameterValue = &registerFor(virtualRegisterForArgument(1 + i));
             emitMove(temp.get(), parameterValue.get());
             if (parameter.second) {
@@ -764,7 +782,7 @@
         // If we have default parameter values, we handle this case above.
         for (unsigned i = 0; i < parameters.size(); i++) {
             DestructuringPatternNode* pattern = parameters.at(i).first;
-            if (!pattern->isBindingNode()) {
+            if (!pattern->isBindingNode() && !pattern->isRestParameter()) {
                 RefPtr<RegisterID> parameterValue = &registerFor(virtualRegisterForArgument(1 + i));
                 pattern->bindValue(*this, parameterValue.get());
             }
@@ -3813,4 +3831,15 @@
     }
 }
 
+RegisterID* BytecodeGenerator::emitRestParameter(RegisterID* result, unsigned numParametersToSkip)
+{
+    emitNewArray(result, nullptr, 0);
+
+    emitOpcode(op_copy_rest);
+    instructions().append(result->index());
+    instructions().append(numParametersToSkip);
+
+    return result;
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -598,6 +598,8 @@
         RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node);
         void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node);
 
+        RegisterID* emitRestParameter(RegisterID* result, unsigned numParametersToSkip);
+
         bool emitReadOnlyExceptionIfNeeded(const Variable&);
 
         // Start a try block. 'start' must have been emitted.
@@ -828,6 +830,7 @@
         enum FunctionVariableType : uint8_t { NormalFunctionVariable, GlobalFunctionVariable };
         Vector<std::pair<FunctionMetadataNode*, FunctionVariableType>> m_functionsToInitialize;
         bool m_needToInitializeArguments { false };
+        RestParameterNode* m_restParameter { nullptr };
         
         Vector<TryRange> m_tryRanges;
         SegmentedVector<TryData, 8> m_tryData;

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -3456,6 +3456,35 @@
         builder.append(static_cast<ResolveNode*>(m_assignmentTarget)->identifier().string());
 }
 
+void RestParameterNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const
+{
+    identifiers.append(m_name);
+}
+void RestParameterNode::toString(StringBuilder& builder) const
+{
+    builder.append(m_name.string());
+}
+void RestParameterNode::bindValue(BytecodeGenerator&, RegisterID*) const
+{
+    RELEASE_ASSERT_NOT_REACHED();
+}
+void RestParameterNode::emit(BytecodeGenerator& generator)
+{
+    Variable var = generator.variable(m_name);
+    if (RegisterID* local = var.local()) {
+        generator.emitRestParameter(local, m_numParametersToSkip);
+        generator.emitProfileType(local, var, m_divotStart, m_divotEnd);
+        return;
+    }
+
+    RefPtr<RegisterID> restParameterArray = generator.emitRestParameter(generator.newTemporary(), m_numParametersToSkip);
+    generator.emitProfileType(restParameterArray.get(), var, m_divotStart, m_divotEnd);
+    RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
+    generator.emitExpressionInfo(m_divotEnd, m_divotStart, m_divotEnd);
+    generator.emitPutToScope(scope.get(), var, restParameterArray.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, Initialization);
+}
+
+
 RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*)
 {
     RELEASE_ASSERT_NOT_REACHED();

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -2508,6 +2508,9 @@
     case CheckTierUpAtReturn:
         break;
 
+    case CopyRest:
+        break;
+            
     case Check: {
         // Simplify out checks that don't actually do checking.
         for (unsigned i = 0; i < AdjacencyList::Size; ++i) {

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -3330,6 +3330,13 @@
             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand)));
             NEXT_OPCODE(op_new_regexp);
         }
+
+        case op_copy_rest: {
+            noticeArgumentsUse();
+            addToGraph(CopyRest,
+                OpInfo(currentInstruction[2].u.unsignedValue), get(VirtualRegister(currentInstruction[1].u.operand)));
+            NEXT_OPCODE(op_copy_rest);
+        }
             
         // === Bitwise operations ===
 

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -219,6 +219,7 @@
     case op_create_lexical_environment:
     case op_get_parent_scope:
     case op_catch:
+    case op_copy_rest:
         return CanCompileAndInline;
 
     case op_put_to_scope: {

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -983,6 +983,12 @@
         return;
     }
 
+    case CopyRest: {
+        read(Stack);
+        write(Heap);
+        return;
+    }
+
     case NewObject:
     case NewRegexp:
     case NewStringObject:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -224,6 +224,7 @@
     case GetStack:
     case GetFromArguments:
     case PutToArguments:
+    case CopyRest:
         return false;
 
     case CreateActivation:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1368,6 +1368,11 @@
             break;
         }
 
+        case CopyRest: {
+            fixEdge<KnownCellUse>(node->child1());
+            break;
+        }
+
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -2158,7 +2158,13 @@
     {
         m_misc.epoch = epoch.toUnsigned();
     }
-    
+
+    unsigned numberOfArgumentsToSkip()
+    {
+        ASSERT(op() == CopyRest);
+        return static_cast<unsigned>(m_opInfo);
+    }
+
     void dumpChildren(PrintStream& out)
     {
         if (!child1())

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -262,6 +262,7 @@
     macro(NewArrayBuffer, NodeResultJS) \
     macro(NewTypedArray, NodeResultJS | NodeMustGenerate) \
     macro(NewRegexp, NodeResultJS) \
+    macro(CopyRest, NodeMustGenerate) \
     \
     /* Support for allocation sinking. */\
     macro(PhantomNewObject, NodeResultJS | NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -818,6 +818,16 @@
     return result;
 }
 
+void JIT_OPERATION operationCopyRest(ExecState* exec, JSCell* arrayAsCell, Register* argumentStart, unsigned numberOfParamsToSkip, unsigned numberOfArguments)
+{
+    RELEASE_ASSERT(numberOfArguments > numberOfParamsToSkip); // We should only call this from JIT code when this condition is true.
+    JSArray* array = jsCast<JSArray*>(arrayAsCell);
+    unsigned arraySize = numberOfArguments - numberOfParamsToSkip;
+    array->setLength(exec, arraySize);
+    for (unsigned i = 0; i < arraySize; i++)
+        array->putDirectIndex(exec, i, argumentStart[i + numberOfParamsToSkip].jsValue());
+}
+
 size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object)
 {
     VM& vm = exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -103,6 +103,7 @@
 JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState*, Structure*, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment*);
 JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, int32_t argumentCount);
 JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState*, Structure*, Register* argumentStart, int32_t length, JSFunction* callee);
+void JIT_OPERATION operationCopyRest(ExecState*, JSCell*, Register* argumentStart, unsigned numberOfParamsToSkip, unsigned argumentsCount);
 double JIT_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
 size_t JIT_OPERATION operationObjectIsObject(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;
 size_t JIT_OPERATION operationObjectIsFunction(ExecState*, JSGlobalObject*, JSCell*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -676,6 +676,7 @@
         case ZombieHint:
         case ExitOK:
         case LoadVarargs:
+        case CopyRest:
             break;
             
         // This gets ignored because it only pretends to produce a value.

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -322,6 +322,7 @@
     case PhantomClonedArguments:
     case GetMyArgumentByVal:
     case ForwardVarargs:
+    case CopyRest:
         return true;
 
     case BottomValue:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -5344,6 +5344,34 @@
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileCopyRest(Node* node)
+{
+    ASSERT(node->op() == CopyRest);
+
+    SpeculateCellOperand array(this, node->child1());
+    GPRReg arrayGPR = array.gpr();
+
+    GPRTemporary argumentsLength(this);
+    GPRReg argumentsLengthGPR = argumentsLength.gpr();
+
+    GPRTemporary argumentsStart(this);
+    GPRReg argumentsStartGPR = argumentsStart.gpr();
+
+    emitGetLength(node->origin.semantic, argumentsLengthGPR);
+    CCallHelpers::Jump done = m_jit.branch32(MacroAssembler::LessThanOrEqual, argumentsLengthGPR, TrustedImm32(node->numberOfArgumentsToSkip()));
+
+    emitGetArgumentStart(node->origin.semantic, argumentsStartGPR);
+    silentSpillAllRegisters(argumentsLengthGPR, argumentsStartGPR);
+    // Arguments: 0:exec, 1:JSCell* array, 2:arguments start, 3:number of arguments to skip, 4:number of arguments
+    callOperation(operationCopyRest, arrayGPR, argumentsStartGPR, TrustedImm32(node->numberOfArgumentsToSkip()), argumentsLengthGPR);
+    silentFillAllRegisters(argumentsLengthGPR);
+    m_jit.exceptionCheck();
+
+    done.link(&m_jit);
+
+    noResult(node);
+}
+
 void SpeculativeJIT::compileNotifyWrite(Node* node)
 {
     WatchpointSet* set = node->watchpointSet();

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1221,6 +1221,12 @@
         return appendCall(operation);
     }
 
+    JITCompiler::Call callOperation(V_JITOperation_ECRUiUi operation, GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2, arg3, arg4);
+        return appendCall(operation);
+    }
+
 #if USE(JSVALUE64)
     JITCompiler::Call callOperation(J_JITOperation_E operation, GPRReg result)
     {
@@ -2238,6 +2244,7 @@
     void compilePutToArguments(Node*);
     void compileCreateScopedArguments(Node*);
     void compileCreateClonedArguments(Node*);
+    void compileCopyRest(Node*);
     void compileNotifyWrite(Node*);
     bool compileRegExpExec(Node*);
     void compileIsObjectOrNull(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -4438,6 +4438,11 @@
         break;
     }
 
+    case CopyRest: {
+        compileCopyRest(node);
+        break;
+    }
+
     case NewFunction:
     case NewArrowFunction:
         compileNewFunction(node);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -4427,6 +4427,10 @@
         compileCreateClonedArguments(node);
         break;
     }
+    case CopyRest: {
+        compileCopyRest(node);
+        break;
+    }
 
     case NewFunction:
     case NewArrowFunction:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -210,6 +210,7 @@
     case PutGetterSetterById:
     case PutGetterByVal:
     case PutSetterByVal:
+    case CopyRest:
         // These are OK.
         break;
 

Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (192670 => 192671)


--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -130,6 +130,7 @@
     macro(Z_JITOperation_EGC, functionType(int32, intPtr, intPtr, intPtr)) \
     macro(Z_JITOperation_EJZ, functionType(int32, intPtr, int64, int32)) \
     macro(Z_JITOperation_ESJss, functionType(int32, intPtr, intPtr, int64)) \
+    macro(V_JITOperation_ECRUiUi, functionType(voidType, intPtr, intPtr, intPtr, int32, int32))
     
 class IntrinsicRepository : public CommonValues {
 public:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -967,6 +967,9 @@
         case CheckWatchdogTimer:
             compileCheckWatchdogTimer();
             break;
+        case CopyRest:
+            compileCopyRest();
+            break;
 
         case PhantomLocal:
         case LoopHint:
@@ -3636,6 +3639,28 @@
         
         setJSValue(result);
     }
+
+    void compileCopyRest()
+    {            
+        LBasicBlock doCopyRest = FTL_NEW_BLOCK(m_out, ("CopyRest C call"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("FillRestParameter continuation"));
+
+        LValue numberOfArgumentsToSkip = m_out.constInt32(m_node->numberOfArgumentsToSkip());
+        LValue numberOfArguments = getArgumentsLength().value;
+
+        m_out.branch(
+            m_out.above(numberOfArguments, numberOfArgumentsToSkip),
+            unsure(doCopyRest), unsure(continuation));
+            
+        LBasicBlock lastNext = m_out.appendTo(doCopyRest, continuation);
+        // Arguments: 0:exec, 1:JSCell* array, 2:arguments start, 3:number of arguments to skip, 4:number of arguments
+        vmCall(
+            m_out.voidType,m_out.operation(operationCopyRest), m_callFrame, lowCell(m_node->child1()),
+            getArgumentsStart(), numberOfArgumentsToSkip, numberOfArguments);
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+    }
     
     void compileNewObject()
     {

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -211,6 +211,7 @@
         DEFINE_OP(op_create_direct_arguments)
         DEFINE_OP(op_create_scoped_arguments)
         DEFINE_OP(op_create_out_of_band_arguments)
+        DEFINE_OP(op_copy_rest)
         DEFINE_OP(op_check_tdz)
         DEFINE_OP(op_assert)
         DEFINE_OP(op_debug)

Modified: trunk/Source/_javascript_Core/jit/JIT.h (192670 => 192671)


--- trunk/Source/_javascript_Core/jit/JIT.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -490,6 +490,7 @@
         void emit_op_create_direct_arguments(Instruction*);
         void emit_op_create_scoped_arguments(Instruction*);
         void emit_op_create_out_of_band_arguments(Instruction*);
+        void emit_op_copy_rest(Instruction*);
         void emit_op_check_tdz(Instruction*);
         void emit_op_assert(Instruction*);
         void emit_op_debug(Instruction*);

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1399,6 +1399,12 @@
     slowPathCall.call();
 }
 
+void JIT::emit_op_copy_rest(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_copy_rest);
+    slowPathCall.call();
+}
+
 } // namespace JSC
 
 #endif // ENABLE(JIT)

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (192670 => 192671)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -92,6 +92,7 @@
     Vm: VM*
     Ws: WatchpointSet*
     Z: int32_t
+    Ui: uint32_t
 */
 
 typedef CallFrame* JIT_OPERATION (*F_JITOperation_EFJZZ)(ExecState*, CallFrame*, EncodedJSValue, int32_t, int32_t);
@@ -219,6 +220,7 @@
 typedef void JIT_OPERATION (*V_JITOperation_EVm)(ExecState*, VM*);
 typedef void JIT_OPERATION (*V_JITOperation_J)(EncodedJSValue);
 typedef void JIT_OPERATION (*V_JITOperation_Z)(int32_t);
+typedef void JIT_OPERATION (*V_JITOperation_ECRUiUi)(ExecState*, JSCell*, Register*, uint32_t, uint32_t);
 typedef char* JIT_OPERATION (*P_JITOperation_E)(ExecState*);
 typedef char* JIT_OPERATION (*P_JITOperation_EC)(ExecState*, JSCell*);
 typedef char* JIT_OPERATION (*P_JITOperation_ECli)(ExecState*, CallLinkInfo*);

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (192670 => 192671)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1675,6 +1675,12 @@
     callSlowPath(_slow_path_to_index_string)
     dispatch(3)
 
+_llint_op_copy_rest:
+    traceExecution()
+    callSlowPath(_slow_path_copy_rest)
+    dispatch(3)
+
+
 # Lastly, make sure that we can link even though we don't support all opcodes.
 # These opcodes should never arise when using LLInt or either JIT. We assert
 # as much.

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (192670 => 192671)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -857,6 +857,11 @@
         return new (m_parserArena) BindingNode(boundProperty, start, end, context);
     }
 
+    RestParameterNode* createRestParameter(const Identifier& name, size_t numParametersToSkip, const JSTextPosition& start, const JSTextPosition& end)
+    {
+        return new (m_parserArena) RestParameterNode(name, numParametersToSkip, start, end);
+    }
+
     AssignmentElement createAssignmentElement(const _expression_& assignmentTarget, const JSTextPosition& start, const JSTextPosition& end)
     {
         return new (m_parserArena) AssignmentElementNode(assignmentTarget, start, end);

Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (192670 => 192671)


--- trunk/Source/_javascript_Core/parser/NodeConstructors.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1029,6 +1029,15 @@
     {
     }
 
+    inline RestParameterNode::RestParameterNode(const Identifier& name, unsigned numParametersToSkip, const JSTextPosition& start, const JSTextPosition& end)
+        : DestructuringPatternNode()
+        , m_name(name)
+        , m_numParametersToSkip(numParametersToSkip)
+        , m_divotStart(start)
+        , m_divotEnd(end)
+    {
+    }
+
     inline DestructuringAssignmentNode::DestructuringAssignmentNode(const JSTokenLocation& location, DestructuringPatternNode* bindings, ExpressionNode* initializer)
         : ExpressionNode(location)
         , m_bindings(bindings)

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (192670 => 192671)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1973,6 +1973,7 @@
         virtual void toString(StringBuilder&) const = 0;
 
         virtual bool isBindingNode() const { return false; }
+        virtual bool isRestParameter() const { return false; }
         virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID*, ExpressionNode*) { return 0; }
         
     protected:
@@ -2053,6 +2054,27 @@
         AssignmentContext m_bindingContext;
     };
 
+    class RestParameterNode : public DestructuringPatternNode {
+    public:
+        RestParameterNode(const Identifier& boundProperty, unsigned numParametersToSkip, const JSTextPosition& start, const JSTextPosition& end);
+
+        bool isRestParameter() const override { return true; }
+
+        void emit(BytecodeGenerator&);
+
+        const Identifier& name() const { return m_name; }
+
+    private:
+        virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
+        virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
+        virtual void toString(StringBuilder&) const override;
+
+        const Identifier& m_name;
+        unsigned m_numParametersToSkip;
+        JSTextPosition m_divotStart; // "f" in "...foo"
+        JSTextPosition m_divotEnd;
+    };
+
     class AssignmentElementNode : public DestructuringPatternNode {
     public:
         AssignmentElementNode(ExpressionNode* assignmentTarget, const JSTextPosition& start, const JSTextPosition& end);

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -669,6 +669,30 @@
 }
 
 template <typename LexerType>
+bool Parser<LexerType>::declareRestOrNormalParameter(const Identifier& name, const Identifier** duplicateIdentifier)
+{
+    DeclarationResultMask declarationResult = declareParameter(&name);
+    if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
+        semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
+        if (m_lastFunctionName && name == *m_lastFunctionName)
+            semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
+        semanticFailureDueToKeyword("parameter name");
+        if (hasDeclaredParameter(name))
+            semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
+        semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
+    }
+    if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
+        // It's not always an error to define a duplicate parameter.
+        // It's only an error when there are default parameter values or destructuring parameters.
+        // We note this value now so we can check it later.
+        if (duplicateIdentifier)
+            *duplicateIdentifier = &name;
+    }
+
+    return true;
+}
+
+template <typename LexerType>
 template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
 {
     ASSERT(!name.isNull());
@@ -687,23 +711,8 @@
             failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
         }
     } else if (kind == DestructureToParameters) {
-        DeclarationResultMask declarationResult = declareParameter(&name);
-        if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
-            semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
-            if (m_lastFunctionName && name == *m_lastFunctionName)
-                semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
-            semanticFailureDueToKeyword("parameter name");
-            if (hasDeclaredParameter(name))
-                semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
-            semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
-        }
-        if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
-            // It's not always an error to define a duplicate parameter.
-            // It's only an error when there are default parameter values or destructuring parameters.
-            // We note this value now so we can check it later.
-            if (duplicateIdentifier)
-                *duplicateIdentifier = &name;
-        }
+        declareRestOrNormalParameter(name, duplicateIdentifier);
+        propagateError();
     }
 
     if (exportType == ExportType::Exported) {
@@ -1536,32 +1545,45 @@
 template <typename LexerType>
 template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeBuilder& context, TreeFormalParameterList list, unsigned& parameterCount)
 {
-#define failFromDuplicate() \
+#define failIfDuplicateIfViolation() \
     if (duplicateParameter) {\
         semanticFailIfTrue(defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");\
         semanticFailIfTrue(hasDestructuringPattern, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with destructuring parameters");\
+        semanticFailIfTrue(isRestParameter, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with a rest parameter");\
     }
 
+    bool hasDestructuringPattern = false;
+    bool isRestParameter = false;
     const Identifier* duplicateParameter = nullptr;
-    bool hasDestructuringPattern = false;
-    auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
-    failIfFalse(parameter, "Cannot parse parameter pattern");
-    auto defaultValue = parseDefaultValueForDestructuringPattern(context);
-    propagateError();
-    failFromDuplicate();
-    context.appendParameter(list, parameter, defaultValue);
-    parameterCount++;
-    while (consume(COMMA)) {
-        parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
+    do {
+        TreeDestructuringPattern parameter = 0;
+        TreeExpression defaultValue = 0;
+
+        if (match(DOTDOTDOT)) {
+            next();
+            failIfFalse(matchSpecIdentifier(), "Rest parameter '...' should be followed by a variable identifier");
+            declareRestOrNormalParameter(*m_token.m_data.ident, &duplicateParameter);
+            propagateError();
+            JSTextPosition identifierStart = tokenStartPosition();
+            JSTextPosition identifierEnd = tokenEndPosition();
+            parameter = context.createRestParameter(*m_token.m_data.ident, parameterCount, identifierStart, identifierEnd);
+            next();
+            failIfTrue(match(COMMA), "Rest parameter should be the last parameter in a function declaration"); // Let's have a good error message for this common case.
+            isRestParameter = true;
+        } else
+            parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
         failIfFalse(parameter, "Cannot parse parameter pattern");
-        defaultValue = parseDefaultValueForDestructuringPattern(context);
+        if (!isRestParameter)
+            defaultValue = parseDefaultValueForDestructuringPattern(context);
         propagateError();
-        failFromDuplicate();
+        failIfDuplicateIfViolation();
         context.appendParameter(list, parameter, defaultValue);
-        parameterCount++;
-    }
+        if (!isRestParameter)
+            parameterCount++;
+    } while (!isRestParameter && consume(COMMA));
+
     return true;
-#undef failFromDuplicate
+#undef failIfDuplicateIfViolation
 }
 
 template <typename LexerType>

Modified: trunk/Source/_javascript_Core/parser/Parser.h (192670 => 192671)


--- trunk/Source/_javascript_Core/parser/Parser.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1073,6 +1073,8 @@
     bool strictMode() { return currentScope()->strictMode(); }
     bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
     DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+    bool declareRestOrNormalParameter(const Identifier&, const Identifier**);
+
     bool breakIsValid()
     {
         ScopeRef current = currentScope();

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (192670 => 192671)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -75,7 +75,7 @@
         FunctionExpr, ClassExpr, SuperExpr, BracketExpr, DotExpr, CallExpr,
         NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
         ConditionalExpr, AssignmentExpr, TypeofExpr, NewTargetExpr,
-        DeleteExpr, ArrayLiteralExpr, BindingDestructuring,
+        DeleteExpr, ArrayLiteralExpr, BindingDestructuring, RestParameter,
         ArrayDestructuring, ObjectDestructuring, SourceElementsResult,
         FunctionBodyResult, SpreadExpr, ArgumentsResult,
         PropertyListResult, ArgumentsListResult, ElementsListResult,
@@ -135,6 +135,7 @@
     typedef int DestructuringPattern;
     typedef DestructuringPattern ArrayPattern;
     typedef DestructuringPattern ObjectPattern;
+    typedef DestructuringPattern RestPattern;
 
     static const bool CreatesAST = false;
     static const bool NeedsFreeVariableInfo = false;
@@ -346,6 +347,10 @@
     {
         return BindingDestructuring;
     }
+    RestPattern createRestParameter(const Identifier&, size_t, const JSTextPosition&, const JSTextPosition&)
+    { 
+        return RestParameter;
+    }
     DestructuringPattern createAssignmentElement(const _expression_&, const JSTextPosition&, const JSTextPosition&)
     {
         return BindingDestructuring;

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (192670 => 192671)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2015-11-20 02:37:47 UTC (rev 192671)
@@ -701,4 +701,20 @@
     RETURN(resolvedScope);
 }
 
+SLOW_PATH_DECL(slow_path_copy_rest)
+{
+    BEGIN();
+    unsigned numParamsToSkip = pc[2].u.unsignedValue;
+    unsigned numArgumentsToFunction = exec->argumentCount();
+    if (numArgumentsToFunction <= numParamsToSkip)
+        END();
+
+    JSArray* array = jsCast<JSArray*>(OP(1).jsValue());
+    unsigned arraySize = numArgumentsToFunction - numParamsToSkip;
+    array->setLength(exec, arraySize);
+    for (unsigned i = 0; i < arraySize; i++)
+        array->putDirectIndex(exec, i, exec->uncheckedArgument(i + numParamsToSkip));
+    END();
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h (192670 => 192671)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2015-11-20 02:37:47 UTC (rev 192671)
@@ -293,6 +293,7 @@
 SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment);
 SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
+SLOW_PATH_HIDDEN_DECL(slow_path_copy_rest);
 
 } // namespace JSC
 

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (192670 => 192671)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2015-11-20 01:28:30 UTC (rev 192670)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2015-11-20 02:37:47 UTC (rev 192671)
@@ -1089,15 +1089,15 @@
 - path: es6/RegExp_y_and_u_flags_y_flag_lastIndex.js
   cmd: runES6 :fail
 - path: es6/rest_parameters_arguments_object_interaction.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/rest_parameters_basic_functionality.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/rest_parameters_cant_be_used_in_setters.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/rest_parameters_function_length_property.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/rest_parameters_new_Function_support.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Set_iterator_closing.js
   cmd: runES6 :fail
 - path: es6/Set_Set[Symbol.species].js

Added: trunk/Source/_javascript_Core/tests/stress/rest-parameter-and-default-arguments.js (0 => 192671)


--- trunk/Source/_javascript_Core/tests/stress/rest-parameter-and-default-arguments.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/rest-parameter-and-default-arguments.js	2015-11-20 02:37:47 UTC (rev 192671)
@@ -0,0 +1,36 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion")
+}
+noInline(assert);
+
+function shouldThrowTDZ(func) {
+    var hasThrown = false;
+    try {
+        func();
+    } catch(e) {
+        if (e.name.indexOf("ReferenceError") !== -1)
+            hasThrown = true;
+    }
+    assert(hasThrown);
+}
+noInline(shouldThrowTDZ);
+
+function foo(a = function() { return c; }, b = a(), ...c) {
+    return a();
+}
+noInline(foo);
+
+function baz(a = function() { return b; }, ...b) {
+    return a();
+}
+
+for (let i = 0; i < 1000; i++) {
+    shouldThrowTDZ(function() { foo(undefined, undefined, 10, 20); });
+    let o = {x: 20};
+    let result = baz(undefined, 10, o, "baz");
+    assert(result.length === 3);
+    assert(result[0] === 10);
+    assert(result[1] === o);
+    assert(result[2] === "baz");
+}

Added: trunk/Source/_javascript_Core/tests/stress/rest-parameter-basics.js (0 => 192671)


--- trunk/Source/_javascript_Core/tests/stress/rest-parameter-basics.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/rest-parameter-basics.js	2015-11-20 02:37:47 UTC (rev 192671)
@@ -0,0 +1,103 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion")
+}
+noInline(assert);
+
+function foo(a, ...b) {
+    return b;    
+}
+noInline(foo);
+
+function bar(a, ...b) {
+    return a + b[0];
+}
+noInline(bar);
+
+function baz(a, ...b) {
+    function capture() { return b; }
+    assert(b[0] === capture()[0]);
+    return a + b[0];
+}
+noInline(baz);
+
+function jaz(a, ...b) {
+    function capture() { return a + b[0]; }
+    assert(capture() === a + b[0]);
+    return a + b[0];
+}
+noInline(jaz);
+
+function kaz(a = 10, ...b) {
+    return a + b[0]
+}
+noInline(kaz);
+
+function raz(a = 10, ...b) {
+    function capture() { return a + b[0]; }
+    assert(capture() === a + b[0]);
+    return a + b[0];
+}
+noInline(raz);
+
+function restLength(a, ...b) {
+    return b.length;
+}
+noInline(restLength);
+
+function testArgumentsObject(...args) {
+    assert(args.length === arguments.length);
+    for (let i = 0; i < args.length; i++)
+        assert(args[i] === arguments[i]);
+}
+noInline(testArgumentsObject);
+
+function strictModeLikeArgumentsObject(a, ...args) {
+    assert(arguments[0] === a);
+    a = "a";
+    assert(arguments[0] !== a);
+    assert(arguments[0] === 20);
+    assert(arguments.length === 2);
+    assert(args.length === 1);
+    assert(arguments[1] === args[0]);
+    arguments[1] = "b";
+    assert(args[0] !== "b");
+}
+noInline(strictModeLikeArgumentsObject);
+
+for (let i = 0; i < 10000; i++) {
+    let a1 = foo(10, 20);
+    assert(a1 instanceof Array);
+    assert(a1.length === 1);
+    assert(a1[0] === 20);
+
+    let a2 = foo(10);
+    assert(a2 instanceof Array);
+    assert(a2.length === 0);
+
+    let a3 = bar(10, 20);
+    assert(a3 === 30);
+
+    let a4 = baz(10, 20);
+    assert(a4 === 30);
+
+    let a5 = jaz("hello", "world");
+    assert(a5 === "helloworld");
+
+    let a6 = kaz(undefined, 40);
+    assert(a6 === 50);
+
+    let a7 = kaz(undefined, 40);
+    assert(a7 === 50);
+
+    assert(restLength() === 0);
+    assert(restLength(1) === 0);
+    assert(restLength(1, 1) === 1);
+    assert(restLength(1, 1, 1) === 2);
+    assert(restLength(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) === 20);
+
+    let obj = {foo: 40};
+    testArgumentsObject("hello", obj, 100, 12.34, "world", obj, [1, 2, 3]);
+
+    strictModeLikeArgumentsObject(20, 30);
+}

Added: trunk/Source/_javascript_Core/tests/stress/rest-parameter-inlined.js (0 => 192671)


--- trunk/Source/_javascript_Core/tests/stress/rest-parameter-inlined.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/rest-parameter-inlined.js	2015-11-20 02:37:47 UTC (rev 192671)
@@ -0,0 +1,38 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion")
+}
+noInline(assert);
+
+function bar(...rest) {
+    return rest;
+}
+
+function foo(a, b, c) {
+    return bar(a, b, c);
+}
+noInline(foo);
+
+for (let i = 0; i < 10000; i++) {
+    let result = foo(10, 20, 30);
+    assert(result.length === 3);
+    assert(result[0] === 10);
+    assert(result[1] === 20);
+    assert(result[2] === 30);
+}
+
+function baz(...rest) {
+    return rest;
+}
+function jaz(a, b, c) {
+    return baz.apply(null, Array.prototype.slice.call(arguments));
+}
+noInline(jaz);
+
+for (let i = 0; i < 50000; i++) {
+    let result = jaz(10, 20, 30);
+    assert(result.length === 3);
+    assert(result[0] === 10);
+    assert(result[1] === 20);
+    assert(result[2] === 30);
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to