Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 4412b8a98cdca5618ec0b7caf1a77caf246718b3..0dc013202f857d8398a72fb599c2b6daadc94ce1 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -877,6 +877,7 @@ Parser::Parser(ParseInfo* info) |
set_allow_harmony_computed_property_names( |
FLAG_harmony_computed_property_names); |
set_allow_harmony_rest_params(FLAG_harmony_rest_parameters); |
+ set_allow_harmony_spreadcalls(FLAG_harmony_spreadcalls); |
set_allow_strong_mode(FLAG_strong_mode); |
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; |
++feature) { |
@@ -4231,6 +4232,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( |
allow_harmony_computed_property_names()); |
reusable_preparser_->set_allow_harmony_rest_params( |
allow_harmony_rest_params()); |
+ reusable_preparser_->set_allow_harmony_spreadcalls( |
+ allow_harmony_spreadcalls()); |
reusable_preparser_->set_allow_strong_mode(allow_strong_mode()); |
} |
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( |
@@ -4349,7 +4352,10 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { |
Expect(Token::MOD, CHECK_OK); |
// Allow "eval" or "arguments" for backward compatibility. |
const AstRawString* name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK); |
- ZoneList<Expression*>* args = ParseArguments(CHECK_OK); |
+ Scanner::Location spread_pos; |
+ ZoneList<Expression*>* args = ParseArguments(&spread_pos, CHECK_OK); |
+ |
+ DCHECK(!spread_pos.IsValid()); |
if (extension_ != NULL) { |
// The extension structures are only accessible while parsing the |
@@ -5614,4 +5620,121 @@ uint32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) { |
return running_hash; |
} |
+ |
+ |
+ZoneList<v8::internal::Expression*>* Parser::PrepareSpreadArguments( |
+ ZoneList<v8::internal::Expression*>* list) { |
+ ZoneList<v8::internal::Expression*>* args = |
+ new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); |
+ 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*>(0, zone()); |
+ spread_list->Add(list->at(0)->AsSpread()->expression(), zone()); |
+ args->Add( |
+ factory()->NewCallRuntime(ast_value_factory()->spread_iterable_string(), |
+ NULL, spread_list, RelocInfo::kNoPosition), |
+ zone()); |
+ 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<v8::internal::Expression*>* unspread = |
+ new (zone()) ZoneList<v8::internal::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, |
+ RelocInfo::kNoPosition), |
+ zone()); |
+ |
+ if (i == n) break; |
+ } |
+ |
+ // Push eagerly spread argument |
+ ZoneList<v8::internal::Expression*>* spread_list = |
+ new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); |
+ spread_list->Add(list->at(i++)->AsSpread()->expression(), zone()); |
+ args->Add(factory()->NewCallRuntime( |
+ ast_value_factory()->spread_iterable_string(), NULL, |
+ spread_list, RelocInfo::kNoPosition), |
+ zone()); |
+ } |
+ |
+ list = new (zone()) ZoneList<v8::internal::Expression*>(1, zone()); |
+ list->Add(factory()->NewCallRuntime( |
+ ast_value_factory()->spread_arguments_string(), NULL, args, |
+ RelocInfo::kNoPosition), |
+ zone()); |
+ return list; |
+ } |
+ UNREACHABLE(); |
+} |
+ |
+ |
+Expression* Parser::SpreadCall(Expression* function, |
+ ZoneList<v8::internal::Expression*>* args, |
+ int pos) { |
+ if (function->IsSuperReference()) { |
+ // Super calls |
+ args->InsertAt(0, function, zone()); |
+ args->Add(factory()->NewVariableProxy(scope_->new_target_var()), zone()); |
+ Expression* result = factory()->NewCallRuntime( |
+ ast_value_factory()->reflect_construct_string(), NULL, args, pos); |
+ args = new (zone()) ZoneList<Expression*>(0, zone()); |
+ args->Add(result, zone()); |
+ return factory()->NewCallRuntime( |
+ ast_value_factory()->empty_string(), |
+ Runtime::FunctionForId(Runtime::kInlineCallSuperWithSpread), args, pos); |
+ } else { |
+ if (function->IsProperty()) { |
+ // Method calls |
+ Variable* temp = |
+ scope_->NewTemporary(ast_value_factory()->empty_string()); |
+ VariableProxy* obj = factory()->NewVariableProxy(temp); |
+ Assignment* assign_obj = factory()->NewAssignment( |
+ Token::ASSIGN, obj, function->AsProperty()->obj(), |
+ RelocInfo::kNoPosition); |
+ function = factory()->NewProperty( |
+ assign_obj, function->AsProperty()->key(), RelocInfo::kNoPosition); |
+ args->InsertAt(0, function, zone()); |
+ obj = factory()->NewVariableProxy(temp); |
+ args->InsertAt(1, obj, zone()); |
+ } else { |
+ // Non-method calls |
+ args->InsertAt(0, function, zone()); |
+ args->InsertAt(1, factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), |
+ zone()); |
+ } |
+ return factory()->NewCallRuntime( |
+ ast_value_factory()->reflect_apply_string(), NULL, args, pos); |
+ } |
+} |
+ |
+ |
+Expression* Parser::SpreadCallNew(Expression* function, |
+ ZoneList<v8::internal::Expression*>* args, |
+ int pos) { |
+ args->InsertAt(0, function, zone()); |
+ |
+ return factory()->NewCallRuntime( |
+ ast_value_factory()->reflect_construct_string(), NULL, args, pos); |
+} |
} } // namespace v8::internal |