diff options
Diffstat (limited to 'deps/v8/src/parsing/parser.cc')
-rw-r--r-- | deps/v8/src/parsing/parser.cc | 601 |
1 files changed, 298 insertions, 303 deletions
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 7b88695e77..8d8890129f 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -68,7 +68,6 @@ bool ParseData::IsSane() { if (data_length < PreparseDataConstants::kHeaderSize) return false; if (Magic() != PreparseDataConstants::kMagicNumber) return false; if (Version() != PreparseDataConstants::kCurrentVersion) return false; - if (HasError()) return false; // Check that the space allocated for function entries is sane. int functions_size = FunctionsSize(); if (functions_size < 0) return false; @@ -90,11 +89,6 @@ void ParseData::Initialize() { } -bool ParseData::HasError() { - return Data()[PreparseDataConstants::kHasErrorOffset]; -} - - unsigned ParseData::Magic() { return Data()[PreparseDataConstants::kMagicOffset]; } @@ -124,6 +118,7 @@ class DiscardableZoneScope { parser_->zone_ = temp_zone; if (parser_->reusable_preparser_ != nullptr) { parser_->reusable_preparser_->zone_ = temp_zone; + parser_->reusable_preparser_->factory()->set_zone(temp_zone); } } } @@ -132,6 +127,7 @@ class DiscardableZoneScope { parser_->zone_ = prev_zone_; if (parser_->reusable_preparser_ != nullptr) { parser_->reusable_preparser_->zone_ = prev_zone_; + parser_->reusable_preparser_->factory()->set_zone(prev_zone_); } ast_node_factory_scope_.Reset(); } @@ -148,12 +144,11 @@ class DiscardableZoneScope { }; void Parser::SetCachedData(ParseInfo* info) { - if (compile_options_ == ScriptCompiler::kNoCompileOptions) { - cached_parse_data_ = NULL; - } else { - DCHECK(info->cached_data() != NULL); - if (compile_options_ == ScriptCompiler::kConsumeParserCache) { - cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); + DCHECK_NULL(cached_parse_data_); + if (consume_cached_parse_data()) { + cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); + if (cached_parse_data_ == nullptr) { + compile_options_ = ScriptCompiler::kNoCompileOptions; } } } @@ -219,7 +214,7 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, LanguageMode language_mode) { int materialized_literal_count = -1; int expected_property_count = -1; - int parameter_count = 0; + const int parameter_count = 0; if (name == nullptr) name = ast_value_factory()->empty_string(); FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor @@ -282,59 +277,16 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, FunctionLiteral* function_literal = factory()->NewFunctionLiteral( name, function_scope, body, materialized_literal_count, - expected_property_count, parameter_count, + expected_property_count, parameter_count, parameter_count, FunctionLiteral::kNoDuplicateParameters, - FunctionLiteral::kAnonymousExpression, - FunctionLiteral::kShouldLazyCompile, pos); + FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, + true); function_literal->set_requires_class_field_init(requires_class_field_init); return function_literal; } - -// ---------------------------------------------------------------------------- -// Target is a support class to facilitate manipulation of the -// Parser's target_stack_ (the stack of potential 'break' and -// 'continue' statement targets). Upon construction, a new target is -// added; it is removed upon destruction. - -class ParserTarget BASE_EMBEDDED { - public: - ParserTarget(ParserBase<Parser>* parser, BreakableStatement* statement) - : variable_(&parser->impl()->target_stack_), - statement_(statement), - previous_(parser->impl()->target_stack_) { - parser->impl()->target_stack_ = this; - } - - ~ParserTarget() { *variable_ = previous_; } - - ParserTarget* previous() { return previous_; } - BreakableStatement* statement() { return statement_; } - - private: - ParserTarget** variable_; - BreakableStatement* statement_; - ParserTarget* previous_; -}; - -class ParserTargetScope BASE_EMBEDDED { - public: - explicit ParserTargetScope(ParserBase<Parser>* parser) - : variable_(&parser->impl()->target_stack_), - previous_(parser->impl()->target_stack_) { - parser->impl()->target_stack_ = nullptr; - } - - ~ParserTargetScope() { *variable_ = previous_; } - - private: - ParserTarget** variable_; - ParserTarget* previous_; -}; - - // ---------------------------------------------------------------------------- // The CHECK_OK macro is a convenient macro to enforce error // handling for functions that may fail (by returning !*ok). @@ -521,9 +473,7 @@ Expression* Parser::NewSuperCallReference(int pos) { } Expression* Parser::NewTargetExpression(int pos) { - static const int kNewTargetStringLength = 10; - auto proxy = NewUnresolved(ast_value_factory()->new_target_string(), pos, - pos + kNewTargetStringLength); + auto proxy = NewUnresolved(ast_value_factory()->new_target_string(), pos); proxy->set_is_new_target(); return proxy; } @@ -547,7 +497,7 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { case Token::FALSE_LITERAL: return factory()->NewBooleanLiteral(false, pos); case Token::SMI: { - int value = scanner()->smi_value(); + uint32_t value = scanner()->smi_value(); return factory()->NewSmiLiteral(value, pos); } case Token::NUMBER: { @@ -631,31 +581,48 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name, Parser::Parser(ParseInfo* info) : ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(), - info->extension(), info->ast_value_factory(), NULL), + info->extension(), info->ast_value_factory(), + info->isolate()->counters()->runtime_call_stats()), scanner_(info->unicode_cache()), - reusable_preparser_(NULL), - original_scope_(NULL), - target_stack_(NULL), + reusable_preparser_(nullptr), + original_scope_(nullptr), + mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. + target_stack_(nullptr), compile_options_(info->compile_options()), - cached_parse_data_(NULL), + cached_parse_data_(nullptr), total_preparse_skipped_(0), - pre_parse_timer_(NULL), - parsing_on_main_thread_(true) { + parsing_on_main_thread_(true), + log_(nullptr) { // Even though we were passed ParseInfo, we should not store it in // Parser - this makes sure that Isolate is not accidentally accessed via // ParseInfo during background parsing. DCHECK(!info->script().is_null() || info->source_stream() != nullptr || info->character_stream() != nullptr); + // Determine if functions can be lazily compiled. This is necessary to + // allow some of our builtin JS files to be lazily compiled. These + // builtins cannot be handled lazily by the parser, since we have to know + // if a function uses the special natives syntax, which is something the + // parser records. + // If the debugger requests compilation for break points, we cannot be + // aggressive about lazy compilation, because it might trigger compilation + // of functions without an outer context when setting a breakpoint through + // Debug::FindSharedFunctionInfoInScript + bool can_compile_lazily = FLAG_lazy && !info->is_debug(); + + // Consider compiling eagerly when targeting the code cache. + can_compile_lazily &= !(FLAG_serialize_eager && info->will_serialize()); + + set_default_eager_compile_hint(can_compile_lazily + ? FunctionLiteral::kShouldLazyCompile + : FunctionLiteral::kShouldEagerCompile); set_allow_lazy(FLAG_lazy && info->allow_lazy_parsing() && - !info->is_native() && info->extension() == nullptr); + !info->is_native() && info->extension() == nullptr && + can_compile_lazily); set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); set_allow_tailcalls(FLAG_harmony_tailcalls && !info->is_native() && info->isolate()->is_tail_call_elimination_enabled()); set_allow_harmony_do_expressions(FLAG_harmony_do_expressions); - set_allow_harmony_for_in(FLAG_harmony_for_in); set_allow_harmony_function_sent(FLAG_harmony_function_sent); - set_allow_harmony_restrictive_declarations( - FLAG_harmony_restrictive_declarations); set_allow_harmony_async_await(FLAG_harmony_async_await); set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators); set_allow_harmony_trailing_commas(FLAG_harmony_trailing_commas); @@ -699,9 +666,10 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { // called in the main thread. DCHECK(parsing_on_main_thread_); - HistogramTimerScope timer_scope(isolate->counters()->parse(), true); - RuntimeCallTimerScope runtime_timer(isolate, &RuntimeCallStats::Parse); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.Parse"); + RuntimeCallTimerScope runtime_timer( + runtime_call_stats_, info->is_eval() ? &RuntimeCallStats::ParseEval + : &RuntimeCallStats::ParseProgram); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseProgram"); Handle<String> source(String::cast(info->script()->source())); isolate->counters()->total_parse_size()->Increment(source->length()); base::ElapsedTimer timer; @@ -711,10 +679,10 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); // Initialize parser state. - CompleteParserRecorder recorder; + ParserLogger logger; if (produce_cached_parse_data()) { - log_ = &recorder; + log_ = &logger; } else if (consume_cached_parse_data()) { cached_parse_data_->Initialize(); } @@ -734,7 +702,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { } HandleSourceURLComments(isolate, info->script()); - if (FLAG_trace_parse && result != NULL) { + if (FLAG_trace_parse && result != nullptr) { double ms = timer.Elapsed().InMillisecondsF(); if (info->is_eval()) { PrintF("[parsing eval"); @@ -747,10 +715,10 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { } PrintF(" - took %0.3f ms]\n", ms); } - if (produce_cached_parse_data()) { - if (result != NULL) *info->cached_data() = recorder.GetScriptData(); - log_ = NULL; + if (produce_cached_parse_data() && result != nullptr) { + *info->cached_data() = logger.GetScriptData(); } + log_ = nullptr; return result; } @@ -762,7 +730,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { DCHECK_NULL(scope_state_); DCHECK_NULL(target_stack_); - Mode parsing_mode = allow_lazy() ? PARSE_LAZILY : PARSE_EAGERLY; + ParsingModeScope mode(this, allow_lazy() ? PARSE_LAZILY : PARSE_EAGERLY); FunctionLiteral* result = NULL; { @@ -770,25 +738,16 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { DCHECK_NOT_NULL(outer); parsing_module_ = info->is_module(); if (info->is_eval()) { - if (!outer->is_script_scope() || is_strict(info->language_mode())) { - parsing_mode = PARSE_EAGERLY; - } outer = NewEvalScope(outer); } else if (parsing_module_) { DCHECK_EQ(outer, info->script_scope()); outer = NewModuleScope(info->script_scope()); - // Never do lazy parsing in modules. If we want to support this in the - // future, we must force context-allocation for all variables that are - // declared at the module level but not MODULE-allocated. - parsing_mode = PARSE_EAGERLY; } DeclarationScope* scope = outer->AsDeclarationScope(); scope->set_start_position(0); - // Enter 'scope' with the given parsing mode. - ParsingModeScope parsing_mode_scope(this, parsing_mode); FunctionState function_state(&function_state_, &scope_state_, scope); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); @@ -868,14 +827,13 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { return result; } - -FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) { +FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info) { // It's OK to use the Isolate & counters here, since this function is only // called in the main thread. DCHECK(parsing_on_main_thread_); - RuntimeCallTimerScope runtime_timer(isolate, &RuntimeCallStats::ParseLazy); - HistogramTimerScope timer_scope(isolate->counters()->parse_lazy()); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseLazy"); + RuntimeCallTimerScope runtime_timer(runtime_call_stats_, + &RuntimeCallStats::ParseFunction); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseFunction"); Handle<String> source(String::cast(info->script()->source())); isolate->counters()->total_parse_size()->Increment(source->length()); base::ElapsedTimer timer; @@ -892,8 +850,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) { std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For( source, shared_info->start_position(), shared_info->end_position())); Handle<String> name(String::cast(shared_info->name())); - result = - DoParseLazy(info, ast_value_factory()->GetString(name), stream.get()); + result = DoParseFunction(info, ast_value_factory()->GetString(name), + stream.get()); if (result != nullptr) { Handle<String> inferred_name(shared_info->inferred_name()); result->set_inferred_name(inferred_name); @@ -922,9 +880,9 @@ static FunctionLiteral::FunctionType ComputeFunctionType(ParseInfo* info) { return FunctionLiteral::kAnonymousExpression; } -FunctionLiteral* Parser::DoParseLazy(ParseInfo* info, - const AstRawString* raw_name, - Utf16CharacterStream* source) { +FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, + const AstRawString* raw_name, + Utf16CharacterStream* source) { scanner_.Initialize(source); DCHECK_NULL(scope_state_); DCHECK_NULL(target_stack_); @@ -1130,15 +1088,19 @@ void Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, } const AstRawString* local_name = ParseIdentifierName(CHECK_OK_VOID); const AstRawString* export_name = NULL; + Scanner::Location location = scanner()->location(); if (CheckContextualKeyword(CStrVector("as"))) { export_name = ParseIdentifierName(CHECK_OK_VOID); + // Set the location to the whole "a as b" string, so that it makes sense + // both for errors due to "a" and for errors due to "b". + location.end_pos = scanner()->location().end_pos; } if (export_name == NULL) { export_name = local_name; } export_names->Add(export_name, zone()); local_names->Add(local_name, zone()); - export_locations->Add(scanner()->location(), zone()); + export_locations->Add(location, zone()); if (peek() == Token::RBRACE) break; Expect(Token::COMMA, CHECK_OK_VOID); } @@ -1168,6 +1130,7 @@ ZoneList<const Parser::NamedImport*>* Parser::ParseNamedImports( while (peek() != Token::RBRACE) { const AstRawString* import_name = ParseIdentifierName(CHECK_OK); const AstRawString* local_name = import_name; + Scanner::Location location = scanner()->location(); // In the presence of 'as', the left-side of the 'as' can // be any IdentifierName. But without 'as', it must be a valid // BindingIdentifier. @@ -1188,8 +1151,8 @@ ZoneList<const Parser::NamedImport*>* Parser::ParseNamedImports( DeclareVariable(local_name, CONST, kNeedsInitialization, position(), CHECK_OK); - NamedImport* import = new (zone()) NamedImport( - import_name, local_name, scanner()->location()); + NamedImport* import = + new (zone()) NamedImport(import_name, local_name, location); result->Add(import, zone()); if (peek() == Token::RBRACE) break; @@ -1377,21 +1340,23 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { // 'export' Declaration // 'export' 'default' ... (handled in ParseExportDefault) - int pos = peek_position(); Expect(Token::EXPORT, CHECK_OK); + int pos = position(); Statement* result = nullptr; ZoneList<const AstRawString*> names(1, zone()); + Scanner::Location loc = scanner()->peek_location(); switch (peek()) { case Token::DEFAULT: return ParseExportDefault(ok); case Token::MUL: { Consume(Token::MUL); + loc = scanner()->location(); ExpectContextualKeyword(CStrVector("from"), CHECK_OK); const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK); ExpectSemicolon(CHECK_OK); - module()->AddStarExport(module_specifier, scanner()->location(), zone()); + module()->AddStarExport(module_specifier, loc, zone()); return factory()->NewEmptyStatement(pos); } @@ -1472,11 +1437,11 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { ReportUnexpectedToken(scanner()->current_token()); return nullptr; } + loc.end_pos = scanner()->location().end_pos; ModuleDescriptor* descriptor = module(); for (int i = 0; i < names.length(); ++i) { - // TODO(neis): Provide better location. - descriptor->AddExport(names[i], names[i], scanner()->location(), zone()); + descriptor->AddExport(names[i], names[i], loc, zone()); } DCHECK_NOT_NULL(result); @@ -1484,13 +1449,12 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { } VariableProxy* Parser::NewUnresolved(const AstRawString* name, int begin_pos, - int end_pos, VariableKind kind) { - return scope()->NewUnresolved(factory(), name, begin_pos, end_pos, kind); + VariableKind kind) { + return scope()->NewUnresolved(factory(), name, begin_pos, kind); } VariableProxy* Parser::NewUnresolved(const AstRawString* name) { - return scope()->NewUnresolved(factory(), name, scanner()->location().beg_pos, - scanner()->location().end_pos); + return scope()->NewUnresolved(factory(), name, scanner()->location().beg_pos); } Declaration* Parser::DeclareVariable(const AstRawString* name, @@ -1504,18 +1468,19 @@ Declaration* Parser::DeclareVariable(const AstRawString* name, int pos, bool* ok) { DCHECK_NOT_NULL(name); VariableProxy* proxy = factory()->NewVariableProxy( - name, NORMAL_VARIABLE, scanner()->location().beg_pos, - scanner()->location().end_pos); + name, NORMAL_VARIABLE, scanner()->location().beg_pos); Declaration* declaration = factory()->NewVariableDeclaration(proxy, this->scope(), pos); - Declare(declaration, DeclarationDescriptor::NORMAL, mode, init, CHECK_OK); + Declare(declaration, DeclarationDescriptor::NORMAL, mode, init, ok, nullptr, + scanner()->location().end_pos); + if (!*ok) return nullptr; return declaration; } Variable* Parser::Declare(Declaration* declaration, DeclarationDescriptor::Kind declaration_kind, VariableMode mode, InitializationFlag init, bool* ok, - Scope* scope) { + Scope* scope, int var_end_pos) { if (scope == nullptr) { scope = this->scope(); } @@ -1524,11 +1489,18 @@ Variable* Parser::Declare(Declaration* declaration, declaration, mode, init, allow_harmony_restrictive_generators(), &sloppy_mode_block_scope_function_redefinition, ok); if (!*ok) { + // If we only have the start position of a proxy, we can't highlight the + // whole variable name. Pretend its length is 1 so that we highlight at + // least the first character. + Scanner::Location loc(declaration->proxy()->position(), + var_end_pos != kNoSourcePosition + ? var_end_pos + : declaration->proxy()->position() + 1); if (declaration_kind == DeclarationDescriptor::NORMAL) { - ReportMessage(MessageTemplate::kVarRedeclaration, - declaration->proxy()->raw_name()); + ReportMessageAt(loc, MessageTemplate::kVarRedeclaration, + declaration->proxy()->raw_name()); } else { - ReportMessage(MessageTemplate::kParamDupe); + ReportMessageAt(loc, MessageTemplate::kParamDupe); } return nullptr; } @@ -1947,7 +1919,6 @@ Block* Parser::RewriteForVarInLegacy(const ForInfo& for_info) { for_info.parsing_result.declarations[0]; if (!IsLexicalVariableMode(for_info.parsing_result.descriptor.mode) && decl.pattern->IsVariableProxy() && decl.initializer != nullptr) { - DCHECK(!allow_harmony_for_in()); ++use_counts_[v8::Isolate::kForInInitializer]; const AstRawString* name = decl.pattern->AsVariableProxy()->raw_name(); VariableProxy* single_var = NewUnresolved(name); @@ -2034,8 +2005,7 @@ void Parser::DesugarBindingInForEachStatement(ForInfo* for_info, *body_block = factory()->NewBlock(nullptr, 3, false, kNoSourcePosition); (*body_block)->statements()->Add(each_initialization_block, zone()); - *each_variable = factory()->NewVariableProxy(temp, for_info->each_loc.beg_pos, - for_info->each_loc.end_pos); + *each_variable = factory()->NewVariableProxy(temp, for_info->position); } // Create a TDZ for any lexically-bound names in for in/of statements. @@ -2483,7 +2453,7 @@ void Parser::DeclareArrowFunctionFormalParameters( AddArrowFunctionFormalParameters(parameters, expr, params_loc.end_pos, CHECK_OK_VOID); - if (parameters->Arity() > Code::kMaxArguments) { + if (parameters->arity > Code::kMaxArguments) { ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList); *ok = false; return; @@ -2493,7 +2463,7 @@ void Parser::DeclareArrowFunctionFormalParameters( if (!parameters->is_simple) { this->classifier()->RecordNonSimpleParameter(); } - for (int i = 0; i < parameters->Arity(); ++i) { + for (int i = 0; i < parameters->arity; ++i) { auto parameter = parameters->at(i); DeclareFormalParameter(parameters->scope, parameter); if (!this->classifier() @@ -2551,8 +2521,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( int pos = function_token_pos == kNoSourcePosition ? peek_position() : function_token_pos; - bool is_generator = IsGeneratorFunction(kind); - // Anonymous functions were passed either the empty symbol or a null // handle as the function name. Remember if we were passed a non-empty // handle to decide whether to invoke function name inference. @@ -2566,7 +2534,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( FunctionLiteral::EagerCompileHint eager_compile_hint = function_state_->next_function_is_parenthesized() ? FunctionLiteral::kShouldEagerCompile - : FunctionLiteral::kShouldLazyCompile; + : default_eager_compile_hint(); // Determine if the function can be parsed lazily. Lazy parsing is // different from lazy compilation; we need to parse more eagerly than we @@ -2600,14 +2568,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // parenthesis before the function means that it will be called // immediately). bar can be parsed lazily, but we need to parse it in a mode // that tracks unresolved variables. - DCHECK_IMPLIES(mode() == PARSE_LAZILY, FLAG_lazy); - DCHECK_IMPLIES(mode() == PARSE_LAZILY, allow_lazy()); - DCHECK_IMPLIES(mode() == PARSE_LAZILY, extension_ == nullptr); + DCHECK_IMPLIES(parse_lazily(), FLAG_lazy); + DCHECK_IMPLIES(parse_lazily(), allow_lazy()); + DCHECK_IMPLIES(parse_lazily(), extension_ == nullptr); + + bool can_preparse = parse_lazily() && + eager_compile_hint == FunctionLiteral::kShouldLazyCompile; bool is_lazy_top_level_function = - mode() == PARSE_LAZILY && - eager_compile_hint == FunctionLiteral::kShouldLazyCompile && - scope()->AllowsLazyParsingWithoutUnresolvedVariables(); + can_preparse && impl()->AllowsLazyParsingWithoutUnresolvedVariables(); + + RuntimeCallTimerScope runtime_timer(runtime_call_stats_, + &RuntimeCallStats::ParseFunctionLiteral); // Determine whether we can still lazy parse the inner function. // The preconditions are: @@ -2629,8 +2601,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // will migrate unresolved variable into a Scope in the main Zone. // TODO(marja): Refactor parsing modes: simplify this. bool use_temp_zone = - allow_lazy() && function_type == FunctionLiteral::kDeclaration && - eager_compile_hint != FunctionLiteral::kShouldEagerCompile && + (FLAG_lazy_inner_functions + ? can_preparse + : (is_lazy_top_level_function || + (allow_lazy() && function_type == FunctionLiteral::kDeclaration && + eager_compile_hint == FunctionLiteral::kShouldLazyCompile))) && !(FLAG_validate_asm && scope()->IsAsmModule()); bool is_lazy_inner_function = use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function; @@ -2638,40 +2613,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // This Scope lives in the main zone. We'll migrate data into that zone later. DeclarationScope* scope = NewFunctionScope(kind); SetLanguageMode(scope, language_mode); +#ifdef DEBUG + scope->SetScopeName(function_name); +#endif ZoneList<Statement*>* body = nullptr; - int arity = -1; int materialized_literal_count = -1; int expected_property_count = -1; - DuplicateFinder duplicate_finder(scanner()->unicode_cache()); bool should_be_used_once_hint = false; - bool has_duplicate_parameters; - - FunctionState function_state(&function_state_, &scope_state_, scope); -#ifdef DEBUG - scope->SetScopeName(function_name); -#endif - - ExpressionClassifier formals_classifier(this, &duplicate_finder); - - if (is_generator) PrepareGeneratorVariables(&function_state); + int num_parameters = -1; + int function_length = -1; + bool has_duplicate_parameters = false; Expect(Token::LPAREN, CHECK_OK); - int start_position = scanner()->location().beg_pos; - this->scope()->set_start_position(start_position); - ParserFormalParameters formals(scope); - ParseFormalParameterList(&formals, CHECK_OK); - arity = formals.Arity(); - Expect(Token::RPAREN, CHECK_OK); - int formals_end_position = scanner()->location().end_pos; - - CheckArityRestrictions(arity, kind, formals.has_rest, start_position, - formals_end_position, CHECK_OK); - Expect(Token::LBRACE, CHECK_OK); - // Don't include the rest parameter into the function's formal parameter - // count (esp. the SharedFunctionInfo::internal_formal_parameter_count, - // which says whether we need to create an arguments adaptor frame). - if (formals.has_rest) arity--; + scope->set_start_position(scanner()->location().beg_pos); { // Temporary zones can nest. When we migrate free variables (see below), we @@ -2684,26 +2639,25 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // the previous zone is always restored after parsing the body. To be able // to do scope analysis correctly after full parsing, we migrate needed // information when the function is parsed. - Zone temp_zone(zone()->allocator()); + Zone temp_zone(zone()->allocator(), ZONE_NAME); DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone); #ifdef DEBUG if (use_temp_zone) scope->set_needs_migration(); #endif // Eager or lazy parse? If is_lazy_top_level_function, we'll parse - // lazily. We'll call SkipLazyFunctionBody, which may decide to abort lazy - // parsing if it suspects that wasn't a good idea. If so (in which case the - // parser is expected to have backtracked), or if we didn't try to lazy - // parse in the first place, we'll have to parse eagerly. + // lazily. We'll call SkipFunction, which may decide to + // abort lazy parsing if it suspects that wasn't a good idea. If so (in + // which case the parser is expected to have backtracked), or if we didn't + // try to lazy parse in the first place, we'll have to parse eagerly. if (is_lazy_top_level_function || is_lazy_inner_function) { Scanner::BookmarkScope bookmark(scanner()); bookmark.Set(); - LazyParsingResult result = SkipLazyFunctionBody( - &materialized_literal_count, &expected_property_count, - is_lazy_inner_function, is_lazy_top_level_function, CHECK_OK); - - materialized_literal_count += formals.materialized_literals_count + - function_state.materialized_literal_count(); + LazyParsingResult result = + SkipFunction(kind, scope, &num_parameters, &function_length, + &has_duplicate_parameters, &materialized_literal_count, + &expected_property_count, is_lazy_inner_function, + is_lazy_top_level_function, CHECK_OK); if (result == kLazyParsingAborted) { DCHECK(is_lazy_top_level_function); @@ -2723,31 +2677,41 @@ FunctionLiteral* Parser::ParseFunctionLiteral( } if (!is_lazy_top_level_function && !is_lazy_inner_function) { - body = ParseEagerFunctionBody(function_name, pos, formals, kind, - function_type, CHECK_OK); - - materialized_literal_count = function_state.materialized_literal_count(); - expected_property_count = function_state.expected_property_count(); + body = ParseFunction( + function_name, pos, kind, function_type, scope, &num_parameters, + &function_length, &has_duplicate_parameters, + &materialized_literal_count, &expected_property_count, CHECK_OK); } - if (use_temp_zone || is_lazy_top_level_function) { + DCHECK(use_temp_zone || !is_lazy_top_level_function); + if (use_temp_zone) { // If the preconditions are correct the function body should never be // accessed, but do this anyway for better behaviour if they're wrong. body = nullptr; scope->AnalyzePartially(&previous_zone_ast_node_factory); } - // Parsing the body may change the language mode in our scope. - language_mode = scope->language_mode(); + if (FLAG_trace_preparse) { + PrintF(" [%s]: %i-%i %.*s\n", + is_lazy_top_level_function + ? "Preparse no-resolution" + : (use_temp_zone ? "Preparse resolution" : "Full parse"), + scope->start_position(), scope->end_position(), + function_name->byte_length(), function_name->raw_data()); + if (is_lazy_top_level_function) { + CHANGE_CURRENT_RUNTIME_COUNTER(runtime_call_stats_, + PreParseNoVariableResolution); + } else if (use_temp_zone) { + CHANGE_CURRENT_RUNTIME_COUNTER(runtime_call_stats_, + PreParseWithVariableResolution); + } + } - // Validate name and parameter names. We can do this only after parsing the - // function, since the function can declare itself strict. + // Validate function name. We can do this only after parsing the function, + // since the function can declare itself strict. + language_mode = scope->language_mode(); CheckFunctionName(language_mode, function_name, function_name_validity, function_name_location, CHECK_OK); - const bool allow_duplicate_parameters = - is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind); - ValidateFormalParameters(language_mode, allow_duplicate_parameters, - CHECK_OK); if (is_strict(language_mode)) { CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), @@ -2756,13 +2720,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( scope->end_position()); } CheckConflictingVarDeclarations(scope, CHECK_OK); - - if (body) { - // If body can be inspected, rewrite queued destructuring assignments - RewriteDestructuringAssignments(); - } - has_duplicate_parameters = - !classifier()->is_valid_formal_parameter_list_without_duplicates(); } // DiscardableZoneScope goes out of scope. FunctionLiteral::ParameterFlag duplicate_parameters = @@ -2772,8 +2729,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // Note that the FunctionLiteral needs to be created in the main Zone again. FunctionLiteral* function_literal = factory()->NewFunctionLiteral( function_name, scope, body, materialized_literal_count, - expected_property_count, arity, duplicate_parameters, function_type, - eager_compile_hint, pos); + expected_property_count, num_parameters, function_length, + duplicate_parameters, function_type, eager_compile_hint, pos, true); function_literal->set_function_token_position(function_token_pos); if (should_be_used_once_hint) function_literal->set_should_be_used_once_hint(); @@ -2785,44 +2742,72 @@ FunctionLiteral* Parser::ParseFunctionLiteral( return function_literal; } -Parser::LazyParsingResult Parser::SkipLazyFunctionBody( +Parser::LazyParsingResult Parser::SkipFunction( + FunctionKind kind, DeclarationScope* function_scope, int* num_parameters, + int* function_length, bool* has_duplicate_parameters, int* materialized_literal_count, int* expected_property_count, bool is_inner_function, bool may_abort, bool* ok) { + DCHECK_NE(kNoSourcePosition, function_scope->start_position()); if (produce_cached_parse_data()) CHECK(log_); - int function_block_pos = position(); - DeclarationScope* scope = function_state_->scope(); - DCHECK(scope->is_function_scope()); + DCHECK_IMPLIES(IsArrowFunction(kind), + scanner()->current_token() == Token::ARROW); + // Inner functions are not part of the cached data. if (!is_inner_function && consume_cached_parse_data() && !cached_parse_data_->rejected()) { - // If we have cached data, we use it to skip parsing the function body. The - // data contains the information we need to construct the lazy function. + // If we have cached data, we use it to skip parsing the function. The data + // contains the information we need to construct the lazy function. FunctionEntry entry = - cached_parse_data_->GetFunctionEntry(function_block_pos); + cached_parse_data_->GetFunctionEntry(function_scope->start_position()); // Check that cached data is valid. If not, mark it as invalid (the embedder // handles it). Note that end position greater than end of stream is safe, // and hard to check. - if (entry.is_valid() && entry.end_pos() > function_block_pos) { + if (entry.is_valid() && + entry.end_pos() > function_scope->start_position()) { + total_preparse_skipped_ += entry.end_pos() - position(); + function_scope->set_end_position(entry.end_pos()); scanner()->SeekForward(entry.end_pos() - 1); - - scope->set_end_position(entry.end_pos()); Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); - total_preparse_skipped_ += scope->end_position() - function_block_pos; + *num_parameters = entry.num_parameters(); + *function_length = entry.function_length(); + *has_duplicate_parameters = entry.has_duplicate_parameters(); *materialized_literal_count = entry.literal_count(); *expected_property_count = entry.property_count(); - SetLanguageMode(scope, entry.language_mode()); - if (entry.uses_super_property()) scope->RecordSuperPropertyUsage(); - if (entry.calls_eval()) scope->RecordEvalCall(); + SetLanguageMode(function_scope, entry.language_mode()); + if (entry.uses_super_property()) + function_scope->RecordSuperPropertyUsage(); + if (entry.calls_eval()) function_scope->RecordEvalCall(); return kLazyParsingComplete; } cached_parse_data_->Reject(); } + // With no cached data, we partially parse the function, without building an // AST. This gathers the data needed to build a lazy function. - SingletonLogger logger; - PreParser::PreParseResult result = - ParseLazyFunctionBodyWithPreParser(&logger, is_inner_function, may_abort); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse"); + + if (reusable_preparser_ == NULL) { + reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(), + &pending_error_handler_, + runtime_call_stats_, stack_limit_); + reusable_preparser_->set_allow_lazy(true); +#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); + SET_ALLOW(natives); + SET_ALLOW(harmony_do_expressions); + SET_ALLOW(harmony_function_sent); + SET_ALLOW(harmony_async_await); + SET_ALLOW(harmony_trailing_commas); + SET_ALLOW(harmony_class_fields); +#undef SET_ALLOW + } + // Aborting inner function preparsing would leave scopes in an inconsistent + // state; we don't parse inner functions in the abortable mode anyway. + DCHECK(!is_inner_function || !may_abort); + + PreParser::PreParseResult result = reusable_preparser_->PreParseFunction( + kind, function_scope, parsing_module_, is_inner_function, may_abort, + use_counts_); // Return immediately if pre-parser decided to abort parsing. if (result == PreParser::kPreParseAbort) return kLazyParsingAborted; @@ -2832,28 +2817,27 @@ Parser::LazyParsingResult Parser::SkipLazyFunctionBody( *ok = false; return kLazyParsingComplete; } - if (logger.has_error()) { - ReportMessageAt(Scanner::Location(logger.start(), logger.end()), - logger.message(), logger.argument_opt(), - logger.error_type()); + if (pending_error_handler_.has_pending_error()) { *ok = false; return kLazyParsingComplete; } - scope->set_end_position(logger.end()); + PreParserLogger* logger = reusable_preparser_->logger(); + function_scope->set_end_position(logger->end()); Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); - total_preparse_skipped_ += scope->end_position() - function_block_pos; - *materialized_literal_count = logger.literals(); - *expected_property_count = logger.properties(); - SetLanguageMode(scope, logger.language_mode()); - if (logger.uses_super_property()) scope->RecordSuperPropertyUsage(); - if (logger.calls_eval()) scope->RecordEvalCall(); + total_preparse_skipped_ += + function_scope->end_position() - function_scope->start_position(); + *num_parameters = logger->num_parameters(); + *function_length = logger->function_length(); + *has_duplicate_parameters = logger->has_duplicate_parameters(); + *materialized_literal_count = logger->literals(); + *expected_property_count = logger->properties(); if (!is_inner_function && produce_cached_parse_data()) { DCHECK(log_); - // Position right after terminal '}'. - int body_end = scanner()->location().end_pos; - log_->LogFunction(function_block_pos, body_end, *materialized_literal_count, - *expected_property_count, language_mode(), - scope->uses_super_property(), scope->calls_eval()); + log_->LogFunction( + function_scope->start_position(), function_scope->end_position(), + *num_parameters, *function_length, *has_duplicate_parameters, + *materialized_literal_count, *expected_property_count, language_mode(), + function_scope->uses_super_property(), function_scope->calls_eval()); } return kLazyParsingComplete; } @@ -3126,15 +3110,57 @@ Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) { Yield::kOnExceptionThrow); } +ZoneList<Statement*>* Parser::ParseFunction( + const AstRawString* function_name, int pos, FunctionKind kind, + FunctionLiteral::FunctionType function_type, + DeclarationScope* function_scope, int* num_parameters, int* function_length, + bool* has_duplicate_parameters, int* materialized_literal_count, + int* expected_property_count, bool* ok) { + FunctionState function_state(&function_state_, &scope_state_, function_scope); + + DuplicateFinder duplicate_finder(scanner()->unicode_cache()); + ExpressionClassifier formals_classifier(this, &duplicate_finder); + + if (IsGeneratorFunction(kind)) PrepareGeneratorVariables(&function_state); + + ParserFormalParameters formals(function_scope); + ParseFormalParameterList(&formals, CHECK_OK); + Expect(Token::RPAREN, CHECK_OK); + int formals_end_position = scanner()->location().end_pos; + *num_parameters = formals.num_parameters(); + *function_length = formals.function_length; + + CheckArityRestrictions(formals.arity, kind, formals.has_rest, + function_scope->start_position(), formals_end_position, + CHECK_OK); + Expect(Token::LBRACE, CHECK_OK); + + ZoneList<Statement*>* body = ParseEagerFunctionBody( + function_name, pos, formals, kind, function_type, ok); + + // Validate parameter names. We can do this only after parsing the function, + // since the function can declare itself strict. + const bool allow_duplicate_parameters = + is_sloppy(function_scope->language_mode()) && formals.is_simple && + !IsConciseMethod(kind); + ValidateFormalParameters(function_scope->language_mode(), + allow_duplicate_parameters, CHECK_OK); + + RewriteDestructuringAssignments(); + + *has_duplicate_parameters = + !classifier()->is_valid_formal_parameter_list_without_duplicates(); + + *materialized_literal_count = function_state.materialized_literal_count(); + *expected_property_count = function_state.expected_property_count(); + return body; +} + ZoneList<Statement*>* Parser::ParseEagerFunctionBody( const AstRawString* function_name, int pos, const ParserFormalParameters& parameters, FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) { - // Everything inside an eagerly parsed function will be parsed eagerly (see - // comment above). Lazy inner functions are handled separately and they won't - // require the mode to be PARSE_LAZILY (see ParseFunctionLiteral). - // TODO(marja): Refactor parsing modes: remove this. - ParsingModeScope parsing_mode(this, PARSE_EAGERLY); + ParsingModeScope mode(this, allow_lazy() ? PARSE_LAZILY : PARSE_EAGERLY); ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone()); static const int kFunctionNameAssignmentIndex = 0; @@ -3286,46 +3312,6 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( return result; } -PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( - SingletonLogger* logger, bool is_inner_function, bool may_abort) { - // This function may be called on a background thread too; record only the - // main thread preparse times. - if (pre_parse_timer_ != NULL) { - pre_parse_timer_->Start(); - } - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse"); - - DCHECK_EQ(Token::LBRACE, scanner()->current_token()); - - if (reusable_preparser_ == NULL) { - reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(), - NULL, stack_limit_); - reusable_preparser_->set_allow_lazy(true); -#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); - SET_ALLOW(natives); - SET_ALLOW(harmony_do_expressions); - SET_ALLOW(harmony_for_in); - SET_ALLOW(harmony_function_sent); - SET_ALLOW(harmony_restrictive_declarations); - SET_ALLOW(harmony_async_await); - SET_ALLOW(harmony_trailing_commas); - SET_ALLOW(harmony_class_fields); -#undef SET_ALLOW - } - // Aborting inner function preparsing would leave scopes in an inconsistent - // state; we don't parse inner functions in the abortable mode anyway. - DCHECK(!is_inner_function || !may_abort); - - DeclarationScope* function_scope = function_state_->scope(); - PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( - function_scope, parsing_module_, logger, is_inner_function, may_abort, - use_counts_); - if (pre_parse_timer_ != NULL) { - pre_parse_timer_->Stop(); - } - return result; -} - Expression* Parser::InstallHomeObject(Expression* function_literal, Expression* home_object) { Block* do_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); @@ -3426,12 +3412,12 @@ FunctionLiteral* Parser::SynthesizeClassFieldInitializer(int count) { FunctionLiteral* function_literal = factory()->NewFunctionLiteral( ast_value_factory()->empty_string(), initializer_scope, body, initializer_state.materialized_literal_count(), - initializer_state.expected_property_count(), 0, + initializer_state.expected_property_count(), 0, count, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, - FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position()); + FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position(), + true); function_literal->set_is_class_field_initializer(true); - function_literal->scope()->set_arity(count); return function_literal; } @@ -3442,7 +3428,7 @@ FunctionLiteral* Parser::InsertClassFieldInitializer( constructor->scope(), constructor->scope()->NewUnresolved( factory(), ast_value_factory()->this_string(), kNoSourcePosition, - kNoSourcePosition + 4, THIS_VARIABLE)), + THIS_VARIABLE)), kNoSourcePosition); constructor->body()->InsertAt(0, call_initializer, zone()); return constructor; @@ -3636,6 +3622,7 @@ Expression* Parser::RewriteClassLiteral(const AstRawString* name, } do_block->set_scope(scope()->FinalizeBlockScope()); do_expr->set_represented_function(class_info->constructor); + AddFunctionForNameInference(class_info->constructor); return do_expr; } @@ -3668,10 +3655,8 @@ void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) { DCHECK(inner_scope->is_declaration_scope()); Scope* function_scope = inner_scope->outer_scope(); DCHECK(function_scope->is_function_scope()); - ZoneList<Declaration*>* decls = inner_scope->declarations(); BlockState block_state(&scope_state_, inner_scope); - for (int i = 0; i < decls->length(); ++i) { - Declaration* decl = decls->at(i); + for (Declaration* decl : *inner_scope->declarations()) { if (decl->proxy()->var()->mode() != VAR || !decl->IsVariableDeclaration()) { continue; } @@ -3781,6 +3766,15 @@ void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) { } isolate->counters()->total_preparse_skipped()->Increment( total_preparse_skipped_); + if (!parsing_on_main_thread_ && + FLAG_runtime_stats == + v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE) { + // Copy over the counters from the background thread to the main counters on + // the isolate. + // TODO(cbruni,lpy): properly attach the runtime stats to the trace for + // background parsing. + isolate->counters()->runtime_call_stats()->Add(runtime_call_stats_); + } } @@ -3804,18 +3798,12 @@ bool Parser::Parse(ParseInfo* info) { // Ok to use Isolate here; this function is only called in the main thread. DCHECK(parsing_on_main_thread_); Isolate* isolate = info->isolate(); - pre_parse_timer_ = isolate->counters()->pre_parse(); - if (info->is_lazy()) { - DCHECK(!info->is_eval()); - if (info->shared_info()->is_function()) { - result = ParseLazy(isolate, info); - } else { - result = ParseProgram(isolate, info); - } - } else { + if (info->is_toplevel()) { SetCachedData(info); result = ParseProgram(isolate, info); + } else { + result = ParseFunction(isolate, info); } info->set_literal(result); @@ -3830,8 +3818,12 @@ void Parser::ParseOnBackground(ParseInfo* info) { DCHECK(info->literal() == NULL); FunctionLiteral* result = NULL; - CompleteParserRecorder recorder; - if (produce_cached_parse_data()) log_ = &recorder; + ParserLogger logger; + if (produce_cached_parse_data()) log_ = &logger; + if (FLAG_runtime_stats) { + // Create separate runtime stats for background parsing. + runtime_call_stats_ = new (zone()) RuntimeCallStats(); + } std::unique_ptr<Utf16CharacterStream> stream; Utf16CharacterStream* stream_ptr; @@ -3854,12 +3846,12 @@ void Parser::ParseOnBackground(ParseInfo* info) { // don't). We work around this by storing all the scopes which need their end // position set at the end of the script (the top scope and possible eval // scopes) and set their end position after we know the script length. - if (info->is_lazy()) { - result = DoParseLazy(info, info->function_name(), stream_ptr); - } else { + if (info->is_toplevel()) { fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); scanner_.Initialize(stream_ptr); result = DoParseProgram(info); + } else { + result = DoParseFunction(info, info->function_name(), stream_ptr); } info->set_literal(result); @@ -3868,9 +3860,13 @@ void Parser::ParseOnBackground(ParseInfo* info) { // care of calling Parser::Internalize just before compilation. if (produce_cached_parse_data()) { - if (result != NULL) *info->cached_data() = recorder.GetScriptData(); + if (result != NULL) *info->cached_data() = logger.GetScriptData(); log_ = NULL; } + if (FLAG_runtime_stats) { + // TODO(cbruni,lpy): properly attach the runtime stats to the trace for + // background parsing. + } } Parser::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) { @@ -3943,9 +3939,9 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos), zone()); - // Ensure hash is suitable as a Smi value + // Truncate hash to Smi-range. Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash))); - args->Add(factory()->NewSmiLiteral(hash_obj->value(), pos), zone()); + args->Add(factory()->NewNumberLiteral(hash_obj->value(), pos), zone()); Expression* call_site = factory()->NewCallRuntime( Context::GET_TEMPLATE_CALL_SITE_INDEX, args, start); @@ -4002,7 +3998,7 @@ ZoneList<Expression*>* Parser::PrepareSpreadArguments( ZoneList<Expression*>* spread_list = new (zone()) ZoneList<Expression*>(0, zone()); spread_list->Add(list->at(0)->AsSpread()->expression(), zone()); - args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX, + args->Add(factory()->NewCallRuntime(Runtime::kSpreadIterablePrepare, spread_list, kNoSourcePosition), zone()); return args; @@ -4338,8 +4334,7 @@ Expression* Parser::RewriteAssignExponentiation(Expression* left, Expression* result; DCHECK_NOT_NULL(lhs->raw_name()); - result = ExpressionFromIdentifier(lhs->raw_name(), lhs->position(), - lhs->end_position()); + result = ExpressionFromIdentifier(lhs->raw_name(), lhs->position()); args->Add(left, zone()); args->Add(right, zone()); Expression* call = |