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 = ®isterFor(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 = ®isterFor(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);
+}