Index: src/parsing/parser.cc |
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc |
index 6b7cb7d6a7f94ccdd143469a092de5581161c747..07ad607d37ac382d0eb51a9d3a6ca2ace923c32c 100644 |
--- a/src/parsing/parser.cc |
+++ b/src/parsing/parser.cc |
@@ -3682,85 +3682,90 @@ |
return running_hash; |
} |
-namespace { |
- |
-bool OnlyLastArgIsSpread(ZoneList<Expression*>* args) { |
- for (int i = 0; i < args->length() - 1; i++) { |
- if (args->at(i)->IsSpread()) { |
- return false; |
- } |
- } |
- return args->at(args->length() - 1)->IsSpread(); |
-} |
- |
-} // namespace |
- |
ZoneList<Expression*>* Parser::PrepareSpreadArguments( |
ZoneList<Expression*>* list) { |
- // Here we only deal with multiple arguments where the spread is not at the |
- // end, or there are multiple spreads. |
- DCHECK_GT(list->length(), 1); |
- DCHECK(!OnlyLastArgIsSpread(list)); |
- |
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); |
- // Spread-call with multiple arguments produces array literals for each |
- // sequences of unspread arguments, and converts each spread iterable to |
- // an Internal array. Finally, all of these produced arrays are flattened |
- // into a single InternalArray, containing the arguments for the call. |
- // |
- // EG: Apply(Func, Flatten([unspread0, unspread1], Spread(spread0), |
- // Spread(spread1), [unspread2, unspread3])) |
- int i = 0; |
- int n = list->length(); |
- while (i < n) { |
- if (!list->at(i)->IsSpread()) { |
- ZoneList<Expression*>* unspread = |
- new (zone()) ZoneList<Expression*>(1, zone()); |
- |
- // Push array of unspread parameters |
- while (i < n && !list->at(i)->IsSpread()) { |
- unspread->Add(list->at(i++), zone()); |
- } |
- int literal_index = function_state_->NextMaterializedLiteralIndex(); |
- args->Add(factory()->NewArrayLiteral(unspread, literal_index, |
- kNoSourcePosition), |
- zone()); |
- |
- if (i == n) break; |
- } |
- |
- // Push eagerly spread argument |
+ if (list->length() == 1) { |
+ // Spread-call with single spread argument produces an InternalArray |
+ // containing the values from the array. |
+ // |
+ // Function is called or constructed with the produced array of arguments |
+ // |
+ // EG: Apply(Func, Spread(spread0)) |
ZoneList<Expression*>* spread_list = |
- new (zone()) ZoneList<Expression*>(1, zone()); |
- spread_list->Add(list->at(i++)->AsSpread()->expression(), zone()); |
- args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX, |
+ new (zone()) ZoneList<Expression*>(0, zone()); |
+ spread_list->Add(list->at(0)->AsSpread()->expression(), zone()); |
+ args->Add(factory()->NewCallRuntime(Runtime::kSpreadIterablePrepare, |
spread_list, kNoSourcePosition), |
zone()); |
- } |
- |
- list = new (zone()) ZoneList<Expression*>(1, zone()); |
- list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args, |
- kNoSourcePosition), |
- zone()); |
- return list; |
+ return args; |
+ } else { |
+ // Spread-call with multiple arguments produces array literals for each |
+ // sequences of unspread arguments, and converts each spread iterable to |
+ // an Internal array. Finally, all of these produced arrays are flattened |
+ // into a single InternalArray, containing the arguments for the call. |
+ // |
+ // EG: Apply(Func, Flatten([unspread0, unspread1], Spread(spread0), |
+ // Spread(spread1), [unspread2, unspread3])) |
+ int i = 0; |
+ int n = list->length(); |
+ while (i < n) { |
+ if (!list->at(i)->IsSpread()) { |
+ ZoneList<Expression*>* unspread = |
+ new (zone()) ZoneList<Expression*>(1, zone()); |
+ |
+ // Push array of unspread parameters |
+ while (i < n && !list->at(i)->IsSpread()) { |
+ unspread->Add(list->at(i++), zone()); |
+ } |
+ int literal_index = function_state_->NextMaterializedLiteralIndex(); |
+ args->Add(factory()->NewArrayLiteral(unspread, literal_index, |
+ kNoSourcePosition), |
+ zone()); |
+ |
+ if (i == n) break; |
+ } |
+ |
+ // Push eagerly spread argument |
+ ZoneList<Expression*>* spread_list = |
+ new (zone()) ZoneList<Expression*>(1, zone()); |
+ spread_list->Add(list->at(i++)->AsSpread()->expression(), zone()); |
+ args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX, |
+ spread_list, kNoSourcePosition), |
+ zone()); |
+ } |
+ |
+ list = new (zone()) ZoneList<Expression*>(1, zone()); |
+ list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args, |
+ kNoSourcePosition), |
+ zone()); |
+ return list; |
+ } |
+ UNREACHABLE(); |
} |
Expression* Parser::SpreadCall(Expression* function, |
- ZoneList<Expression*>* args, int pos, |
- Call::PossiblyEval is_possibly_eval) { |
- // Handle these cases in BytecodeGenerator. |
- if (OnlyLastArgIsSpread(args)) { |
- if (function->IsSuperCallReference()) { |
- function = NewSuperCallReference(pos); |
- } |
- return factory()->NewCall(function, args, pos); |
- } |
- |
+ ZoneList<Expression*>* args, int pos) { |
if (function->IsSuperCallReference()) { |
// Super calls |
// $super_constructor = %_GetSuperConstructor(<this-function>) |
// %reflect_construct($super_constructor, args, new.target) |
+ bool only_last_arg_is_spread = false; |
+ for (int i = 0; i < args->length(); i++) { |
+ if (args->at(i)->IsSpread()) { |
+ if (i == args->length() - 1) { |
+ only_last_arg_is_spread = true; |
+ } |
+ break; |
+ } |
+ } |
+ |
+ if (only_last_arg_is_spread) { |
+ // Handle in BytecodeGenerator. |
+ Expression* super_call_ref = NewSuperCallReference(pos); |
+ return factory()->NewCall(super_call_ref, args, pos); |
+ } |
args = PrepareSpreadArguments(args); |
ZoneList<Expression*>* tmp = new (zone()) ZoneList<Expression*>(1, zone()); |
tmp->Add(function->AsSuperCallReference()->this_function_var(), zone()); |
@@ -3802,10 +3807,6 @@ |
Expression* Parser::SpreadCallNew(Expression* function, |
ZoneList<Expression*>* args, int pos) { |
- if (OnlyLastArgIsSpread(args)) { |
- // Handle in BytecodeGenerator. |
- return factory()->NewCallNew(function, args, pos); |
- } |
args = PrepareSpreadArguments(args); |
args->InsertAt(0, function, zone()); |