WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
WIP
b-backup.diff (text/plain), 47.95 KB, created by
Saam Barati
on 2015-11-17 18:29:22 PST
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2015-11-17 18:29:22 PST
Size:
47.95 KB
patch
obsolete
>Index: Source/JavaScriptCore/bytecode/BytecodeList.json >=================================================================== >--- Source/JavaScriptCore/bytecode/BytecodeList.json (revision 192525) >+++ Source/JavaScriptCore/bytecode/BytecodeList.json (working copy) >@@ -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_fill_rest_parameter_array", "length": 3 } > ] > }, > { >Index: Source/JavaScriptCore/bytecode/BytecodeUseDef.h >=================================================================== >--- Source/JavaScriptCore/bytecode/BytecodeUseDef.h (revision 192525) >+++ Source/JavaScriptCore/bytecode/BytecodeUseDef.h (working copy) >@@ -70,7 +70,8 @@ void computeUsesForBytecodeOffset( > case op_jeq_null: > case op_jneq_null: > case op_dec: >- case op_inc: { >+ case op_inc: >+ case op_fill_rest_parameter_array: { > functor(codeBlock, instruction, opcodeID, instruction[1].u.operand); > return; > } >@@ -247,6 +248,7 @@ void computeDefsForBytecodeOffset(CodeBl > OpcodeID opcodeID = interpreter->getOpcodeID(instruction->u.opcode); > switch (opcodeID) { > // These don't define anything. >+ case op_fill_rest_parameter_array: > case op_put_to_scope: > case op_end: > case op_profile_will_call: >Index: Source/JavaScriptCore/bytecode/CodeBlock.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.cpp (revision 192525) >+++ Source/JavaScriptCore/bytecode/CodeBlock.cpp (working copy) >@@ -781,6 +781,14 @@ void CodeBlock::dumpBytecode( > out.printf("%s", registerName(r0).data()); > break; > } >+ case op_fill_rest_parameter_array: { >+ int r0 = (++it)->u.operand; >+ printLocationAndOp(out, exec, location, it, "fill_rest_parameter_array"); >+ out.printf("%s, ", registerName(r0).data()); >+ size_t argumentOffset = bitwise_cast<size_t>((++it)->u.pointer); >+ out.printf("ArgumentsOffset: %zu", argumentOffset); >+ break; >+ } > case op_create_this: { > int r0 = (++it)->u.operand; > int r1 = (++it)->u.operand; >Index: Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >=================================================================== >--- Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (revision 192525) >+++ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (working copy) >@@ -70,6 +70,9 @@ ParserError BytecodeGenerator::generate( > 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 @@ BytecodeGenerator::BytecodeGenerator(VM& > // 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,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > m_argumentsRegister->ref(); > } > >- if (needsArguments && !codeBlock->isStrictMode() && !parameters.hasDefaultParameterValues()) { >+ if (needsArguments && !codeBlock->isStrictMode() && !parameters.hasDefaultParameterValues() && !m_restParameter) { > // 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 +398,7 @@ BytecodeGenerator::BytecodeGenerator(VM& > } > } > >- if (needsArguments && (codeBlock->isStrictMode() || parameters.hasDefaultParameterValues())) { >+ if (needsArguments && (codeBlock->isStrictMode() || parameters.hasDefaultParameterValues() || !!m_restParameter)) { > // Allocate an out-of-bands arguments object. > emitOpcode(op_create_out_of_band_arguments); > instructions().append(m_argumentsRegister->index()); >@@ -707,6 +716,8 @@ void BytecodeGenerator::initializeDefaul > 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 +775,7 @@ void BytecodeGenerator::initializeDefaul > // 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 +3824,15 @@ void BytecodeGenerator::invalidateForInC > } > } > >+RegisterID* BytecodeGenerator::emitRestParameter(RegisterID* result, size_t numParametersToSkip) >+{ >+ emitNewArray(result, nullptr, 0); >+ >+ emitOpcode(op_fill_rest_parameter_array); >+ instructions().append(result->index()); >+ instructions().append(numParametersToSkip); >+ >+ return result; >+} >+ > } // namespace JSC >Index: Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >=================================================================== >--- Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (revision 192525) >+++ Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (working copy) >@@ -598,6 +598,8 @@ namespace JSC { > RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* iterator, const ThrowableExpressionData* node); > void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node); > >+ RegisterID* emitRestParameter(RegisterID* result, size_t numParametersToSkip); >+ > bool emitReadOnlyExceptionIfNeeded(const Variable&); > > // Start a try block. 'start' must have been emitted. >@@ -828,6 +830,7 @@ namespace JSC { > 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; >Index: Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >=================================================================== >--- Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (revision 192525) >+++ Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (working copy) >@@ -3456,6 +3456,36 @@ void AssignmentElementNode::toString(Str > builder.append(static_cast<ResolveNode*>(m_assignmentTarget)->identifier().string()); > } > >+ >+void RestParameterNode::collectBoundIdentifiers(Vector<Identifier>& identifiers) const >+{ >+ identifiers.append(m_name); >+} >+void RestParameterNode::bindValue(BytecodeGenerator&, RegisterID*) const >+{ >+ RELEASE_ASSERT_NOT_REACHED(); >+} >+void RestParameterNode::toString(StringBuilder&) const >+{ >+ RELEASE_ASSERT_NOT_REACHED(); >+} >+void RestParameterNode::emit(BytecodeGenerator& generator) >+{ >+ // FIXME: type profiler support. >+ >+ Variable var = generator.variable(m_name); >+ if (RegisterID* local = var.local()) { >+ generator.emitRestParameter(local, m_numParametersToSkip); >+ return; >+ } >+ >+ // FIXME: expression info and all that jazz. >+ RefPtr<RegisterID> restParameterArray = generator.emitRestParameter(generator.newTemporary(), m_numParametersToSkip); >+ RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); >+ generator.emitPutToScope(scope.get(), var, restParameterArray.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, Initialization); >+} >+ >+ > RegisterID* SpreadExpressionNode::emitBytecode(BytecodeGenerator&, RegisterID*) > { > RELEASE_ASSERT_NOT_REACHED(); >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -1663,7 +1663,7 @@ bool AbstractInterpreter<AbstractStateTy > m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure( > node->typedArrayType())); > break; >- >+ > case NewRegexp: > forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure()); > break; >@@ -2508,6 +2508,10 @@ bool AbstractInterpreter<AbstractStateTy > case CheckTierUpAtReturn: > break; > >+ case FillRestParameterArray: >+ break; >+ >+ > case Check: { > // Simplify out checks that don't actually do checking. > for (unsigned i = 0; i < AdjacencyList::Size; ++i) { >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -3322,6 +3322,12 @@ bool ByteCodeParser::parseBlock(unsigned > set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand))); > NEXT_OPCODE(op_new_regexp); > } >+ >+ case op_fill_rest_parameter_array: { >+ noticeArgumentsUse(); >+ addToGraph(FillRestParameterArray, OpInfo(currentInstruction[2].u.pointer), get(VirtualRegister(currentInstruction[1].u.operand))); >+ NEXT_OPCODE(op_fill_rest_parameter_array); >+ } > > // === Bitwise operations === > >Index: Source/JavaScriptCore/dfg/DFGCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCapabilities.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGCapabilities.cpp (working copy) >@@ -219,6 +219,7 @@ CapabilityLevel capabilityLevel(OpcodeID > case op_create_lexical_environment: > case op_get_parent_scope: > case op_catch: >+ case op_fill_rest_parameter_array: > return CanCompileAndInline; > > case op_put_to_scope: { >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -983,6 +983,12 @@ void clobberize(Graph& graph, Node* node > return; > } > >+ case FillRestParameterArray: { >+ read(Stack); >+ write(Heap); >+ return; >+ } >+ > case NewObject: > case NewRegexp: > case NewStringObject: >Index: Source/JavaScriptCore/dfg/DFGDoesGC.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDoesGC.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGDoesGC.cpp (working copy) >@@ -224,6 +224,7 @@ bool doesGC(Graph& graph, Node* node) > case GetStack: > case GetFromArguments: > case PutToArguments: >+ case FillRestParameterArray: > return false; > > case CreateActivation: >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -1367,6 +1367,11 @@ private: > break; > } > >+ case FillRestParameterArray: { >+ 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: >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -2158,7 +2158,13 @@ struct Node { > { > m_misc.epoch = epoch.toUnsigned(); > } >- >+ >+ size_t numberOfArgumentsToSkip() >+ { >+ ASSERT(op() == FillRestParameterArray); >+ return bitwise_cast<size_t>(m_opInfo); >+ } >+ > void dumpChildren(PrintStream& out) > { > if (!child1()) >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -262,6 +262,7 @@ namespace JSC { namespace DFG { > macro(NewArrayBuffer, NodeResultJS) \ > macro(NewTypedArray, NodeResultJS | NodeMustGenerate) \ > macro(NewRegexp, NodeResultJS) \ >+ macro(FillRestParameterArray, NodeMustGenerate) \ > \ > /* Support for allocation sinking. */\ > macro(PhantomNewObject, NodeResultJS | NodeMustGenerate) \ >Index: Source/JavaScriptCore/dfg/DFGOperations.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGOperations.cpp (working copy) >@@ -818,6 +818,18 @@ JSCell* JIT_OPERATION operationCreateClo > return result; > } > >+void JIT_OPERATION operationFillRestParameterArray(ExecState* exec, JSCell* arrayAsCell, Register* argumentStart, size_t numParamsToSkip, size_t numberOfArguments) >+{ >+ JSArray* array = jsCast<JSArray*>(arrayAsCell); >+ if (numberOfArguments <= numParamsToSkip) >+ return; >+ >+ size_t arraySize = numberOfArguments - numParamsToSkip; >+ array->setLength(exec, arraySize); >+ for (size_t i = 0; i < arraySize; i++) >+ array->putDirectIndex(exec, i, argumentStart[i + numParamsToSkip].jsValue()); >+} >+ > size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) > { > VM& vm = exec->vm(); >Index: Source/JavaScriptCore/dfg/DFGOperations.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGOperations.h (working copy) >@@ -103,6 +103,7 @@ JSCell* JIT_OPERATION operationCreateDir > 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 operationFillRestParameterArray(ExecState*, JSCell*, Register* argumentStart, size_t argumentsOffset, size_t 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; >Index: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -676,6 +676,7 @@ private: > case ZombieHint: > case ExitOK: > case LoadVarargs: >+ case FillRestParameterArray: > break; > > // This gets ignored because it only pretends to produce a value. >Index: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -322,6 +322,7 @@ bool safeToExecute(AbstractStateType& st > case PhantomClonedArguments: > case GetMyArgumentByVal: > case ForwardVarargs: >+ case FillRestParameterArray: > return true; > > case BottomValue: >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -4443,6 +4443,10 @@ void SpeculativeJIT::compile(Node* node) > compileCreateClonedArguments(node); > break; > } >+ case FillRestParameterArray: { >+ compileFillRestParameterArray(node); >+ break; >+ } > > case NewFunction: > case NewArrowFunction: >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -5216,6 +5216,28 @@ void SpeculativeJIT::compileCreateCloned > cellResult(resultGPR, node); > } > >+void SpeculativeJIT::compileFillRestParameterArray(Node* node) >+{ >+ ASSERT(node->op() == FillRestParameterArray); >+ >+ SpeculateCellOperand array(this, node->child1()); >+ GPRReg arrayGPR = array.gpr(); >+ >+ flushRegisters(); >+ >+ // Arguments: 0:exec, 1:JSCell* array, 2:arguments start, 3:number of arguments to skip, 4:number of arguments or size_t max. >+ m_jit.setupArgument(4, [&] (GPRReg destGPR) { emitGetLength(node->origin.semantic, destGPR); }); >+ m_jit.setupArgument(3, [&] (GPRReg destGPR) { m_jit.move(TrustedImmPtr(node->numberOfArgumentsToSkip()), destGPR); }); >+ m_jit.setupArgument(2, [&] (GPRReg destGPR) { emitGetArgumentStart(node->origin.semantic, destGPR); }); >+ m_jit.setupArgument(1, [&] (GPRReg destGPR) { m_jit.move(arrayGPR, destGPR); }); >+ m_jit.setupArgument(0, [&] (GPRReg destGPR) { m_jit.move(GPRInfo::callFrameRegister, destGPR); }); >+ >+ appendCall(operationFillRestParameterArray); >+ m_jit.exceptionCheck(); // FIXME: Can this even throw? >+ >+ noResult(node); >+} >+ > void SpeculativeJIT::compileNotifyWrite(Node* node) > { > WatchpointSet* set = node->watchpointSet(); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (working copy) >@@ -2237,6 +2237,7 @@ public: > void compilePutToArguments(Node*); > void compileCreateScopedArguments(Node*); > void compileCreateClonedArguments(Node*); >+ void compileFillRestParameterArray(Node*); > void compileNotifyWrite(Node*); > bool compileRegExpExec(Node*); > void compileIsObjectOrNull(Node*); >Index: Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp (revision 192525) >+++ Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp (working copy) >@@ -322,6 +322,10 @@ private: > m_node->phi()->setEpoch(m_node->epoch()); > m_node->setEpoch(Epoch()); > break; >+ >+ case FillRestParameterArray: >+ // FIXME: make sure this is ok. >+ break; > > default: > // For nodes that aren't guaranteed to allocate, we say that their return value >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 192525) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -210,6 +210,7 @@ inline CapabilityLevel canCompile(Node* > case PutGetterSetterById: > case PutGetterByVal: > case PutSetterByVal: >+ case FillRestParameterArray: > // These are OK. > break; > >Index: Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (revision 192525) >+++ Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h (working copy) >@@ -126,6 +126,7 @@ namespace JSC { namespace FTL { > 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_ECRSS, functionType(voidType, intPtr, intPtr, intPtr, int64, int32)) > > class IntrinsicRepository : public CommonValues { > public: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 192525) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -918,6 +918,9 @@ private: > case CheckWatchdogTimer: > compileCheckWatchdogTimer(); > break; >+ case FillRestParameterArray: >+ compileFillRestParameterArray(); >+ break; > > case PhantomLocal: > case LoopHint: >@@ -3508,6 +3511,17 @@ private: > > setJSValue(result); > } >+ >+ void compileFillRestParameterArray() >+ { >+ // Arguments: 0:exec, 1:JSCell* array, 2:arguments start, 3:number of arguments to skip, 4:number of arguments or size_t max. >+ // FIXME: there are some instances where the number of getArgumentsLength is constant, and the number of arguments >+ // to skip is also constant. We can do some math on those constants and see if calling operationCreateFillRestParameterArray >+ // would just be a noop and we can skip compiling it. >+ vmCall( >+ m_out.operation(operationFillRestParameterArray), m_callFrame, lowCell(m_node->child1()), >+ getArgumentsStart(), m_out.constInt64(m_node->numberOfArgumentsToSkip()), getArgumentsLength().value); >+ } > > void compileNewObject() > { >Index: Source/JavaScriptCore/jit/JIT.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JIT.cpp (revision 192525) >+++ Source/JavaScriptCore/jit/JIT.cpp (working copy) >@@ -211,6 +211,7 @@ void JIT::privateCompileMainPass() > DEFINE_OP(op_create_direct_arguments) > DEFINE_OP(op_create_scoped_arguments) > DEFINE_OP(op_create_out_of_band_arguments) >+ DEFINE_OP(op_fill_rest_parameter_array) > DEFINE_OP(op_check_tdz) > DEFINE_OP(op_assert) > DEFINE_OP(op_debug) >Index: Source/JavaScriptCore/jit/JIT.h >=================================================================== >--- Source/JavaScriptCore/jit/JIT.h (revision 192525) >+++ Source/JavaScriptCore/jit/JIT.h (working copy) >@@ -491,6 +491,7 @@ namespace JSC { > 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_fill_rest_parameter_array(Instruction*); > void emit_op_check_tdz(Instruction*); > void emit_op_assert(Instruction*); > void emit_op_debug(Instruction*); >Index: Source/JavaScriptCore/jit/JITOpcodes.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITOpcodes.cpp (revision 192525) >+++ Source/JavaScriptCore/jit/JITOpcodes.cpp (working copy) >@@ -1399,6 +1399,12 @@ void JIT::emit_op_create_out_of_band_arg > slowPathCall.call(); > } > >+void JIT::emit_op_fill_rest_parameter_array(Instruction* currentInstruction) >+{ >+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_fill_rest_parameter_array); >+ slowPathCall.call(); >+} >+ > } // namespace JSC > > #endif // ENABLE(JIT) >Index: Source/JavaScriptCore/jit/JITOperations.h >=================================================================== >--- Source/JavaScriptCore/jit/JITOperations.h (revision 192525) >+++ Source/JavaScriptCore/jit/JITOperations.h (working copy) >@@ -219,6 +219,7 @@ typedef void JIT_OPERATION (*V_JITOperat > 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_ECRSS)(ExecState*, JSCell*, Register*, size_t, size_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*); >Index: Source/JavaScriptCore/llint/LowLevelInterpreter.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter.asm (revision 192525) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter.asm (working copy) >@@ -1675,6 +1675,12 @@ _llint_op_to_index_string: > callSlowPath(_slow_path_to_index_string) > dispatch(3) > >+_llint_op_fill_rest_parameter_array: >+ traceExecution() >+ callSlowPath(_slow_path_fill_rest_parameter_array) >+ 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. >Index: Source/JavaScriptCore/parser/ASTBuilder.h >=================================================================== >--- Source/JavaScriptCore/parser/ASTBuilder.h (revision 192525) >+++ Source/JavaScriptCore/parser/ASTBuilder.h (working copy) >@@ -862,6 +862,11 @@ public: > return new (m_parserArena) AssignmentElementNode(assignmentTarget, start, end); > } > >+ RestParameterNode* createRestParameter(const Identifier& name, size_t numParametersToSkip) >+ { >+ return new (m_parserArena) RestParameterNode(name, numParametersToSkip); >+ } >+ > void setEndOffset(Node* node, int offset) > { > node->setEndOffset(offset); >Index: Source/JavaScriptCore/parser/NodeConstructors.h >=================================================================== >--- Source/JavaScriptCore/parser/NodeConstructors.h (revision 192525) >+++ Source/JavaScriptCore/parser/NodeConstructors.h (working copy) >@@ -1029,6 +1029,13 @@ namespace JSC { > { > } > >+ inline RestParameterNode::RestParameterNode(const Identifier& name, size_t numParametersToSkip) >+ : DestructuringPatternNode() >+ , m_name(name) >+ , m_numParametersToSkip(numParametersToSkip) >+ { >+ } >+ > inline DestructuringAssignmentNode::DestructuringAssignmentNode(const JSTokenLocation& location, DestructuringPatternNode* bindings, ExpressionNode* initializer) > : ExpressionNode(location) > , m_bindings(bindings) >Index: Source/JavaScriptCore/parser/Nodes.h >=================================================================== >--- Source/JavaScriptCore/parser/Nodes.h (revision 192525) >+++ Source/JavaScriptCore/parser/Nodes.h (working copy) >@@ -1973,6 +1973,7 @@ namespace JSC { > 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: >@@ -2071,6 +2072,25 @@ namespace JSC { > ExpressionNode* m_assignmentTarget; > }; > >+ class RestParameterNode : public DestructuringPatternNode { >+ public: >+ RestParameterNode(const Identifier& boundProperty, size_t numParametersToSkip); >+ >+ 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; >+ size_t m_numParametersToSkip; >+ }; >+ > class DestructuringAssignmentNode : public ExpressionNode { > public: > DestructuringAssignmentNode(const JSTokenLocation&, DestructuringPatternNode*, ExpressionNode*); >Index: Source/JavaScriptCore/parser/Parser.cpp >=================================================================== >--- Source/JavaScriptCore/parser/Parser.cpp (revision 192525) >+++ Source/JavaScriptCore/parser/Parser.cpp (working copy) >@@ -667,6 +667,27 @@ template <class TreeBuilder> TreeExpress > } > > template <typename LexerType> >+bool Parser<LexerType>::declareRestOrDestructuringParameter(const Identifier& name) >+{ >+ auto 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 destructure to '", name.impl(), "' as it shadows the name of a strict mode function"); >+ semanticFailureDueToKeyword("bound parameter name"); >+ if (hasDeclaredParameter(name)) >+ semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared"); >+ semanticFail("Cannot bind to a parameter named '", name.impl(), "' in strict mode"); >+ } >+ if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) { >+ semanticFailureDueToKeyword("bound parameter name"); >+ semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared"); >+ } >+ >+ return true; >+} >+ >+template <typename LexerType> > template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier) > { > ASSERT(!name.isNull()); >@@ -686,22 +707,8 @@ template <class TreeBuilder> TreeDestruc > } > } else if (kind == DestructureToParameters) { > if (depth) { >- auto bindingResult = declareBoundParameter(&name); >- if (bindingResult == Scope::StrictBindingFailed && strictMode()) { >- semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode"); >- if (m_lastFunctionName && name == *m_lastFunctionName) >- semanticFail("Cannot destructure to '", name.impl(), "' as it shadows the name of a strict mode function"); >- semanticFailureDueToKeyword("bound parameter name"); >- if (hasDeclaredParameter(name)) >- semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared"); >- semanticFail("Cannot bind to a parameter named '", name.impl(), "' in strict mode"); >- } >- if (bindingResult == Scope::BindingFailed) { >- semanticFailureDueToKeyword("bound parameter name"); >- if (hasDeclaredParameter(name)) >- semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared"); >- semanticFail("Cannot destructure to a parameter named '", name.impl(), "'"); >- } >+ declareRestOrDestructuringParameter(name); >+ propagateError(); > } else { > DeclarationResultMask declarationResult = declareParameter(&name); > if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) { >@@ -1553,32 +1560,44 @@ template <class TreeBuilder> TreeStateme > 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");\ > } > >- 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); >+ bool isRestParameter = false; >+ const Identifier* duplicateParameter = nullptr; >+ do { >+ TreeDestructuringPattern parameter = 0; >+ TreeExpression defaultValue = 0; >+ >+ if (match(DOTDOTDOT)) { >+ next(); >+ failIfFalse(matchSpecIdentifier(), "Rest parameter '...' should be followed by a variable identifier"); >+ declareRestOrDestructuringParameter(*m_token.m_data.ident); >+ propagateError(); >+ parameter = context.createRestParameter(*m_token.m_data.ident, parameterCount); >+ 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; >+ hasDestructuringPattern = true; >+ // FIXME: >+ } 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 (consume(COMMA) && !isRestParameter); >+ > return true; >-#undef failFromDuplicate >+#undef failIfDuplicateIfViolation > } > > template <typename LexerType> >Index: Source/JavaScriptCore/parser/Parser.h >=================================================================== >--- Source/JavaScriptCore/parser/Parser.h (revision 192525) >+++ Source/JavaScriptCore/parser/Parser.h (working copy) >@@ -1055,6 +1055,8 @@ private: > bool isValidStrictMode() { return currentScope()->isValidStrictMode(); } > DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } > Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); } >+ bool declareRestOrDestructuringParameter(const Identifier&); >+ > bool breakIsValid() > { > ScopeRef current = currentScope(); >Index: Source/JavaScriptCore/parser/SyntaxChecker.h >=================================================================== >--- Source/JavaScriptCore/parser/SyntaxChecker.h (revision 192525) >+++ Source/JavaScriptCore/parser/SyntaxChecker.h (working copy) >@@ -75,7 +75,7 @@ public: > 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 @@ public: > typedef int DestructuringPattern; > typedef DestructuringPattern ArrayPattern; > typedef DestructuringPattern ObjectPattern; >+ typedef DestructuringPattern RestPattern; > > static const bool CreatesAST = false; > static const bool NeedsFreeVariableInfo = false; >@@ -350,6 +351,10 @@ public: > { > return BindingDestructuring; > } >+ RestPattern createRestParameter(const Identifier&, size_t) >+ { >+ return RestParameter; >+ } > > bool isBindingNode(DestructuringPattern pattern) > { >Index: Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (revision 192525) >+++ Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (working copy) >@@ -701,4 +701,22 @@ SLOW_PATH_DECL(slow_path_resolve_scope) > RETURN(resolvedScope); > } > >+SLOW_PATH_DECL(slow_path_fill_rest_parameter_array) >+{ >+ BEGIN(); >+ // function foo(a, b, ...c) >+ // foo(10, 20, 30) >+ size_t numParamsToSkip = bitwise_cast<size_t>(pc[2].u.pointer); >+ size_t numArgumentsToFunction = exec->argumentCount(); >+ if (numArgumentsToFunction <= numParamsToSkip) >+ END(); >+ >+ JSArray* array = jsCast<JSArray*>(OP(1).jsValue()); >+ size_t arraySize = numArgumentsToFunction - numParamsToSkip; >+ array->setLength(exec, arraySize); >+ for (size_t i = 0; i < arraySize; i++) >+ array->putDirectIndex(exec, i, exec->uncheckedArgument(i + numParamsToSkip)); >+ END(); >+} >+ > } // namespace JSC >Index: Source/JavaScriptCore/runtime/CommonSlowPaths.h >=================================================================== >--- Source/JavaScriptCore/runtime/CommonSlowPaths.h (revision 192525) >+++ Source/JavaScriptCore/runtime/CommonSlowPaths.h (working copy) >@@ -293,6 +293,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_assert); > 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_fill_rest_parameter_array); > > } // namespace JSC > >Index: Source/JavaScriptCore/tests/es6.yaml >=================================================================== >--- Source/JavaScriptCore/tests/es6.yaml (revision 192525) >+++ Source/JavaScriptCore/tests/es6.yaml (working copy) >@@ -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 >Index: Source/JavaScriptCore/tests/stress/rest-parameter-and-default-arguments.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/rest-parameter-and-default-arguments.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/rest-parameter-and-default-arguments.js (working copy) >@@ -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"); >+} >Index: Source/JavaScriptCore/tests/stress/rest-parameter-basics.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/rest-parameter-basics.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/rest-parameter-basics.js (working copy) >@@ -0,0 +1,78 @@ >+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); >+ >+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); >+} >Index: Source/JavaScriptCore/tests/stress/rest-parameter-inlined.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/rest-parameter-inlined.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/rest-parameter-inlined.js (working copy) >@@ -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); >+} >Index: LayoutTests/js/parser-syntax-check-expected.txt >=================================================================== >--- LayoutTests/js/parser-syntax-check-expected.txt (revision 192525) >+++ LayoutTests/js/parser-syntax-check-expected.txt (working copy) >@@ -929,6 +929,49 @@ PASS Invalid: "1 % > --" > 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' >Index: LayoutTests/js/script-tests/parser-syntax-check.js >=================================================================== >--- LayoutTests/js/script-tests/parser-syntax-check.js (revision 192525) >+++ LayoutTests/js/script-tests/parser-syntax-check.js (working copy) >@@ -556,6 +556,29 @@ invalid("1 % --"); > 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") }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 38408
:
264908
|
264950
|
264980
|
265714
|
265726
|
265823
|
265880
|
265883
|
265891