diff options
Diffstat (limited to 'deps/v8/src/parsing/parser.cc')
-rw-r--r-- | deps/v8/src/parsing/parser.cc | 578 |
1 files changed, 297 insertions, 281 deletions
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index a554d7d242..4d291a741e 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -8,7 +8,6 @@ #include <memory> #include "src/api.h" -#include "src/ast/ast-expression-rewriter.h" #include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast.h" @@ -16,6 +15,7 @@ #include "src/base/platform/platform.h" #include "src/char-predicates-inl.h" #include "src/compiler-dispatcher/compiler-dispatcher.h" +#include "src/log.h" #include "src/messages.h" #include "src/objects-inl.h" #include "src/parsing/duplicate-finder.h" @@ -173,11 +173,11 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, FunctionKind kind = call_super ? FunctionKind::kDefaultDerivedConstructor : FunctionKind::kDefaultBaseConstructor; DeclarationScope* function_scope = NewFunctionScope(kind); - SetLanguageMode(function_scope, STRICT); + SetLanguageMode(function_scope, LanguageMode::kStrict); // Set start and end position to the same value function_scope->set_start_position(pos); function_scope->set_end_position(pos); - ZoneList<Statement*>* body = NULL; + ZoneList<Statement*>* body = nullptr; { FunctionState function_state(&function_state_, &scope_, function_scope); @@ -212,7 +212,6 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, parameter_count, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, true, GetNextFunctionLiteralId()); - return function_literal; } @@ -245,10 +244,9 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y, Token::Value op, int pos) { - if ((*x)->AsLiteral() && (*x)->AsLiteral()->raw_value()->IsNumber() && - y->AsLiteral() && y->AsLiteral()->raw_value()->IsNumber()) { - double x_val = (*x)->AsLiteral()->raw_value()->AsNumber(); - double y_val = y->AsLiteral()->raw_value()->AsNumber(); + if ((*x)->IsNumberLiteral() && y->IsNumberLiteral()) { + double x_val = (*x)->AsLiteral()->AsNumber(); + double y_val = y->AsLiteral()->AsNumber(); switch (op) { case Token::ADD: *x = factory()->NewNumberLiteral(x_val + y_val, pos); @@ -308,16 +306,48 @@ bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x, return false; } +bool Parser::CollapseNaryExpression(Expression** x, Expression* y, + Token::Value op, int pos, + const SourceRange& range) { + // Filter out unsupported ops. + if (!Token::IsBinaryOp(op) || op == Token::EXP) return false; + + // Convert *x into an nary operation with the given op, returning false if + // this is not possible. + NaryOperation* nary = nullptr; + if ((*x)->IsBinaryOperation()) { + BinaryOperation* binop = (*x)->AsBinaryOperation(); + if (binop->op() != op) return false; + + nary = factory()->NewNaryOperation(op, binop->left(), 2); + nary->AddSubsequent(binop->right(), binop->position()); + ConvertBinaryToNaryOperationSourceRange(binop, nary); + *x = nary; + } else if ((*x)->IsNaryOperation()) { + nary = (*x)->AsNaryOperation(); + if (nary->op() != op) return false; + } else { + return false; + } + + // Append our current expression to the nary operation. + // TODO(leszeks): Do some literal collapsing here if we're appending Smi or + // String literals. + nary->AddSubsequent(y, pos); + AppendNaryOperationSourceRange(nary, range); + + return true; +} + Expression* Parser::BuildUnaryExpression(Expression* expression, Token::Value op, int pos) { - DCHECK(expression != NULL); - if (expression->IsLiteral()) { - const AstValue* literal = expression->AsLiteral()->raw_value(); + DCHECK_NOT_NULL(expression); + const Literal* literal = expression->AsLiteral(); + if (literal != nullptr) { if (op == Token::NOT) { // Convert the literal to a boolean condition and negate it. - bool condition = literal->BooleanValue(); - return factory()->NewBooleanLiteral(!condition, pos); - } else if (literal->IsNumber()) { + return factory()->NewBooleanLiteral(literal->ToBooleanIsFalse(), pos); + } else if (literal->IsNumberLiteral()) { // Compute some expressions involving only number literals. double value = literal->AsNumber(); switch (op) { @@ -383,6 +413,12 @@ Expression* Parser::FunctionSentExpression(int pos) { args, pos); } +Expression* Parser::ImportMetaExpression(int pos) { + return factory()->NewCallRuntime( + Runtime::kInlineGetImportMetaObject, + new (zone()) ZoneList<Expression*>(0, zone()), pos); +} + Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { switch (token) { case Token::NULL_LITERAL: @@ -399,10 +435,13 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { double value = scanner()->DoubleValue(); return factory()->NewNumberLiteral(value, pos); } + case Token::BIGINT: + return factory()->NewBigIntLiteral( + AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos); default: DCHECK(false); } - return NULL; + return nullptr; } Expression* Parser::NewV8Intrinsic(const AstRawString* name, @@ -463,7 +502,10 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name, Parser::Parser(ParseInfo* info) : ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(), info->extension(), info->GetOrCreateAstValueFactory(), - info->runtime_call_stats(), true), + info->pending_error_handler(), + info->runtime_call_stats(), info->logger(), + info->script().is_null() ? -1 : info->script()->id(), + info->is_module(), true), scanner_(info->unicode_cache(), use_counts_), reusable_preparser_(nullptr), mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. @@ -479,7 +521,7 @@ Parser::Parser(ParseInfo* info) // 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->character_stream() != nullptr); + DCHECK_NOT_NULL(info->character_stream()); // 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 @@ -500,13 +542,11 @@ Parser::Parser(ParseInfo* info) set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); set_allow_harmony_do_expressions(FLAG_harmony_do_expressions); set_allow_harmony_function_sent(FLAG_harmony_function_sent); - set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators); - set_allow_harmony_class_fields(FLAG_harmony_class_fields); - set_allow_harmony_object_rest_spread(FLAG_harmony_object_rest_spread); + set_allow_harmony_public_fields(FLAG_harmony_public_fields); set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import); set_allow_harmony_import_meta(FLAG_harmony_import_meta); set_allow_harmony_async_iteration(FLAG_harmony_async_iteration); - set_allow_harmony_template_escapes(FLAG_harmony_template_escapes); + set_allow_harmony_bigint(FLAG_harmony_bigint); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; @@ -527,7 +567,6 @@ void Parser::DeserializeScopeChain( scope = Scope::DeserializeScopeChain( zone(), *outer_scope_info, script_scope, ast_value_factory(), Scope::DeserializationMode::kScopesOnly); - DCHECK(!info->is_module() || scope->is_module_scope()); } original_scope_ = scope; } @@ -557,9 +596,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { : &RuntimeCallStats::ParseProgram); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseProgram"); base::ElapsedTimer timer; - if (FLAG_trace_parse) { - timer.Start(); - } + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); // Initialize parser state. @@ -583,23 +620,25 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { HandleSourceURLComments(isolate, info->script()); - if (FLAG_trace_parse && result != nullptr) { - double ms = timer.Elapsed().InMillisecondsF(); - if (info->is_eval()) { - PrintF("[parsing eval"); - } else if (info->script()->name()->IsString()) { - String* name = String::cast(info->script()->name()); - std::unique_ptr<char[]> name_chars = name->ToCString(); - PrintF("[parsing script: %s", name_chars.get()); - } else { - PrintF("[parsing script"); - } - PrintF(" - took %0.3f ms]\n", ms); - } if (produce_cached_parse_data() && result != nullptr) { *info->cached_data() = logger.GetScriptData(); } log_ = nullptr; + + if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) { + double ms = timer.Elapsed().InMillisecondsF(); + const char* event_name = "parse-eval"; + Script* script = *info->script(); + int start = -1; + int end = -1; + if (!info->is_eval()) { + event_name = "parse-script"; + start = 0; + end = String::cast(script->source())->length(); + } + LOG(script->GetIsolate(), + FunctionEvent(event_name, script, -1, ms, start, end, "", 0)); + } return result; } @@ -616,11 +655,10 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { DCHECK(info->function_literal_id() == FunctionLiteral::kIdTypeTopLevel || info->function_literal_id() == FunctionLiteral::kIdTypeInvalid); - FunctionLiteral* result = NULL; + FunctionLiteral* result = nullptr; { Scope* outer = original_scope_; DCHECK_NOT_NULL(outer); - parsing_module_ = info->is_module(); if (info->is_eval()) { outer = NewEvalScope(outer); } else if (parsing_module_) { @@ -638,6 +676,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { bool ok = true; int beg_pos = scanner()->location().beg_pos; if (parsing_module_) { + DCHECK(info->is_module()); // Declare the special module parameter. auto name = ast_value_factory()->empty_string(); bool is_duplicate = false; @@ -658,9 +697,8 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { zone()); ParseModuleItemList(body, &ok); - ok = ok && - module()->Validate(this->scope()->AsModuleScope(), - &pending_error_handler_, zone()); + ok = ok && module()->Validate(this->scope()->AsModuleScope(), + pending_error_handler(), zone()); } else { // Don't count the mode in the use counters--give the program a chance // to enable script-wide strict mode below. @@ -708,7 +746,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { info->set_max_function_literal_id(GetLastFunctionLiteralId()); // Make sure the target stack is empty. - DCHECK(target_stack_ == NULL); + DCHECK_NULL(target_stack_); return result; } @@ -722,9 +760,8 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, &RuntimeCallStats::ParseFunction); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseFunction"); base::ElapsedTimer timer; - if (FLAG_trace_parse) { - timer.Start(); - } + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); + DeserializeScopeChain(info, info->maybe_outer_scope_info()); DCHECK_EQ(factory()->zone(), info->zone()); @@ -740,12 +777,18 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, result->set_inferred_name(inferred_name); } - if (FLAG_trace_parse && result != NULL) { + if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) { double ms = timer.Elapsed().InMillisecondsF(); // We need to make sure that the debug-name is available. ast_value_factory()->Internalize(isolate); - std::unique_ptr<char[]> name_chars = result->debug_name()->ToCString(); - PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms); + DeclarationScope* function_scope = result->scope(); + Script* script = *info->script(); + std::unique_ptr<char[]> function_name = result->GetDebugName(); + LOG(script->GetIsolate(), + FunctionEvent("parse-function", script, -1, ms, + function_scope->start_position(), + function_scope->end_position(), function_name.get(), + strlen(function_name.get()))); } return result; } @@ -888,6 +931,11 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind, kNoSourcePosition, function_type, info->language_mode(), &ok); } + + if (ok) { + result->set_requires_instance_fields_initializer( + info->requires_instance_fields_initializer()); + } // Make sure the results agree. DCHECK(ok == (result != nullptr)); } @@ -979,11 +1027,12 @@ void Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, // Keep track of the first reserved word encountered in case our // caller needs to report an error. if (!reserved_loc->IsValid() && - !Token::IsIdentifier(name_tok, STRICT, false, parsing_module_)) { + !Token::IsIdentifier(name_tok, LanguageMode::kStrict, false, + parsing_module_)) { *reserved_loc = scanner()->location(); } const AstRawString* local_name = ParseIdentifierName(CHECK_OK_VOID); - const AstRawString* export_name = NULL; + const AstRawString* export_name = nullptr; Scanner::Location location = scanner()->location(); if (CheckContextualKeyword(Token::AS)) { export_name = ParseIdentifierName(CHECK_OK_VOID); @@ -991,7 +1040,7 @@ void Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, // both for errors due to "a" and for errors due to "b". location.end_pos = scanner()->location().end_pos; } - if (export_name == NULL) { + if (export_name == nullptr) { export_name = local_name; } export_names->Add(export_name, zone()); @@ -1033,8 +1082,8 @@ ZoneList<const Parser::NamedImport*>* Parser::ParseNamedImports( if (CheckContextualKeyword(Token::AS)) { local_name = ParseIdentifierName(CHECK_OK); } - if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false, - parsing_module_)) { + if (!Token::IsIdentifier(scanner()->current_token(), LanguageMode::kStrict, + false, parsing_module_)) { *ok = false; ReportMessage(MessageTemplate::kUnexpectedReserved); return nullptr; @@ -1393,8 +1442,8 @@ Variable* Parser::Declare(Declaration* declaration, } bool sloppy_mode_block_scope_function_redefinition = false; Variable* variable = scope->DeclareVariable( - declaration, mode, init, allow_harmony_restrictive_generators(), - &sloppy_mode_block_scope_function_redefinition, ok); + declaration, mode, init, &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 @@ -1778,25 +1827,13 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody( zone()); } -void Parser::CreateFunctionNameAssignment( - const AstRawString* function_name, int pos, - FunctionLiteral::FunctionType function_type, - DeclarationScope* function_scope, ZoneList<Statement*>* result, int index) { - if (function_type == FunctionLiteral::kNamedExpression) { - StatementT statement = factory()->NewEmptyStatement(kNoSourcePosition); - if (function_scope->LookupLocal(function_name) == nullptr) { - // Now that we know the language mode, we can create the const assignment - // in the previously reserved spot. - DCHECK_EQ(function_scope, scope()); - Variable* fvar = function_scope->DeclareFunctionVar(function_name); - VariableProxy* fproxy = factory()->NewVariableProxy(fvar); - statement = factory()->NewExpressionStatement( - factory()->NewAssignment(Token::INIT, fproxy, - factory()->NewThisFunction(pos), - kNoSourcePosition), - kNoSourcePosition); - } - result->Set(index, statement); +void Parser::DeclareFunctionNameVar(const AstRawString* function_name, + FunctionLiteral::FunctionType function_type, + DeclarationScope* function_scope) { + if (function_type == FunctionLiteral::kNamedExpression && + function_scope->LookupLocal(function_name) == nullptr) { + DCHECK_EQ(function_scope, scope()); + function_scope->DeclareFunctionVar(function_name); } } @@ -1851,7 +1888,7 @@ Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt, Expression* subject, Statement* body) { ForOfStatement* for_of = stmt->AsForOfStatement(); - if (for_of != NULL) { + if (for_of != nullptr) { const bool finalize = true; return InitializeForOfStatement(for_of, each, subject, body, finalize, IteratorType::kNormal, each->position()); @@ -2155,7 +2192,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // } // } - DCHECK(for_info.bound_names.length() > 0); + DCHECK_GT(for_info.bound_names.length(), 0); ZoneList<Variable*> temps(for_info.bound_names.length(), zone()); Block* outer_block = @@ -2180,7 +2217,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( temps.Add(temp, zone()); } - Variable* first = NULL; + Variable* first = nullptr; // Make statement: first = 1. if (next) { first = NewTemporary(temp_name); @@ -2205,7 +2242,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // need to know about it. This should be safe because we don't run any code // in this function that looks up break targets. ForStatement* outer_loop = - factory()->NewForStatement(NULL, kNoSourcePosition); + factory()->NewForStatement(nullptr, kNoSourcePosition); outer_block->statements()->Add(outer_loop, zone()); outer_block->set_scope(scope()); @@ -2229,7 +2266,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( Statement* assignment_statement = factory()->NewExpressionStatement(assignment, kNoSourcePosition); int declaration_pos = for_info.parsing_result.descriptor.declaration_pos; - DCHECK(declaration_pos != kNoSourcePosition); + DCHECK_NE(declaration_pos, kNoSourcePosition); decl->proxy()->var()->set_initializer_position(declaration_pos); ignore_completion_block->statements()->Add(assignment_statement, zone()); } @@ -2237,7 +2274,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // Make statement: if (first == 1) { first = 0; } else { next; } if (next) { DCHECK(first); - Expression* compare = NULL; + Expression* compare = nullptr; // Make compare expression: first == 1. { Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition); @@ -2245,7 +2282,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1, kNoSourcePosition); } - Statement* clear_first = NULL; + Statement* clear_first = nullptr; // Make statement: first = 0. { VariableProxy* first_proxy = factory()->NewVariableProxy(first); @@ -2284,7 +2321,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( inner_block->statements()->Add(ignore_completion_block, zone()); // Make cond expression for main loop: flag == 1. - Expression* flag_cond = NULL; + Expression* flag_cond = nullptr; { Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition); VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); @@ -2293,9 +2330,9 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( } // Create chain of expressions "flag = 0, temp_x = x, ..." - Statement* compound_next_statement = NULL; + Statement* compound_next_statement = nullptr; { - Expression* compound_next = NULL; + Expression* compound_next = nullptr; // Make expression: flag = 0. { VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); @@ -2324,12 +2361,12 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // Note that we re-use the original loop node, which retains its labels // and ensures that any break or continue statements in body point to // the right place. - loop->Initialize(NULL, flag_cond, compound_next_statement, body); + loop->Initialize(nullptr, flag_cond, compound_next_statement, body); inner_block->statements()->Add(loop, zone()); // Make statement: {{if (flag == 1) break;}} { - Expression* compare = NULL; + Expression* compare = nullptr; // Make compare expresion: flag == 1. { Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition); @@ -2348,7 +2385,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( inner_block->set_scope(inner_scope); } - outer_loop->Initialize(NULL, NULL, NULL, inner_block); + outer_loop->Initialize(nullptr, nullptr, nullptr, inner_block); return outer_block; } @@ -2357,6 +2394,7 @@ void Parser::AddArrowFunctionFormalParameters( ParserFormalParameters* parameters, Expression* expr, int end_pos, bool* ok) { // ArrowFunctionFormals :: + // Nary(Token::COMMA, VariableProxy*, Tail) // Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail) // Tail // NonTailArrowFunctionFormals :: @@ -2366,9 +2404,30 @@ void Parser::AddArrowFunctionFormalParameters( // VariableProxy // Spread(VariableProxy) // - // As we need to visit the parameters in left-to-right order, we recurse on - // the left-hand side of comma expressions. + // We need to visit the parameters in left-to-right order // + + // For the Nary case, we simply visit the parameters in a loop. + if (expr->IsNaryOperation()) { + NaryOperation* nary = expr->AsNaryOperation(); + // The classifier has already run, so we know that the expression is a valid + // arrow function formals production. + DCHECK_EQ(nary->op(), Token::COMMA); + // Each op position is the end position of the *previous* expr, with the + // second (i.e. first "subsequent") op position being the end position of + // the first child expression. + Expression* next = nary->first(); + for (size_t i = 0; i < nary->subsequent_length(); ++i) { + AddArrowFunctionFormalParameters( + parameters, next, nary->subsequent_op_position(i), CHECK_OK_VOID); + next = nary->subsequent(i); + } + AddArrowFunctionFormalParameters(parameters, next, end_pos, CHECK_OK_VOID); + return; + } + + // For the binary case, we recurse on the left-hand side of binary comma + // expressions. if (expr->IsBinaryOperation()) { BinaryOperation* binop = expr->AsBinaryOperation(); // The classifier has already run, so we know that the expression is a valid @@ -2467,7 +2526,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // 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. - bool should_infer_name = function_name == NULL; + bool should_infer_name = function_name == nullptr; // We want a non-null handle as the function name by default. We will handle // the "function does not have a shared name" case later. @@ -2518,8 +2577,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( const bool is_lazy = eager_compile_hint == FunctionLiteral::kShouldLazyCompile; - const bool is_top_level = - impl()->AllowsLazyParsingWithoutUnresolvedVariables(); + const bool is_top_level = AllowsLazyParsingWithoutUnresolvedVariables(); const bool is_lazy_top_level_function = is_lazy && is_top_level; const bool is_lazy_inner_function = is_lazy && !is_top_level; const bool is_expression = @@ -2531,6 +2589,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( parsing_on_main_thread_ ? &RuntimeCallStats::ParseFunctionLiteral : &RuntimeCallStats::ParseBackgroundFunctionLiteral); + base::ElapsedTimer timer; + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); // Determine whether we can still lazy parse the inner function. // The preconditions are: @@ -2631,13 +2691,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral( } DCHECK_EQ(should_preparse, temp_zoned_); - if (V8_UNLIKELY(FLAG_trace_preparse)) { - PrintF(" [%s]: %i-%i %.*s\n", - should_preparse ? (is_top_level ? "Preparse no-resolution" - : "Preparse resolution") - : "Full parse", - scope->start_position(), scope->end_position(), - function_name->byte_length(), function_name->raw_data()); + if (V8_UNLIKELY(FLAG_log_function_events)) { + double ms = timer.Elapsed().InMillisecondsF(); + const char* event_name = should_preparse + ? (is_top_level ? "preparse-no-resolution" + : "preparse-resolution") + : "full-parse"; + logger_->FunctionEvent( + event_name, nullptr, script_id(), ms, scope->start_position(), + scope->end_position(), + reinterpret_cast<const char*>(function_name->raw_data()), + function_name->byte_length()); } if (V8_UNLIKELY(FLAG_runtime_stats)) { if (should_preparse) { @@ -2764,8 +2828,8 @@ Parser::LazyParsingResult Parser::SkipFunction( DCHECK(!is_inner_function || !may_abort); PreParser::PreParseResult result = reusable_preparser()->PreParseFunction( - function_name, kind, function_type, function_scope, parsing_module_, - is_inner_function, may_abort, use_counts_, produced_preparsed_scope_data); + function_name, kind, function_type, function_scope, is_inner_function, + may_abort, use_counts_, produced_preparsed_scope_data, this->script_id()); // Return immediately if pre-parser decided to abort parsing. if (result == PreParser::kPreParseAbort) return kLazyParsingAborted; @@ -2775,7 +2839,7 @@ Parser::LazyParsingResult Parser::SkipFunction( *ok = false; return kLazyParsingComplete; } - if (pending_error_handler_.has_pending_error()) { + if (pending_error_handler()->has_pending_error()) { *ok = false; return kLazyParsingComplete; } @@ -3137,6 +3201,20 @@ void Parser::DeclareClassVariable(const AstRawString* name, } } +// TODO(gsathya): Ideally, this should just bypass scope analysis and +// allocate a slot directly on the context. We should just store this +// index in the AST, instead of storing the variable. +Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name, + bool* ok) { + VariableProxy* proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE); + Declaration* declaration = + factory()->NewVariableDeclaration(proxy, kNoSourcePosition); + Variable* var = Declare(declaration, DeclarationDescriptor::NORMAL, CONST, + Variable::DefaultInitializationFlag(CONST), CHECK_OK); + var->ForceContextAllocation(); + return var; +} + // This method declares a property of the given class. It updates the // following fields of class_info, as appropriate: // - constructor @@ -3145,7 +3223,8 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, ClassLiteralProperty* property, ClassLiteralProperty::Kind kind, bool is_static, bool is_constructor, - ClassInfo* class_info, bool* ok) { + bool is_computed_name, ClassInfo* class_info, + bool* ok) { if (is_constructor) { DCHECK(!class_info->constructor); class_info->constructor = property->value()->AsFunctionLiteral(); @@ -3156,11 +3235,44 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, return; } - if (property->kind() == ClassLiteralProperty::FIELD) { - DCHECK(allow_harmony_class_fields()); - // TODO(littledan): Implement class fields + if (kind != ClassLiteralProperty::FIELD) { + class_info->properties->Add(property, zone()); + return; + } + + DCHECK(allow_harmony_public_fields()); + + if (is_static) { + class_info->static_fields->Add(property, zone()); + } else { + class_info->instance_fields->Add(property, zone()); + } + + if (is_computed_name) { + // We create a synthetic variable name here so that scope + // analysis doesn't dedupe the vars. + Variable* computed_name_var = CreateSyntheticContextVariable( + ClassFieldVariableName(ast_value_factory(), + class_info->computed_field_count), + CHECK_OK_VOID); + property->set_computed_name_var(computed_name_var); + class_info->properties->Add(property, zone()); } - class_info->properties->Add(property, zone()); +} + +FunctionLiteral* Parser::CreateInitializerFunction( + DeclarationScope* scope, ZoneList<ClassLiteral::Property*>* fields) { + // function() { .. class fields initializer .. } + ZoneList<Statement*>* statements = NewStatementList(1); + InitializeClassFieldsStatement* static_fields = + factory()->NewInitializeClassFieldsStatement(fields, kNoSourcePosition); + statements->Add(static_fields, zone()); + return factory()->NewFunctionLiteral( + ast_value_factory()->empty_string(), scope, statements, 0, 0, 0, + FunctionLiteral::kNoDuplicateParameters, + FunctionLiteral::kAnonymousExpression, + FunctionLiteral::kShouldEagerCompile, scope->start_position(), true, + GetNextFunctionLiteralId()); } // This method generates a ClassLiteral AST node. @@ -3177,7 +3289,7 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope, int end_pos, bool* ok) { DCHECK_NOT_NULL(block_scope); DCHECK_EQ(block_scope->scope_type(), BLOCK_SCOPE); - DCHECK_EQ(block_scope->language_mode(), STRICT); + DCHECK_EQ(block_scope->language_mode(), LanguageMode::kStrict); bool has_extends = class_info->extends != nullptr; bool has_default_constructor = class_info->constructor == nullptr; @@ -3191,25 +3303,33 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope, class_info->variable->set_initializer_position(end_pos); } + FunctionLiteral* static_fields_initializer = nullptr; + if (class_info->has_static_class_fields) { + static_fields_initializer = CreateInitializerFunction( + class_info->static_fields_scope, class_info->static_fields); + } + + FunctionLiteral* instance_fields_initializer_function = nullptr; + if (class_info->has_instance_class_fields) { + instance_fields_initializer_function = CreateInitializerFunction( + class_info->instance_fields_scope, class_info->instance_fields); + class_info->constructor->set_requires_instance_fields_initializer(true); + } + ClassLiteral* class_literal = factory()->NewClassLiteral( block_scope, class_info->variable, class_info->extends, - class_info->constructor, class_info->properties, pos, end_pos, - class_info->has_name_static_property, + class_info->constructor, class_info->properties, + static_fields_initializer, instance_fields_initializer_function, pos, + end_pos, class_info->has_name_static_property, class_info->has_static_computed_names, class_info->is_anonymous); AddFunctionForNameInference(class_info->constructor); - return class_literal; } -Literal* Parser::GetLiteralUndefined(int position) { - return factory()->NewUndefinedLiteral(position); -} - - void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { Declaration* decl = scope->CheckConflictingVarDeclarations(); - if (decl != NULL) { + if (decl != nullptr) { // In ES6, conflicting variable bindings are early errors. const AstRawString* name = decl->proxy()->raw_name(); int position = decl->proxy()->position(); @@ -3263,7 +3383,7 @@ void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) { // Parser support bool Parser::TargetStackContainsLabel(const AstRawString* label) { - for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) { + for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) { if (ContainsLabel(t->statement()->labels(), label)) return true; } return false; @@ -3272,31 +3392,31 @@ bool Parser::TargetStackContainsLabel(const AstRawString* label) { BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label, bool* ok) { - bool anonymous = label == NULL; - for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) { + bool anonymous = label == nullptr; + for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) { BreakableStatement* stat = t->statement(); if ((anonymous && stat->is_target_for_anonymous()) || (!anonymous && ContainsLabel(stat->labels(), label))) { return stat; } } - return NULL; + return nullptr; } IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, bool* ok) { - bool anonymous = label == NULL; - for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) { + bool anonymous = label == nullptr; + for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) { IterationStatement* stat = t->statement()->AsIterationStatement(); - if (stat == NULL) continue; + if (stat == nullptr) continue; DCHECK(stat->is_target_for_anonymous()); if (anonymous || ContainsLabel(stat->labels(), label)) { return stat; } } - return NULL; + return nullptr; } @@ -3311,17 +3431,6 @@ void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) { } } -void Parser::ReportErrors(Isolate* isolate, Handle<Script> script) { - if (stack_overflow()) { - isolate->StackOverflow(); - } else { - DCHECK(pending_error_handler_.has_pending_error()); - // Internalize ast values for throwing the pending error. - ast_value_factory()->Internalize(isolate); - pending_error_handler_.ThrowPendingError(isolate, script); - } -} - void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) { // Move statistics to Isolate. for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; @@ -3341,10 +3450,15 @@ void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) { } void Parser::ParseOnBackground(ParseInfo* info) { + RuntimeCallTimerScope runtimeTimer(runtime_call_stats_, + &RuntimeCallStats::ParseBackgroundProgram); parsing_on_main_thread_ = false; + if (!info->script().is_null()) { + set_script_id(info->script()->id()); + } - DCHECK(info->literal() == NULL); - FunctionLiteral* result = NULL; + DCHECK_NULL(info->literal()); + FunctionLiteral* result = nullptr; ParserLogger logger; if (produce_cached_parse_data()) { @@ -3380,17 +3494,8 @@ void Parser::ParseOnBackground(ParseInfo* info) { // care of calling AstValueFactory::Internalize just before compilation. if (produce_cached_parse_data()) { - if (result != NULL) *info->cached_data() = logger.GetScriptData(); - log_ = NULL; - } - if (runtime_call_stats_ && - (FLAG_runtime_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { - auto value = v8::tracing::TracedValue::Create(); - runtime_call_stats_->Dump(value.get()); - TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"), - "V8.RuntimeStats", TRACE_EVENT_SCOPE_THREAD, - "runtime-call-stats", std::move(value)); + if (result != nullptr) *info->cached_data() = logger.GetScriptData(); + log_ = nullptr; } } @@ -3400,17 +3505,13 @@ Parser::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) { void Parser::AddTemplateSpan(TemplateLiteralState* state, bool should_cook, bool tail) { - DCHECK(should_cook || allow_harmony_template_escapes()); - int pos = scanner()->location().beg_pos; int end = scanner()->location().end_pos - (tail ? 1 : 2); - const AstRawString* trv = scanner()->CurrentRawSymbol(ast_value_factory()); - Literal* raw = factory()->NewStringLiteral(trv, pos); + const AstRawString* raw = scanner()->CurrentRawSymbol(ast_value_factory()); if (should_cook) { - const AstRawString* tv = scanner()->CurrentSymbol(ast_value_factory()); - Literal* cooked = factory()->NewStringLiteral(tv, pos); + const AstRawString* cooked = scanner()->CurrentSymbol(ast_value_factory()); (*state)->AddTemplateSpan(cooked, raw, end, zone()); } else { - (*state)->AddTemplateSpan(GetLiteralUndefined(pos), raw, end, zone()); + (*state)->AddTemplateSpan(nullptr, raw, end, zone()); } } @@ -3425,46 +3526,54 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, Expression* tag) { TemplateLiteral* lit = *state; int pos = lit->position(); - const ZoneList<Literal*>* cooked_strings = lit->cooked(); - const ZoneList<Literal*>* raw_strings = lit->raw(); + const ZoneList<const AstRawString*>* cooked_strings = lit->cooked(); + const ZoneList<const AstRawString*>* raw_strings = lit->raw(); const ZoneList<Expression*>* expressions = lit->expressions(); DCHECK_EQ(cooked_strings->length(), raw_strings->length()); DCHECK_EQ(cooked_strings->length(), expressions->length() + 1); if (!tag) { - // Build tree of BinaryOps to simplify code-generation - Expression* expr = cooked_strings->at(0); + Expression* first_string = + factory()->NewStringLiteral(cooked_strings->at(0), kNoSourcePosition); + if (expressions->length() == 0) return first_string; + + // Build N-ary addition op to simplify code-generation. + // TODO(leszeks): Could we just store this expression in the + // TemplateLiteralState and build it as we go? + NaryOperation* expr = factory()->NewNaryOperation( + Token::ADD, first_string, 2 * expressions->length()); + int i = 0; while (i < expressions->length()) { Expression* sub = expressions->at(i++); - Expression* cooked_str = cooked_strings->at(i); + const AstRawString* cooked_str = cooked_strings->at(i); + DCHECK_NOT_NULL(cooked_str); // Let middle be ToString(sub). ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); args->Add(sub, zone()); - Expression* middle = factory()->NewCallRuntime(Runtime::kInlineToString, - args, sub->position()); + Expression* sub_to_string = factory()->NewCallRuntime( + Runtime::kInlineToString, args, sub->position()); - expr = factory()->NewBinaryOperation( - Token::ADD, factory()->NewBinaryOperation( - Token::ADD, expr, middle, expr->position()), - cooked_str, sub->position()); + expr->AddSubsequent(sub_to_string, sub->position()); + expr->AddSubsequent( + factory()->NewStringLiteral(cooked_str, kNoSourcePosition), + sub->position()); } return expr; } else { // GetTemplateObject const int32_t hash = ComputeTemplateLiteralHash(lit); - Expression* template_object = factory()->NewGetTemplateObject( - const_cast<ZoneList<Literal*>*>(cooked_strings), - const_cast<ZoneList<Literal*>*>(raw_strings), hash, pos); + Expression* template_object = + factory()->NewGetTemplateObject(cooked_strings, raw_strings, hash, pos); // Call TagFn ZoneList<Expression*>* call_args = new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone()); call_args->Add(template_object, zone()); call_args->AddAll(*expressions, zone()); - return factory()->NewCall(tag, call_args, pos); + return factory()->NewTaggedTemplate(tag, call_args, pos); } } @@ -3483,7 +3592,7 @@ uint32_t HalfAvalance(uint32_t a) { } // namespace int32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) { - const ZoneList<Literal*>* raw_strings = lit->raw(); + const ZoneList<const AstRawString*>* raw_strings = lit->raw(); int total = raw_strings->length(); DCHECK_GT(total, 0); @@ -3495,8 +3604,7 @@ int32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) { running_hash, "${}", 3); } - const AstRawString* raw_string = - raw_strings->at(index)->AsLiteral()->raw_value()->AsString(); + const AstRawString* raw_string = raw_strings->at(index); if (raw_string->is_one_byte()) { const char* data = reinterpret_cast<const char*>(raw_string->raw_data()); running_hash = StringHasher::ComputeRunningHashOneByte( @@ -3700,53 +3808,18 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block, body->Add(block, zone()); } -class NonPatternRewriter : public AstExpressionRewriter { - public: - NonPatternRewriter(uintptr_t stack_limit, Parser* parser) - : AstExpressionRewriter(stack_limit), parser_(parser) {} - ~NonPatternRewriter() override {} - - private: - bool RewriteExpression(Expression* expr) override { - if (expr->IsRewritableExpression()) return true; - // Rewrite only what could have been a pattern but is not. - if (expr->IsArrayLiteral()) { - // Spread rewriting in array literals. - ArrayLiteral* lit = expr->AsArrayLiteral(); - VisitExpressions(lit->values()); - replacement_ = parser_->RewriteSpreads(lit); - return false; - } - if (expr->IsObjectLiteral()) { - return true; - } - if (expr->IsBinaryOperation() && - expr->AsBinaryOperation()->op() == Token::COMMA) { - return true; - } - // Everything else does not need rewriting. - return false; - } - - void VisitLiteralProperty(LiteralProperty* property) override { - if (property == nullptr) return; - // Do not rewrite (computed) key expressions - AST_REWRITE_PROPERTY(Expression, property, value); - } - - Parser* parser_; -}; - void Parser::RewriteNonPattern(bool* ok) { ValidateExpression(CHECK_OK_VOID); auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite(); int begin = classifier()->GetNonPatternBegin(); int end = non_patterns_to_rewrite->length(); if (begin < end) { - NonPatternRewriter rewriter(stack_limit_, this); for (int i = begin; i < end; i++) { - DCHECK(non_patterns_to_rewrite->at(i)->IsRewritableExpression()); - rewriter.Rewrite(non_patterns_to_rewrite->at(i)); + RewritableExpression* expr = non_patterns_to_rewrite->at(i); + // TODO(adamk): Make this more typesafe. + DCHECK(expr->expression()->IsArrayLiteral()); + ArrayLiteral* lit = expr->expression()->AsArrayLiteral(); + expr->Rewrite(RewriteSpreads(lit)); } non_patterns_to_rewrite->Rewind(begin); } @@ -3759,73 +3832,19 @@ void Parser::RewriteDestructuringAssignments() { for (int i = assignments.length() - 1; i >= 0; --i) { // Rewrite list in reverse, so that nested assignment patterns are rewritten // correctly. - const DestructuringAssignment& pair = assignments.at(i); - RewritableExpression* to_rewrite = - pair.assignment->AsRewritableExpression(); + RewritableExpression* to_rewrite = assignments[i]; DCHECK_NOT_NULL(to_rewrite); if (!to_rewrite->is_rewritten()) { // Since this function is called at the end of parsing the program, // pair.scope may already have been removed by FinalizeBlockScope in the // meantime. - Scope* scope = pair.scope->GetUnremovedScope(); + Scope* scope = to_rewrite->scope()->GetUnremovedScope(); BlockState block_state(&scope_, scope); RewriteDestructuringAssignment(to_rewrite); } } } -Expression* Parser::RewriteExponentiation(Expression* left, Expression* right, - int pos) { - ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); - args->Add(left, zone()); - args->Add(right, zone()); - return factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos); -} - -Expression* Parser::RewriteAssignExponentiation(Expression* left, - Expression* right, int pos) { - ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); - if (left->IsVariableProxy()) { - VariableProxy* lhs = left->AsVariableProxy(); - - Expression* result; - DCHECK_NOT_NULL(lhs->raw_name()); - result = ExpressionFromIdentifier(lhs->raw_name(), lhs->position()); - args->Add(left, zone()); - args->Add(right, zone()); - Expression* call = - factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos); - return factory()->NewAssignment(Token::ASSIGN, result, call, pos); - } else if (left->IsProperty()) { - Property* prop = left->AsProperty(); - auto temp_obj = NewTemporary(ast_value_factory()->empty_string()); - auto temp_key = NewTemporary(ast_value_factory()->empty_string()); - Expression* assign_obj = factory()->NewAssignment( - Token::ASSIGN, factory()->NewVariableProxy(temp_obj), prop->obj(), - kNoSourcePosition); - Expression* assign_key = factory()->NewAssignment( - Token::ASSIGN, factory()->NewVariableProxy(temp_key), prop->key(), - kNoSourcePosition); - args->Add(factory()->NewProperty(factory()->NewVariableProxy(temp_obj), - factory()->NewVariableProxy(temp_key), - left->position()), - zone()); - args->Add(right, zone()); - Expression* call = - factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos); - Expression* target = factory()->NewProperty( - factory()->NewVariableProxy(temp_obj), - factory()->NewVariableProxy(temp_key), kNoSourcePosition); - Expression* assign = - factory()->NewAssignment(Token::ASSIGN, target, call, pos); - return factory()->NewBinaryOperation( - Token::COMMA, assign_obj, - factory()->NewBinaryOperation(Token::COMMA, assign_key, assign, pos), - pos); - } - UNREACHABLE(); -} - Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { // Array literals containing spreads are rewritten using do expressions, e.g. // [1, 2, 3, ...x, 4, ...y, 5] @@ -3860,8 +3879,7 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { // %AppendElement($R, value) // or, in case of a hole, // ++($R.length) - if (!value->IsLiteral() || - !value->AsLiteral()->raw_value()->IsTheHole()) { + if (!value->IsTheHoleLiteral()) { ZoneList<Expression*>* append_element_args = NewExpressionList(2); append_element_args->Add(factory()->NewVariableProxy(result), zone()); append_element_args->Add(value, zone()); @@ -3914,14 +3932,12 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { return factory()->NewDoExpression(do_block, result, lit->position()); } -void Parser::QueueDestructuringAssignmentForRewriting(Expression* expr) { - DCHECK(expr->IsRewritableExpression()); - function_state_->AddDestructuringAssignment( - DestructuringAssignment(expr, scope())); +void Parser::QueueDestructuringAssignmentForRewriting( + RewritableExpression* expr) { + function_state_->AddDestructuringAssignment(expr); } -void Parser::QueueNonPatternForRewriting(Expression* expr, bool* ok) { - DCHECK(expr->IsRewritableExpression()); +void Parser::QueueNonPatternForRewriting(RewritableExpression* expr, bool* ok) { function_state_->AddNonPatternForRewriting(expr, ok); } @@ -4171,7 +4187,7 @@ void Parser::FinalizeIteratorUse(Variable* completion, Expression* condition, Block* block = factory()->NewBlock(2, true); Expression* proxy = factory()->NewVariableProxy(completion); BuildIteratorCloseForCompletion(block->statements(), iter, proxy, type); - DCHECK(block->statements()->length() == 2); + DCHECK_EQ(block->statements()->length(), 2); maybe_close = IgnoreCompletion(factory()->NewIfStatement( condition, block, factory()->NewEmptyStatement(nopos), nopos)); |