diff options
author | Myles Borins <mylesborins@google.com> | 2017-08-01 11:36:44 -0500 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2017-08-01 15:23:15 -0500 |
commit | 0a66b223e149a841669bfad5598e4254589730cb (patch) | |
tree | 5ec050f7f78aafbf5b1e0e50d639fb843141e162 /deps/v8/src/parsing | |
parent | 1782b3836ba58ef0da6b687f2bb970c0bd8199ad (diff) | |
download | android-node-v8-0a66b223e149a841669bfad5598e4254589730cb.tar.gz android-node-v8-0a66b223e149a841669bfad5598e4254589730cb.tar.bz2 android-node-v8-0a66b223e149a841669bfad5598e4254589730cb.zip |
deps: update V8 to 6.0.286.52
PR-URL: https://github.com/nodejs/node/pull/14004
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'deps/v8/src/parsing')
-rw-r--r-- | deps/v8/src/parsing/parse-info.cc | 36 | ||||
-rw-r--r-- | deps/v8/src/parsing/parse-info.h | 27 | ||||
-rw-r--r-- | deps/v8/src/parsing/parser-base.h | 179 | ||||
-rw-r--r-- | deps/v8/src/parsing/parser.cc | 464 | ||||
-rw-r--r-- | deps/v8/src/parsing/parser.h | 41 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparse-data-format.h | 2 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparse-data.cc | 9 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparse-data.h | 31 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparsed-scope-data.cc | 119 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparsed-scope-data.h | 39 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparser.cc | 54 | ||||
-rw-r--r-- | deps/v8/src/parsing/preparser.h | 91 | ||||
-rw-r--r-- | deps/v8/src/parsing/rewriter.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/parsing/scanner-character-streams.cc | 14 | ||||
-rw-r--r-- | deps/v8/src/parsing/scanner.cc | 45 | ||||
-rw-r--r-- | deps/v8/src/parsing/scanner.h | 8 |
16 files changed, 680 insertions, 483 deletions
diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc index 816a854654..12329307ac 100644 --- a/deps/v8/src/parsing/parse-info.cc +++ b/deps/v8/src/parsing/parse-info.cc @@ -50,7 +50,6 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared) set_toplevel(shared->is_toplevel()); set_allow_lazy_parsing(FLAG_lazy_inner_functions); set_is_named_expression(shared->is_named_expression()); - set_calls_eval(shared->scope_info()->CallsEval()); set_compiler_hints(shared->compiler_hints()); set_start_position(shared->start_position()); set_end_position(shared->end_position()); @@ -58,7 +57,6 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared) set_language_mode(shared->language_mode()); set_shared_info(shared); set_module(shared->kind() == FunctionKind::kModule); - set_scope_info_is_empty(shared->scope_info() == ScopeInfo::Empty(isolate)); Handle<Script> script(Script::cast(shared->script())); set_script(script); @@ -107,7 +105,6 @@ ParseInfo* ParseInfo::AllocateWithoutScript(Handle<SharedFunctionInfo> shared) { p->set_toplevel(shared->is_toplevel()); p->set_allow_lazy_parsing(FLAG_lazy_inner_functions); p->set_is_named_expression(shared->is_named_expression()); - p->set_calls_eval(shared->scope_info()->CallsEval()); p->set_compiler_hints(shared->compiler_hints()); p->set_start_position(shared->start_position()); p->set_end_position(shared->end_position()); @@ -115,7 +112,6 @@ ParseInfo* ParseInfo::AllocateWithoutScript(Handle<SharedFunctionInfo> shared) { p->set_language_mode(shared->language_mode()); p->set_shared_info(shared); p->set_module(shared->kind() == FunctionKind::kModule); - p->set_scope_info_is_empty(shared->scope_info() == ScopeInfo::Empty(isolate)); // BUG(5946): This function exists as a workaround until we can // get rid of %SetCode in our native functions. The ParseInfo @@ -168,6 +164,38 @@ void ParseInfo::InitFromIsolate(Isolate* isolate) { set_ast_string_constants(isolate->ast_string_constants()); } +void ParseInfo::UpdateStatisticsAfterBackgroundParse(Isolate* isolate) { + // Copy over the counters from the background thread to the main counters on + // the isolate. + RuntimeCallStats* main_call_stats = isolate->counters()->runtime_call_stats(); + if (FLAG_runtime_stats == + v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE) { + DCHECK_NE(main_call_stats, runtime_call_stats()); + DCHECK_NOT_NULL(main_call_stats); + DCHECK_NOT_NULL(runtime_call_stats()); + main_call_stats->Add(runtime_call_stats()); + } + set_runtime_call_stats(main_call_stats); +} + +void ParseInfo::ParseFinished(std::unique_ptr<ParseInfo> info) { + if (info->literal()) { + base::LockGuard<base::Mutex> access_child_infos(&child_infos_mutex_); + child_infos_.emplace_back(std::move(info)); + } +} + +std::map<int, ParseInfo*> ParseInfo::child_infos() const { + base::LockGuard<base::Mutex> access_child_infos(&child_infos_mutex_); + std::map<int, ParseInfo*> rv; + for (const auto& child_info : child_infos_) { + DCHECK_NOT_NULL(child_info->literal()); + int start_position = child_info->literal()->start_position(); + rv.insert(std::make_pair(start_position, child_info.get())); + } + return rv; +} + #ifdef DEBUG bool ParseInfo::script_is_native() const { return script_->type() == Script::TYPE_NATIVE; diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h index c115126191..5d8bb9c8eb 100644 --- a/deps/v8/src/parsing/parse-info.h +++ b/deps/v8/src/parsing/parse-info.h @@ -5,9 +5,12 @@ #ifndef V8_PARSING_PARSE_INFO_H_ #define V8_PARSING_PARSE_INFO_H_ +#include <map> #include <memory> +#include <vector> #include "include/v8.h" +#include "src/compiler-dispatcher/compiler-dispatcher-job.h" #include "src/globals.h" #include "src/handles.h" #include "src/parsing/preparsed-scope-data.h" @@ -33,7 +36,7 @@ class Utf16CharacterStream; class Zone; // A container for the inputs, configuration options, and outputs of parsing. -class V8_EXPORT_PRIVATE ParseInfo { +class V8_EXPORT_PRIVATE ParseInfo : public CompileJobFinishCallback { public: explicit ParseInfo(AccountingAllocator* zone_allocator); ParseInfo(Handle<Script> script); @@ -74,10 +77,8 @@ class V8_EXPORT_PRIVATE ParseInfo { set_ast_value_factory_owned) FLAG_ACCESSOR(kIsNamedExpression, is_named_expression, set_is_named_expression) - FLAG_ACCESSOR(kCallsEval, calls_eval, set_calls_eval) FLAG_ACCESSOR(kDebug, is_debug, set_is_debug) FLAG_ACCESSOR(kSerializing, will_serialize, set_will_serialize) - FLAG_ACCESSOR(kScopeInfoIsEmpty, scope_info_is_empty, set_scope_info_is_empty) FLAG_ACCESSOR(kTailCallEliminationEnabled, is_tail_call_elimination_enabled, set_tail_call_elimination_enabled) @@ -245,6 +246,13 @@ class V8_EXPORT_PRIVATE ParseInfo { } } + void UpdateStatisticsAfterBackgroundParse(Isolate* isolate); + + // The key of the map is the FunctionLiteral's start_position + std::map<int, ParseInfo*> child_infos() const; + + void ParseFinished(std::unique_ptr<ParseInfo> info) override; + #ifdef DEBUG bool script_is_native() const; #endif // DEBUG @@ -262,12 +270,10 @@ class V8_EXPORT_PRIVATE ParseInfo { kModule = 1 << 6, kAllowLazyParsing = 1 << 7, kIsNamedExpression = 1 << 8, - kCallsEval = 1 << 9, - kDebug = 1 << 10, - kSerializing = 1 << 11, - kScopeInfoIsEmpty = 1 << 12, - kTailCallEliminationEnabled = 1 << 13, - kAstValueFactoryOwned = 1 << 14, + kDebug = 1 << 9, + kSerializing = 1 << 10, + kTailCallEliminationEnabled = 1 << 11, + kAstValueFactoryOwned = 1 << 12, }; //------------- Inputs to parsing and scope analysis ----------------------- @@ -307,6 +313,9 @@ class V8_EXPORT_PRIVATE ParseInfo { FunctionLiteral* literal_; std::shared_ptr<DeferredHandles> deferred_handles_; + std::vector<std::unique_ptr<ParseInfo>> child_infos_; + mutable base::Mutex child_infos_mutex_; + void SetFlag(Flag f) { flags_ |= f; } void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; } bool GetFlag(Flag f) const { return (flags_ & f) != 0; } diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index 1dbad01dea..2d01398980 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -20,6 +20,7 @@ namespace v8 { namespace internal { +class PreParsedScopeData; enum FunctionNameValidity { kFunctionNameIsStrictReserved, @@ -200,6 +201,7 @@ class ParserBase { ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit, v8::Extension* extension, AstValueFactory* ast_value_factory, RuntimeCallStats* runtime_call_stats, + PreParsedScopeData* preparsed_scope_data, bool parsing_on_main_thread = true) : scope_(nullptr), original_scope_(nullptr), @@ -207,11 +209,12 @@ class ParserBase { extension_(extension), fni_(nullptr), ast_value_factory_(ast_value_factory), - ast_node_factory_(ast_value_factory), + ast_node_factory_(ast_value_factory, zone), runtime_call_stats_(runtime_call_stats), parsing_on_main_thread_(parsing_on_main_thread), parsing_module_(false), stack_limit_(stack_limit), + preparsed_scope_data_(preparsed_scope_data), zone_(zone), classifier_(nullptr), scanner_(scanner), @@ -448,6 +451,30 @@ class ParserBase { next_function_is_likely_called_ = true; } + void RecordFunctionOrEvalCall() { contains_function_or_eval_ = true; } + bool contains_function_or_eval() const { + return contains_function_or_eval_; + } + + class FunctionOrEvalRecordingScope { + public: + explicit FunctionOrEvalRecordingScope(FunctionState* state) + : state_(state) { + prev_value_ = state->contains_function_or_eval_; + state->contains_function_or_eval_ = false; + } + ~FunctionOrEvalRecordingScope() { + bool found = state_->contains_function_or_eval_; + if (!found) { + state_->contains_function_or_eval_ = prev_value_; + } + } + + private: + FunctionState* state_; + bool prev_value_; + }; + private: void AddDestructuringAssignment(DestructuringAssignment pair) { destructuring_assignments_to_rewrite_.Add(pair, scope_->zone()); @@ -482,6 +509,9 @@ class ParserBase { bool next_function_is_likely_called_; bool previous_function_was_likely_called_; + // Track if a function or eval occurs within this FunctionState + bool contains_function_or_eval_; + friend Impl; }; @@ -601,7 +631,8 @@ class ParserBase { constructor(parser->impl()->EmptyFunctionLiteral()), has_seen_constructor(false), has_name_static_property(false), - has_static_computed_names(false) {} + has_static_computed_names(false), + is_anonymous(false) {} VariableProxy* proxy; ExpressionT extends; typename Types::ClassPropertyList properties; @@ -609,6 +640,7 @@ class ParserBase { bool has_seen_constructor; bool has_name_static_property; bool has_static_computed_names; + bool is_anonymous; }; DeclarationScope* NewScriptScope() const { @@ -653,6 +685,10 @@ class ParserBase { if (target_zone == nullptr) target_zone = zone(); DeclarationScope* result = new (target_zone) DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind); + + // Record presence of an inner function scope + function_state_->RecordFunctionOrEvalCall(); + // TODO(verwaest): Move into the DeclarationScope constructor. if (!IsArrowFunction(kind)) { result->DeclareDefaultFunctionVariables(ast_value_factory()); @@ -1337,6 +1373,7 @@ class ParserBase { if (impl()->IsIdentifier(expression) && impl()->IsEval(impl()->AsIdentifier(expression))) { scope->RecordEvalCall(); + function_state_->RecordFunctionOrEvalCall(); if (is_sloppy(scope->language_mode())) { // For sloppy scopes we also have to record the call at function level, // in case it includes declarations that will be hoisted. @@ -1486,6 +1523,7 @@ class ParserBase { bool parsing_on_main_thread_; bool parsing_module_; uintptr_t stack_limit_; + PreParsedScopeData* preparsed_scope_data_; // Parser base's private field members. @@ -1530,7 +1568,8 @@ ParserBase<Impl>::FunctionState::FunctionState( non_patterns_to_rewrite_(0, scope->zone()), reported_errors_(16, scope->zone()), next_function_is_likely_called_(false), - previous_function_was_likely_called_(false) { + previous_function_was_likely_called_(false), + contains_function_or_eval_(false) { *function_state_stack = this; if (outer_function_state_) { outer_function_state_->previous_function_was_likely_called_ = @@ -1933,6 +1972,11 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) { int ellipsis_pos = position(); int pattern_pos = peek_position(); ExpressionT pattern = ParsePrimaryExpression(CHECK_OK); + if (peek() == Token::ASSIGN) { + ReportMessage(MessageTemplate::kRestDefaultInitializer); + *ok = false; + return result; + } ValidateBindingPattern(CHECK_OK); right = factory()->NewSpread(pattern, ellipsis_pos, pattern_pos); } else { @@ -2222,12 +2266,12 @@ ParserBase<Impl>::ParseClassPropertyDefinition( Token::Value name_token = peek(); - int function_token_position = scanner()->peek_location().beg_pos; + int name_token_position = scanner()->peek_location().beg_pos; IdentifierT name = impl()->EmptyIdentifier(); ExpressionT name_expression; if (name_token == Token::STATIC) { Consume(Token::STATIC); - function_token_position = scanner()->peek_location().beg_pos; + name_token_position = scanner()->peek_location().beg_pos; if (peek() == Token::LPAREN) { kind = PropertyKind::kMethodProperty; name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static' @@ -2305,7 +2349,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ExpressionT value = impl()->ParseFunctionLiteral( name, scanner()->location(), kSkipFunctionNameCheck, kind, - FLAG_harmony_function_tostring ? function_token_position + FLAG_harmony_function_tostring ? name_token_position : kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); @@ -2335,7 +2379,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition( FunctionLiteralT value = impl()->ParseFunctionLiteral( name, scanner()->location(), kSkipFunctionNameCheck, kind, - FLAG_harmony_function_tostring ? function_token_position + FLAG_harmony_function_tostring ? name_token_position : kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), CHECK_OK_CUSTOM(EmptyClassLiteralProperty)); @@ -2351,7 +2395,11 @@ ParserBase<Impl>::ParseClassPropertyDefinition( *is_computed_name); } case PropertyKind::kSpreadProperty: - UNREACHABLE(); + ReportUnexpectedTokenAt( + Scanner::Location(name_token_position, name_expression->position()), + name_token); + *ok = false; + return impl()->EmptyClassLiteralProperty(); } UNREACHABLE(); return impl()->EmptyClassLiteralProperty(); @@ -2672,6 +2720,10 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( spread_arg.beg_pos = start_pos; spread_arg.end_pos = peek_position(); } + if (argument->IsAssignment()) { + classifier()->RecordAsyncArrowFormalParametersError( + scanner()->location(), MessageTemplate::kRestDefaultInitializer); + } argument = factory()->NewSpread(argument, start_pos, expr_pos); } result->Add(argument, zone_); @@ -2684,6 +2736,10 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments( done = (peek() != Token::COMMA); if (!done) { Next(); + if (argument->IsSpread()) { + classifier()->RecordAsyncArrowFormalParametersError( + scanner()->location(), MessageTemplate::kParamAfterRest); + } if (allow_harmony_trailing_commas() && peek() == Token::RPAREN) { // allow trailing comma done = true; @@ -3265,6 +3321,9 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { // Explicit calls to the super constructor using super() perform an // implicit binding assignment to the 'this' variable. if (is_super_call) { + classifier()->RecordAssignmentPatternError( + Scanner::Location(pos, scanner()->location().end_pos), + MessageTemplate::kInvalidDestructuringTarget); ExpressionT this_expr = impl()->ThisExpression(pos); result = factory()->NewAssignment(Token::INIT, this_expr, result, pos); @@ -3418,6 +3477,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression( if (impl()->ParsingDynamicFunctionDeclaration()) { // We don't want dynamic functions to actually declare their name // "anonymous". We just want that name in the toString(). + if (stack_overflow()) { + *ok = false; + return impl()->EmptyExpression(); + } Consume(Token::IDENTIFIER); DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); } else if (peek_any_identifier()) { @@ -3506,6 +3569,10 @@ ParserBase<Impl>::ParseNewTargetExpression(bool* ok) { int pos = position(); ExpectMetaProperty(Token::TARGET, "new.target", pos, CHECK_OK); + classifier()->RecordAssignmentPatternError( + Scanner::Location(pos, scanner()->location().end_pos), + MessageTemplate::kInvalidDestructuringTarget); + if (!GetReceiverScope()->is_function_scope()) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedNewTarget); @@ -3603,7 +3670,12 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters, } ExpressionT initializer = impl()->EmptyExpression(); - if (!is_rest && Check(Token::ASSIGN)) { + if (Check(Token::ASSIGN)) { + if (is_rest) { + ReportMessage(MessageTemplate::kRestDefaultInitializer); + *ok = false; + return; + } ExpressionClassifier init_classifier(this); initializer = ParseAssignmentExpression(true, CHECK_OK_CUSTOM(Void)); impl()->RewriteNonPattern(CHECK_OK_CUSTOM(Void)); @@ -4216,32 +4288,20 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( // FIXME(marja): Arrow function parameters will be parsed even if the // body is preparsed; move relevant parts of parameter handling to // simulate consistent parameter handling. - Scanner::BookmarkScope bookmark(scanner()); - bookmark.Set(); + // For arrow functions, we don't need to retrieve data about function // parameters. int dummy_num_parameters = -1; - int dummy_function_length = -1; DCHECK((kind & FunctionKind::kArrowFunction) != 0); - LazyParsingResult result = impl()->SkipFunction( - kind, formal_parameters.scope, &dummy_num_parameters, - &dummy_function_length, false, true, CHECK_OK); - formal_parameters.scope->ResetAfterPreparsing( - ast_value_factory_, result == kLazyParsingAborted); - - if (result == kLazyParsingAborted) { - bookmark.Apply(); - // Trigger eager (re-)parsing, just below this block. - is_lazy_top_level_function = false; - - // This is probably an initialization function. Inform the compiler it - // should also eager-compile this function, and that we expect it to - // be used once. - eager_compile_hint = FunctionLiteral::kShouldEagerCompile; - should_be_used_once_hint = true; - } - } - if (!is_lazy_top_level_function) { + LazyParsingResult result = + impl()->SkipFunction(kind, formal_parameters.scope, + &dummy_num_parameters, false, false, CHECK_OK); + DCHECK_NE(result, kLazyParsingAborted); + USE(result); + formal_parameters.scope->ResetAfterPreparsing(ast_value_factory_, + false); + + } else { Consume(Token::LBRACE); body = impl()->NewStatementList(8); impl()->ParseFunctionBody(body, impl()->EmptyIdentifier(), @@ -4339,24 +4399,30 @@ template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( IdentifierT name, Scanner::Location class_name_location, bool name_is_strict_reserved, int class_token_pos, bool* ok) { + bool is_anonymous = impl()->IsEmptyIdentifier(name); + // All parts of a ClassDeclaration and ClassExpression are strict code. - if (name_is_strict_reserved) { - impl()->ReportMessageAt(class_name_location, - MessageTemplate::kUnexpectedStrictReserved); - *ok = false; - return impl()->EmptyExpression(); - } - if (impl()->IsEvalOrArguments(name)) { - impl()->ReportMessageAt(class_name_location, - MessageTemplate::kStrictEvalArguments); - *ok = false; - return impl()->EmptyExpression(); + if (!is_anonymous) { + if (name_is_strict_reserved) { + impl()->ReportMessageAt(class_name_location, + MessageTemplate::kUnexpectedStrictReserved); + *ok = false; + return impl()->EmptyExpression(); + } + if (impl()->IsEvalOrArguments(name)) { + impl()->ReportMessageAt(class_name_location, + MessageTemplate::kStrictEvalArguments); + *ok = false; + return impl()->EmptyExpression(); + } } - BlockState block_state(zone(), &scope_); + Scope* block_scope = NewScope(BLOCK_SCOPE); + BlockState block_state(&scope_, block_scope); RaiseLanguageMode(STRICT); ClassInfo class_info(this); + class_info.is_anonymous = is_anonymous; impl()->DeclareClassVariable(name, &class_info, class_token_pos, CHECK_OK); scope()->set_start_position(scanner()->location().end_pos); @@ -4401,7 +4467,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( } Expect(Token::RBRACE, CHECK_OK); - return impl()->RewriteClassLiteral(name, &class_info, class_token_pos, ok); + int end_pos = scanner()->location().end_pos; + block_scope->set_end_position(end_pos); + return impl()->RewriteClassLiteral(block_scope, name, &class_info, + class_token_pos, end_pos, ok); } template <typename Impl> @@ -4452,6 +4521,10 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) { if (impl()->ParsingDynamicFunctionDeclaration()) { // We don't want dynamic functions to actually declare their name // "anonymous". We just want that name in the toString(). + if (stack_overflow()) { + *ok = false; + return impl()->EmptyExpression(); + } Consume(Token::IDENTIFIER); DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS)); } else if (peek_any_identifier()) { @@ -5460,6 +5533,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ZoneList<const AstRawString*>* labels, bool* ok) { + typename FunctionState::FunctionOrEvalRecordingScope recording_scope( + function_state_); int stmt_pos = peek_position(); ForInfo for_info(this); bool bound_names_are_lexical = false; @@ -5469,7 +5544,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( Expect(Token::FOR, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); scope()->set_start_position(scanner()->location().beg_pos); - scope()->set_is_hidden(); StatementT init = impl()->NullStatement(); @@ -5527,6 +5601,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) { + scope()->set_is_hidden(); // Just one declaration followed by in/of. if (for_info->parsing_result.declarations.length() != 1) { impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, @@ -5607,6 +5682,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) { + scope()->set_is_hidden(); // Initializer is reference followed by in/of. if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { expression = impl()->CheckAndRewriteReferenceExpression( @@ -5690,15 +5766,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( body = ParseStatement(nullptr, CHECK_OK); } - if (bound_names_are_lexical && for_info->bound_names.length() > 0) { - auto result = impl()->DesugarLexicalBindingsInForStatement( + scope()->set_end_position(scanner()->location().end_pos); + inner_scope->set_end_position(scanner()->location().end_pos); + if (bound_names_are_lexical && for_info->bound_names.length() > 0 && + (is_resumable() || function_state_->contains_function_or_eval())) { + scope()->set_is_hidden(); + return impl()->DesugarLexicalBindingsInForStatement( loop, init, cond, next, body, inner_scope, *for_info, CHECK_OK); - scope()->set_end_position(scanner()->location().end_pos); - inner_scope->set_end_position(scanner()->location().end_pos); - return result; } - scope()->set_end_position(scanner()->location().end_pos); Scope* for_scope = scope()->FinalizeBlockScope(); if (for_scope != nullptr) { // Rewrite a for statement of the form @@ -5722,6 +5798,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( BlockT block = factory()->NewBlock(nullptr, 2, false, kNoSourcePosition); if (!impl()->IsNullStatement(init)) { block->statements()->Add(init, zone()); + init = impl()->NullStatement(); } block->statements()->Add(loop, zone()); block->set_scope(for_scope); diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 6a2c2db0d1..a4f40dda53 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -4,6 +4,7 @@ #include "src/parsing/parser.h" +#include <algorithm> #include <memory> #include "src/api.h" @@ -14,6 +15,7 @@ #include "src/bailout-reason.h" #include "src/base/platform/platform.h" #include "src/char-predicates-inl.h" +#include "src/compiler-dispatcher/compiler-dispatcher.h" #include "src/messages.h" #include "src/objects-inl.h" #include "src/parsing/duplicate-finder.h" @@ -109,8 +111,7 @@ int ParseData::FunctionsSize() { class DiscardableZoneScope { public: DiscardableZoneScope(Parser* parser, Zone* temp_zone, bool use_temp_zone) - : ast_node_factory_scope_(parser->factory(), temp_zone, use_temp_zone), - fni_(parser->ast_value_factory_, temp_zone), + : fni_(parser->ast_value_factory_, temp_zone), parser_(parser), prev_fni_(parser->fni_), prev_zone_(parser->zone_), @@ -122,6 +123,7 @@ class DiscardableZoneScope { parser_->temp_zoned_ = true; parser_->fni_ = &fni_; parser_->zone_ = temp_zone; + parser_->factory()->set_zone(temp_zone); if (parser_->reusable_preparser_ != nullptr) { parser_->reusable_preparser_->zone_ = temp_zone; parser_->reusable_preparser_->factory()->set_zone(temp_zone); @@ -131,18 +133,17 @@ class DiscardableZoneScope { void Reset() { parser_->fni_ = prev_fni_; parser_->zone_ = prev_zone_; + parser_->factory()->set_zone(prev_zone_); parser_->allow_lazy_ = prev_allow_lazy_; parser_->temp_zoned_ = prev_temp_zoned_; if (parser_->reusable_preparser_ != nullptr) { parser_->reusable_preparser_->zone_ = prev_zone_; parser_->reusable_preparser_->factory()->set_zone(prev_zone_); } - ast_node_factory_scope_.Reset(); } ~DiscardableZoneScope() { Reset(); } private: - AstNodeFactory::BodyScope ast_node_factory_scope_; FuncNameInferrer fni_; Parser* parser_; FuncNameInferrer* prev_fni_; @@ -250,60 +251,56 @@ bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x, y->AsLiteral() && y->AsLiteral()->raw_value()->IsNumber()) { double x_val = (*x)->AsLiteral()->raw_value()->AsNumber(); double y_val = y->AsLiteral()->raw_value()->AsNumber(); - bool x_has_dot = (*x)->AsLiteral()->raw_value()->ContainsDot(); - bool y_has_dot = y->AsLiteral()->raw_value()->ContainsDot(); - bool has_dot = x_has_dot || y_has_dot; switch (op) { case Token::ADD: - *x = factory()->NewNumberLiteral(x_val + y_val, pos, has_dot); + *x = factory()->NewNumberLiteral(x_val + y_val, pos); return true; case Token::SUB: - *x = factory()->NewNumberLiteral(x_val - y_val, pos, has_dot); + *x = factory()->NewNumberLiteral(x_val - y_val, pos); return true; case Token::MUL: - *x = factory()->NewNumberLiteral(x_val * y_val, pos, has_dot); + *x = factory()->NewNumberLiteral(x_val * y_val, pos); return true; case Token::DIV: - *x = factory()->NewNumberLiteral(x_val / y_val, pos, has_dot); + *x = factory()->NewNumberLiteral(x_val / y_val, pos); return true; case Token::BIT_OR: { int value = DoubleToInt32(x_val) | DoubleToInt32(y_val); - *x = factory()->NewNumberLiteral(value, pos, has_dot); + *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::BIT_AND: { int value = DoubleToInt32(x_val) & DoubleToInt32(y_val); - *x = factory()->NewNumberLiteral(value, pos, has_dot); + *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::BIT_XOR: { int value = DoubleToInt32(x_val) ^ DoubleToInt32(y_val); - *x = factory()->NewNumberLiteral(value, pos, has_dot); + *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::SHL: { int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f); - *x = factory()->NewNumberLiteral(value, pos, has_dot); + *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::SHR: { uint32_t shift = DoubleToInt32(y_val) & 0x1f; uint32_t value = DoubleToUint32(x_val) >> shift; - *x = factory()->NewNumberLiteral(value, pos, has_dot); + *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::SAR: { uint32_t shift = DoubleToInt32(y_val) & 0x1f; int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift); - *x = factory()->NewNumberLiteral(value, pos, has_dot); + *x = factory()->NewNumberLiteral(value, pos); return true; } case Token::EXP: { double value = Pow(x_val, y_val); int int_value = static_cast<int>(value); *x = factory()->NewNumberLiteral( - int_value == value && value != -0.0 ? int_value : value, pos, - has_dot); + int_value == value && value != -0.0 ? int_value : value, pos); return true; } default: @@ -325,15 +322,13 @@ Expression* Parser::BuildUnaryExpression(Expression* expression, } else if (literal->IsNumber()) { // Compute some expressions involving only number literals. double value = literal->AsNumber(); - bool has_dot = literal->ContainsDot(); switch (op) { case Token::ADD: return expression; case Token::SUB: - return factory()->NewNumberLiteral(-value, pos, has_dot); + return factory()->NewNumberLiteral(-value, pos); case Token::BIT_NOT: - return factory()->NewNumberLiteral(~DoubleToInt32(value), pos, - has_dot); + return factory()->NewNumberLiteral(~DoubleToInt32(value), pos); default: break; } @@ -342,7 +337,7 @@ Expression* Parser::BuildUnaryExpression(Expression* expression, // Desugar '+foo' => 'foo*1' if (op == Token::ADD) { return factory()->NewBinaryOperation( - Token::MUL, expression, factory()->NewNumberLiteral(1, pos, true), pos); + Token::MUL, expression, factory()->NewNumberLiteral(1, pos), pos); } // The same idea for '-foo' => 'foo*(-1)'. if (op == Token::SUB) { @@ -431,9 +426,8 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { return factory()->NewSmiLiteral(value, pos); } case Token::NUMBER: { - bool has_dot = scanner()->ContainsDot(); double value = scanner()->DoubleValue(); - return factory()->NewNumberLiteral(value, pos, has_dot); + return factory()->NewNumberLiteral(value, pos); } default: DCHECK(false); @@ -503,7 +497,8 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name, Parser::Parser(ParseInfo* info) : ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(), info->extension(), info->ast_value_factory(), - info->runtime_call_stats(), true), + info->runtime_call_stats(), + info->preparsed_scope_data(), true), scanner_(info->unicode_cache()), reusable_preparser_(nullptr), mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. @@ -513,7 +508,6 @@ Parser::Parser(ParseInfo* info) total_preparse_skipped_(0), temp_zoned_(false), log_(nullptr), - preparsed_scope_data_(info->preparsed_scope_data()), parameters_end_pos_(info->parameters_end_pos()) { // Even though we were passed ParseInfo, we should not store it in // Parser - this makes sure that Isolate is not accidentally accessed via @@ -621,25 +615,15 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { source = String::Flatten(source); FunctionLiteral* result; + if (FLAG_use_parse_tasks) { + source_ = source; + compiler_dispatcher_ = isolate->compiler_dispatcher(); + main_parse_info_ = info; + } + { std::unique_ptr<Utf16CharacterStream> stream(ScannerStream::For(source)); - if (FLAG_use_parse_tasks) { - // FIXME(wiktorg) make it useful for something - // TODO(wiktorg) make preparser work also with modules - if (!info->is_module()) { - scanner_.Initialize(stream.get()); - // NOTE: Some features will be double counted - once here and one more - // time while being fully parsed by a parse task. - PreParser::PreParseResult result = - reusable_preparser()->PreParseProgram(false, use_counts_); - if (result == PreParser::kPreParseStackOverflow) { - set_stack_overflow(); - return nullptr; - } - stream->Seek(0); - } - } - scanner_.Initialize(stream.get()); + scanner_.Initialize(stream.get(), info->is_module()); result = DoParseProgram(info); } if (result != NULL) { @@ -647,6 +631,14 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { } HandleSourceURLComments(isolate, info->script()); + if (FLAG_use_parse_tasks) { + compiler_dispatcher_->FinishAllNow(); + StitchAst(info, isolate); + source_ = Handle<String>(); + compiler_dispatcher_ = nullptr; + main_parse_info_ = nullptr; + } + if (FLAG_trace_parse && result != nullptr) { double ms = timer.Elapsed().InMillisecondsF(); if (info->is_eval()) { @@ -805,8 +797,9 @@ FunctionLiteral* Parser::ParseFunction(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())); - scanner_.Initialize(stream.get()); - result = DoParseFunction(info, ast_value_factory()->GetString(name)); + scanner_.Initialize(stream.get(), info->is_module()); + info->set_function_name(ast_value_factory()->GetString(name)); + result = DoParseFunction(info); if (result != nullptr) { Handle<String> inferred_name(shared_info->inferred_name()); result->set_inferred_name(inferred_name); @@ -835,8 +828,25 @@ static FunctionLiteral::FunctionType ComputeFunctionType(ParseInfo* info) { return FunctionLiteral::kAnonymousExpression; } -FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, - const AstRawString* raw_name) { +FunctionLiteral* Parser::DoParseFunction(ParseInfo* info) { + const AstRawString* raw_name = info->function_name(); + FunctionNameValidity function_name_validity = kSkipFunctionNameCheck; + if (!raw_name) { + bool ok = true; + if (peek() == Token::LPAREN) { + const AstRawString* variable_name; + impl()->GetDefaultStrings(&raw_name, &variable_name); + } else { + bool is_strict_reserved = true; + raw_name = ParseIdentifierOrStrictReservedWord(info->function_kind(), + &is_strict_reserved, &ok); + if (!ok) return nullptr; + function_name_validity = is_strict_reserved + ? kFunctionNameIsStrictReserved + : kFunctionNameValidityUnknown; + } + } + DCHECK_NOT_NULL(raw_name); DCHECK_NULL(scope_); DCHECK_NULL(target_stack_); @@ -955,7 +965,7 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, info->start_position(), info->end_position()); } else { result = ParseFunctionLiteral( - raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind, + raw_name, Scanner::Location::invalid(), function_name_validity, kind, kNoSourcePosition, function_type, info->language_mode(), &ok); } // Make sure the results agree. @@ -966,8 +976,6 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, DCHECK_NULL(target_stack_); DCHECK_IMPLIES(result, info->function_literal_id() == result->function_literal_id()); - DCHECK_IMPLIES(!info->scope_info_is_empty() && result, - info->calls_eval() == result->scope()->calls_eval()); return result; } @@ -2605,11 +2613,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral( 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 = - can_preparse && impl()->AllowsLazyParsingWithoutUnresolvedVariables(); + const bool source_is_external = + !source_.is_null() && (source_->IsExternalTwoByteString() || + source_->IsExternalOneByteString()); + const bool is_lazy = + eager_compile_hint == FunctionLiteral::kShouldLazyCompile; + const bool is_top_level = + impl()->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_eager_top_level_function = !is_lazy && is_top_level; + const bool is_declaration = function_type == FunctionLiteral::kDeclaration; RuntimeCallTimerScope runtime_timer( runtime_call_stats_, @@ -2633,22 +2647,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // Inner functions will be parsed using a temporary Zone. After parsing, we // will migrate unresolved variable into a Scope in the main Zone. - // TODO(marja): Refactor parsing modes: simplify this. - bool use_temp_zone = - (FLAG_aggressive_lazy_inner_functions - ? can_preparse - : (is_lazy_top_level_function || - (parse_lazily() && - function_type == FunctionLiteral::kDeclaration && - eager_compile_hint == FunctionLiteral::kShouldLazyCompile))); - - DCHECK_IMPLIES( - (is_lazy_top_level_function || - (parse_lazily() && function_type == FunctionLiteral::kDeclaration && - eager_compile_hint == FunctionLiteral::kShouldLazyCompile)), - can_preparse); - bool is_lazy_inner_function = - use_temp_zone && FLAG_lazy_inner_functions && !is_lazy_top_level_function; + + const bool should_preparse_inner = + parse_lazily() && FLAG_lazy_inner_functions && is_lazy_inner_function && + (is_declaration || FLAG_aggressive_lazy_inner_functions); + + bool should_use_parse_task = + FLAG_use_parse_tasks && parse_lazily() && compiler_dispatcher_ && + is_eager_top_level_function && source_is_external; + + // This may be modified later to reflect preparsing decision taken + bool should_preparse = (parse_lazily() && (is_lazy_top_level_function || + should_use_parse_task)) || + should_preparse_inner; ZoneList<Statement*>* body = nullptr; int expected_property_count = -1; @@ -2658,14 +2669,40 @@ FunctionLiteral* Parser::ParseFunctionLiteral( bool has_duplicate_parameters = false; int function_literal_id = GetNextFunctionLiteralId(); + Expect(Token::LPAREN, CHECK_OK); + + if (should_use_parse_task) { + int start_pos = scanner()->location().beg_pos; + if (function_name_location.IsValid()) { + start_pos = function_name_location.beg_pos; + } + // Warning! + // Only sets fields in compiler_hints that are currently used. + int compiler_hints = SharedFunctionInfo::FunctionKindBits::encode(kind); + if (function_type == FunctionLiteral::kDeclaration) { + compiler_hints |= 1 << SharedFunctionInfo::kIsDeclaration; + } + should_use_parse_task = compiler_dispatcher_->Enqueue( + source_, start_pos, source_->length(), language_mode, + function_literal_id, allow_natives(), parsing_module_, + function_type == FunctionLiteral::kNamedExpression, compiler_hints, + main_parse_info_, nullptr); + if (V8_UNLIKELY(FLAG_trace_parse_tasks)) { + PrintF("Spining off task for function at %d: %s\n", start_pos, + should_use_parse_task ? "SUCCESS" : "FAILED"); + } + if (!should_use_parse_task) { + should_preparse = false; + } + } + Zone* outer_zone = zone(); DeclarationScope* scope; { // Temporary zones can nest. When we migrate free variables (see below), we // need to recreate them in the previous Zone. - AstNodeFactory previous_zone_ast_node_factory(ast_value_factory()); - previous_zone_ast_node_factory.set_zone(zone()); + AstNodeFactory previous_zone_ast_node_factory(ast_value_factory(), zone()); // Open a new zone scope, which sets our AstNodeFactory to allocate in the // new temporary zone if the preconditions are satisfied, and ensures that @@ -2673,7 +2710,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // to do scope analysis correctly after full parsing, we migrate needed // information when the function is parsed. Zone temp_zone(zone()->allocator(), ZONE_NAME); - DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone); + DiscardableZoneScope zone_scope(this, &temp_zone, should_preparse); // This Scope lives in the main zone. We'll migrate data into that zone // later. @@ -2681,10 +2718,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( SetLanguageMode(scope, language_mode); #ifdef DEBUG scope->SetScopeName(function_name); - if (use_temp_zone) scope->set_needs_migration(); + if (should_preparse) scope->set_needs_migration(); #endif - - Expect(Token::LPAREN, CHECK_OK); scope->set_start_position(scanner()->location().beg_pos); // Eager or lazy parse? If is_lazy_top_level_function, we'll parse @@ -2692,19 +2727,19 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // 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) { + if (should_preparse) { + DCHECK(parse_lazily()); + DCHECK(is_lazy_top_level_function || is_lazy_inner_function || + should_use_parse_task); Scanner::BookmarkScope bookmark(scanner()); bookmark.Set(); - LazyParsingResult result = SkipFunction( - kind, scope, &num_parameters, &function_length, - is_lazy_inner_function, is_lazy_top_level_function, CHECK_OK); + LazyParsingResult result = + SkipFunction(kind, scope, &num_parameters, is_lazy_inner_function, + is_lazy_top_level_function, CHECK_OK); if (result == kLazyParsingAborted) { DCHECK(is_lazy_top_level_function); bookmark.Apply(); - // Trigger eager (re-)parsing, just below this block. - is_lazy_top_level_function = false; - // This is probably an initialization function. Inform the compiler it // should also eager-compile this function, and that we expect it to be // used once. @@ -2712,48 +2747,45 @@ FunctionLiteral* Parser::ParseFunctionLiteral( should_be_used_once_hint = true; scope->ResetAfterPreparsing(ast_value_factory(), true); zone_scope.Reset(); - use_temp_zone = false; + // Trigger eager (re-)parsing, just below this block. + should_preparse = false; + should_use_parse_task = false; } } - if (!is_lazy_top_level_function && !is_lazy_inner_function) { + if (should_preparse) { + scope->AnalyzePartially(&previous_zone_ast_node_factory, + preparsed_scope_data_); + } else { body = ParseFunction(function_name, pos, kind, function_type, scope, &num_parameters, &function_length, &has_duplicate_parameters, &expected_property_count, CHECK_OK); } - 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, - preparsed_scope_data_); - } - - DCHECK_IMPLIES(use_temp_zone, temp_zoned_); - if (FLAG_trace_preparse) { + DCHECK_EQ(should_preparse, temp_zoned_); + if (V8_UNLIKELY(FLAG_trace_preparse)) { PrintF(" [%s]: %i-%i %.*s\n", - is_lazy_top_level_function - ? "Preparse no-resolution" - : (temp_zoned_ ? "Preparse resolution" : "Full parse"), + 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_runtime_stats)) { - if (is_lazy_top_level_function) { - RuntimeCallStats::CorrectCurrentCounterId( - runtime_call_stats_, - parsing_on_main_thread_ - ? &RuntimeCallStats::PreParseNoVariableResolution - : &RuntimeCallStats::PreParseBackgroundNoVariableResolution); - } else if (temp_zoned_) { - RuntimeCallStats::CorrectCurrentCounterId( - runtime_call_stats_, + if (should_preparse) { + RuntimeCallStats::CounterId counter_id = parsing_on_main_thread_ ? &RuntimeCallStats::PreParseWithVariableResolution - : &RuntimeCallStats::PreParseBackgroundWithVariableResolution); + : &RuntimeCallStats::PreParseBackgroundWithVariableResolution; + if (is_top_level) { + counter_id = + parsing_on_main_thread_ + ? &RuntimeCallStats::PreParseNoVariableResolution + : &RuntimeCallStats::PreParseBackgroundNoVariableResolution; + } + RuntimeCallStats::CorrectCurrentCounterId(runtime_call_stats_, + counter_id); } } @@ -2779,6 +2811,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral( function_name, scope, body, expected_property_count, num_parameters, function_length, duplicate_parameters, function_type, eager_compile_hint, pos, true, function_literal_id); + if (should_use_parse_task) { + literals_to_stitch_.emplace_back(function_literal); + } function_literal->set_function_token_position(function_token_pos); if (should_be_used_once_hint) function_literal->set_should_be_used_once_hint(); @@ -2790,9 +2825,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral( return function_literal; } -Parser::LazyParsingResult Parser::SkipFunction( - FunctionKind kind, DeclarationScope* function_scope, int* num_parameters, - int* function_length, bool is_inner_function, bool may_abort, bool* ok) { +Parser::LazyParsingResult Parser::SkipFunction(FunctionKind kind, + DeclarationScope* function_scope, + int* num_parameters, + bool is_inner_function, + bool may_abort, bool* ok) { + FunctionState function_state(&function_state_, &scope_, function_scope); + DCHECK_NE(kNoSourcePosition, function_scope->start_position()); DCHECK_EQ(kNoSourcePosition, parameters_end_pos_); if (produce_cached_parse_data()) CHECK(log_); @@ -2817,52 +2856,21 @@ Parser::LazyParsingResult Parser::SkipFunction( scanner()->SeekForward(entry.end_pos() - 1); Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); *num_parameters = entry.num_parameters(); - *function_length = entry.function_length(); SetLanguageMode(function_scope, entry.language_mode()); if (entry.uses_super_property()) function_scope->RecordSuperPropertyUsage(); - if (entry.calls_eval()) function_scope->RecordEvalCall(); SkipFunctionLiterals(entry.num_inner_functions()); return kLazyParsingComplete; } cached_parse_data_->Reject(); } - if (FLAG_use_parse_tasks && !is_inner_function && - reusable_preparser()->preparse_data()) { - // All top-level functions are already preparsed and parser tasks for eager - // functions are already created. Use data gathered during the preparse step - // to skip the function. - PreParseData::FunctionData data = - reusable_preparser()->preparse_data()->GetFunctionData( - function_scope->start_position()); - if (data.is_valid()) { - if (FLAG_trace_parse_tasks) { - PrintF("Skipping top level func @ %d : %d using preparse data\n", - function_scope->start_position(), data.end); - } - function_scope->set_end_position(data.end); - scanner()->SeekForward(data.end - 1); - Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); - *num_parameters = data.num_parameters; - *function_length = data.function_length; - SetLanguageMode(function_scope, data.language_mode); - if (data.uses_super_property) { - function_scope->RecordSuperPropertyUsage(); - } - if (data.calls_eval) { - function_scope->RecordEvalCall(); - } - SkipFunctionLiterals(data.num_inner_functions); - return kLazyParsingComplete; - } - } - // FIXME(marja): There are 3 ways to skip functions now. Unify them. if (preparsed_scope_data_->Consuming()) { - DCHECK(FLAG_preparser_scope_analysis); + DCHECK(FLAG_experimental_preparser_scope_analysis); const PreParseData::FunctionData& data = - preparsed_scope_data_->FindFunction(function_scope->start_position()); + preparsed_scope_data_->FindSkippableFunction( + function_scope->start_position()); if (data.is_valid()) { function_scope->set_is_skipped_function(true); function_scope->outer_scope()->SetMustUsePreParsedScopeData(); @@ -2871,14 +2879,10 @@ Parser::LazyParsingResult Parser::SkipFunction( scanner()->SeekForward(data.end - 1); Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete)); *num_parameters = data.num_parameters; - *function_length = data.function_length; SetLanguageMode(function_scope, data.language_mode); if (data.uses_super_property) { function_scope->RecordSuperPropertyUsage(); } - if (data.calls_eval) { - function_scope->RecordEvalCall(); - } SkipFunctionLiterals(data.num_inner_functions); return kLazyParsingComplete; } @@ -2914,15 +2918,13 @@ Parser::LazyParsingResult Parser::SkipFunction( total_preparse_skipped_ += function_scope->end_position() - function_scope->start_position(); *num_parameters = logger->num_parameters(); - *function_length = logger->function_length(); SkipFunctionLiterals(logger->num_inner_functions()); if (!is_inner_function && produce_cached_parse_data()) { DCHECK(log_); - log_->LogFunction( - function_scope->start_position(), function_scope->end_position(), - *num_parameters, *function_length, language_mode(), - function_scope->uses_super_property(), function_scope->calls_eval(), - logger->num_inner_functions()); + log_->LogFunction(function_scope->start_position(), + function_scope->end_position(), *num_parameters, + language_mode(), function_scope->uses_super_property(), + logger->num_inner_functions()); } return kLazyParsingComplete; } @@ -3128,22 +3130,6 @@ Block* Parser::BuildRejectPromiseOnException(Block* inner_block) { return result; } -Assignment* Parser::BuildCreateJSGeneratorObject(int pos, FunctionKind kind) { - // .generator = %CreateJSGeneratorObject(...); - DCHECK_NOT_NULL(function_state_->generator_object_variable()); - ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); - args->Add(factory()->NewThisFunction(pos), zone()); - args->Add(IsArrowFunction(kind) ? GetLiteralUndefined(pos) - : ThisExpression(kNoSourcePosition), - zone()); - Expression* allocation = - factory()->NewCallRuntime(Runtime::kCreateJSGeneratorObject, args, pos); - VariableProxy* proxy = - factory()->NewVariableProxy(function_state_->generator_object_variable()); - return factory()->NewAssignment(Token::INIT, proxy, allocation, - kNoSourcePosition); -} - Expression* Parser::BuildResolvePromise(Expression* value, int pos) { // %ResolvePromise(.promise, value), .promise ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); @@ -3193,13 +3179,17 @@ Variable* Parser::AsyncGeneratorAwaitVariable() { } Expression* Parser::BuildInitialYield(int pos, FunctionKind kind) { - Assignment* assignment = BuildCreateJSGeneratorObject(pos, kind); - VariableProxy* generator = + // We access the generator object twice: once for the {generator} + // member of the Suspend AST node, and once for the result of + // the initial yield. + Expression* yield_result = + factory()->NewVariableProxy(function_state_->generator_object_variable()); + Expression* generator_object = factory()->NewVariableProxy(function_state_->generator_object_variable()); // The position of the yield is important for reporting the exception // caused by calling the .throw method on a generator suspended at the // initial yield (i.e. right after generator instantiation). - return BuildSuspend(generator, assignment, scope()->start_position(), + return BuildSuspend(generator_object, yield_result, scope()->start_position(), Suspend::kOnExceptionThrow, SuspendFlags::kYield); } @@ -3317,7 +3307,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, class_info->properties->Add(property, zone()); } -// This method rewrites a class literal into a do-expression. +// This method generates a ClassLiteral AST node. // It uses the following fields of class_info: // - constructor (if missing, it updates it with a default constructor) // - proxy @@ -3325,13 +3315,13 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, // - properties // - has_name_static_property // - has_static_computed_names -Expression* Parser::RewriteClassLiteral(const AstRawString* name, +Expression* Parser::RewriteClassLiteral(Scope* block_scope, + const AstRawString* name, ClassInfo* class_info, int pos, - bool* ok) { - int end_pos = scanner()->location().end_pos; - Block* do_block = factory()->NewBlock(nullptr, 1, false, pos); - Variable* result_var = NewTemporary(ast_value_factory()->empty_string()); - DoExpression* do_expr = factory()->NewDoExpression(do_block, result_var, pos); + 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); bool has_extends = class_info->extends != nullptr; bool has_default_constructor = class_info->constructor == nullptr; @@ -3340,31 +3330,20 @@ Expression* Parser::RewriteClassLiteral(const AstRawString* name, DefaultConstructor(name, has_extends, pos, end_pos); } - scope()->set_end_position(end_pos); - if (name != nullptr) { DCHECK_NOT_NULL(class_info->proxy); class_info->proxy->var()->set_initializer_position(end_pos); } ClassLiteral* class_literal = factory()->NewClassLiteral( - class_info->proxy, class_info->extends, class_info->constructor, - class_info->properties, pos, end_pos, + block_scope, class_info->proxy, class_info->extends, + class_info->constructor, class_info->properties, pos, end_pos, class_info->has_name_static_property, - class_info->has_static_computed_names); + class_info->has_static_computed_names, class_info->is_anonymous); - do_block->statements()->Add( - factory()->NewExpressionStatement( - factory()->NewAssignment(Token::ASSIGN, - factory()->NewVariableProxy(result_var), - class_literal, kNoSourcePosition), - pos), - zone()); - do_block->set_scope(scope()->FinalizeBlockScope()); - do_expr->set_represented_function(class_info->constructor); AddFunctionForNameInference(class_info->constructor); - return do_expr; + return class_literal; } Literal* Parser::GetLiteralUndefined(int position) { @@ -3503,13 +3482,6 @@ void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) { } 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. - isolate->counters()->runtime_call_stats()->Add(runtime_call_stats_); - } } void Parser::ParseOnBackground(ParseInfo* info) { @@ -3526,10 +3498,6 @@ void Parser::ParseOnBackground(ParseInfo* info) { compile_options_ = ScriptCompiler::kNoCompileOptions; } } - 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; @@ -3543,7 +3511,7 @@ void Parser::ParseOnBackground(ParseInfo* info) { runtime_call_stats_)); stream_ptr = stream.get(); } - scanner_.Initialize(stream_ptr); + scanner_.Initialize(stream_ptr, info->is_module()); DCHECK(info->maybe_outer_scope_info().is_null()); DCHECK(original_scope_); @@ -3558,12 +3526,7 @@ void Parser::ParseOnBackground(ParseInfo* info) { fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); result = DoParseProgram(info); } else { - const AstRawString* function_name = info->function_name(); - if (!function_name) { - // FIXME(wiktorg) solve fni in parse tasks - function_name = ast_value_factory()->empty_string(); - } - result = DoParseFunction(info, function_name); + result = DoParseFunction(info); } info->set_literal(result); @@ -3887,9 +3850,6 @@ void Parser::PrepareAsyncFunctionBody(ZoneList<Statement*>* body, if (function_state_->generator_object_variable() == nullptr) { PrepareGeneratorVariables(); } - body->Add(factory()->NewExpressionStatement( - BuildCreateJSGeneratorObject(pos, kind), kNoSourcePosition), - zone()); } // This method completes the desugaring of the body of async_function. @@ -4251,7 +4211,7 @@ void Parser::SetFunctionNameFromPropertyName(ObjectLiteralProperty* property, // Ignore "__proto__" as a name when it's being used to set the [[Prototype]] // of an object literal. - if (property->kind() == ObjectLiteralProperty::PROTOTYPE) return; + if (property->IsPrototype()) return; Expression* value = property->value(); @@ -4270,12 +4230,11 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) { DCHECK_NOT_NULL(name); if (!value->IsAnonymousFunctionDefinition()) return; auto function = value->AsFunctionLiteral(); + if (value->IsClassLiteral()) { + function = value->AsClassLiteral()->constructor(); + } if (function != nullptr) { function->set_raw_name(ast_value_factory()->NewConsString(name)); - } else { - DCHECK(value->IsDoExpression()); - value->AsDoExpression()->represented_function()->set_raw_name( - ast_value_factory()->NewConsString(name)); } } @@ -4704,10 +4663,26 @@ Expression* Parser::RewriteYieldStar(Expression* generator, // while (true) { ... } // Already defined earlier: WhileStatement* loop = ... { - Block* loop_body = factory()->NewBlock(nullptr, 4, false, nopos); + Block* loop_body = factory()->NewBlock(nullptr, 5, false, nopos); loop_body->statements()->Add(switch_mode, zone()); loop_body->statements()->Add(if_done, zone()); loop_body->statements()->Add(set_mode_return, zone()); + + if (is_async_generator()) { + // AsyncGeneratorYield does not yield the original iterator result, + // unlike sync generators. Do `output = output.value` + VariableProxy* output_proxy = factory()->NewVariableProxy(var_output); + Expression* literal = factory()->NewStringLiteral( + ast_value_factory()->value_string(), nopos); + Assignment* assign = factory()->NewAssignment( + Token::ASSIGN, output_proxy, + factory()->NewProperty(factory()->NewVariableProxy(var_output), + literal, nopos), + nopos); + loop_body->statements()->Add( + factory()->NewExpressionStatement(assign, nopos), zone()); + } + loop_body->statements()->Add(try_finally, zone()); loop->Initialize(factory()->NewBooleanLiteral(true, nopos), loop_body); @@ -5191,6 +5166,41 @@ Statement* Parser::FinalizeForOfStatement(ForOfStatement* loop, return final_loop; } +void Parser::StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate) { + if (literals_to_stitch_.empty()) return; + std::map<int, ParseInfo*> child_infos = top_level_parse_info->child_infos(); + DCHECK(std::is_sorted(literals_to_stitch_.begin(), literals_to_stitch_.end(), + [](FunctionLiteral* a, FunctionLiteral* b) { + return a->start_position() < b->start_position(); + })); + auto it = literals_to_stitch_.begin(); + for (auto& child_info : child_infos) { + ParseInfo* result = child_info.second; + // If the parse task failed the function will be treated as lazy function + // and reparsed before it gets called + if (!result) continue; + result->UpdateStatisticsAfterBackgroundParse(isolate); + if (!result->literal()) continue; + while ((*it)->start_position() != child_info.first) { + if (++it == literals_to_stitch_.end()) { + return; + } + } + FunctionLiteral* literal = *it; + // FIXME(wiktorg) better handling of default params for arrow functions + Scope* outer_scope = literal->scope()->outer_scope(); + if (outer_scope->is_declaration_scope() && + outer_scope->AsDeclarationScope()->was_lazily_parsed()) { + continue; + } + // TODO(wiktorg) in the future internalize somewhere else (stitching may be + // done on streamer thread) + result->ast_value_factory()->Internalize(isolate); + literal->ReplaceBodyAndScope(result->literal()); + literal->SetShouldEagerCompile(); + } +} + #undef CHECK_OK #undef CHECK_OK_VOID #undef CHECK_FAILED diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h index 8a970608e7..c51c0eff01 100644 --- a/deps/v8/src/parsing/parser.h +++ b/deps/v8/src/parsing/parser.h @@ -35,7 +35,6 @@ class FunctionEntry BASE_EMBEDDED { kStartPositionIndex, kEndPositionIndex, kNumParametersIndex, - kFunctionLengthIndex, kFlagsIndex, kNumInnerFunctionsIndex, kSize @@ -49,29 +48,22 @@ class FunctionEntry BASE_EMBEDDED { class LanguageModeField : public BitField<LanguageMode, 0, 1> {}; class UsesSuperPropertyField : public BitField<bool, LanguageModeField::kNext, 1> {}; - class CallsEvalField - : public BitField<bool, UsesSuperPropertyField::kNext, 1> {}; static uint32_t EncodeFlags(LanguageMode language_mode, - bool uses_super_property, bool calls_eval) { + bool uses_super_property) { return LanguageModeField::encode(language_mode) | - UsesSuperPropertyField::encode(uses_super_property) | - CallsEvalField::encode(calls_eval); + UsesSuperPropertyField::encode(uses_super_property); } int start_pos() const { return backing_[kStartPositionIndex]; } int end_pos() const { return backing_[kEndPositionIndex]; } int num_parameters() const { return backing_[kNumParametersIndex]; } - int function_length() const { return backing_[kFunctionLengthIndex]; } LanguageMode language_mode() const { return LanguageModeField::decode(backing_[kFlagsIndex]); } bool uses_super_property() const { return UsesSuperPropertyField::decode(backing_[kFlagsIndex]); } - bool calls_eval() const { - return CallsEvalField::decode(backing_[kFlagsIndex]); - } int num_inner_functions() const { return backing_[kNumInnerFunctionsIndex]; } bool is_valid() const { return !backing_.is_empty(); } @@ -274,14 +266,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { FunctionLiteral* ParseProgram(Isolate* isolate, ParseInfo* info); FunctionLiteral* ParseFunction(Isolate* isolate, ParseInfo* info); - FunctionLiteral* DoParseFunction(ParseInfo* info, - const AstRawString* raw_name); + FunctionLiteral* DoParseFunction(ParseInfo* info); // Called by ParseProgram after setting up the scanner. FunctionLiteral* DoParseProgram(ParseInfo* info); void SetCachedData(ParseInfo* info); + void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate); + ScriptCompiler::CompileOptions compile_options() const { return compile_options_; } @@ -297,7 +290,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { reusable_preparser_ = new PreParser(zone(), &scanner_, stack_limit_, ast_value_factory(), &pending_error_handler_, runtime_call_stats_, - parsing_on_main_thread_); + preparsed_scope_data_, parsing_on_main_thread_); #define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); SET_ALLOW(natives); SET_ALLOW(tailcalls); @@ -380,9 +373,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ClassLiteralProperty::Kind kind, bool is_static, bool is_constructor, ClassInfo* class_info, bool* ok); - V8_INLINE Expression* RewriteClassLiteral(const AstRawString* name, + V8_INLINE Expression* RewriteClassLiteral(Scope* block_scope, + const AstRawString* name, ClassInfo* class_info, int pos, - bool* ok); + int end_pos, bool* ok); V8_INLINE Statement* DeclareNative(const AstRawString* name, int pos, bool* ok); @@ -561,9 +555,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // in order to force the function to be eagerly parsed, after all. LazyParsingResult SkipFunction(FunctionKind kind, DeclarationScope* function_scope, - int* num_parameters, int* function_length, - bool is_inner_function, bool may_abort, - bool* ok); + int* num_parameters, bool is_inner_function, + bool may_abort, bool* ok); Block* BuildParameterInitializationBlock( const ParserFormalParameters& parameters, bool* ok); @@ -733,7 +726,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { V8_INLINE static bool IsIdentifier(Expression* expression) { DCHECK_NOT_NULL(expression); VariableProxy* operand = expression->AsVariableProxy(); - return operand != nullptr && !operand->is_this(); + return operand != nullptr && !operand->is_this() && + !operand->is_new_target(); } V8_INLINE static const AstRawString* AsIdentifier(Expression* expression) { @@ -759,7 +753,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { V8_INLINE static bool IsBoilerplateProperty( ObjectLiteral::Property* property) { - return ObjectLiteral::IsBoilerplateProperty(property); + return !property->IsPrototype(); } V8_INLINE bool IsNative(Expression* expr) const { @@ -1161,6 +1155,11 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { PreParser* reusable_preparser_; Mode mode_; + std::vector<FunctionLiteral*> literals_to_stitch_; + Handle<String> source_; + CompilerDispatcher* compiler_dispatcher_ = nullptr; + ParseInfo* main_parse_info_ = nullptr; + friend class ParserTarget; friend class ParserTargetScope; ParserTarget* target_stack_; // for break, continue statements @@ -1178,8 +1177,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { bool temp_zoned_; ParserLogger* log_; - PreParsedScopeData* preparsed_scope_data_; - // If not kNoSourcePosition, indicates that the first function literal // encountered is a dynamic function, see CreateDynamicFunction(). This field // indicates the correct position of the ')' that closes the parameter list. diff --git a/deps/v8/src/parsing/preparse-data-format.h b/deps/v8/src/parsing/preparse-data-format.h index e579c66af9..2f317ce75f 100644 --- a/deps/v8/src/parsing/preparse-data-format.h +++ b/deps/v8/src/parsing/preparse-data-format.h @@ -14,7 +14,7 @@ struct PreparseDataConstants { public: // Layout and constants of the preparse data exchange format. static const unsigned kMagicNumber = 0xBadDead; - static const unsigned kCurrentVersion = 16; + static const unsigned kCurrentVersion = 17; static const int kMagicOffset = 0; static const int kVersionOffset = 1; diff --git a/deps/v8/src/parsing/preparse-data.cc b/deps/v8/src/parsing/preparse-data.cc index e9f98b7356..f11eb7b21e 100644 --- a/deps/v8/src/parsing/preparse-data.cc +++ b/deps/v8/src/parsing/preparse-data.cc @@ -14,15 +14,14 @@ namespace v8 { namespace internal { void ParserLogger::LogFunction(int start, int end, int num_parameters, - int function_length, LanguageMode language_mode, - bool uses_super_property, bool calls_eval, + LanguageMode language_mode, + bool uses_super_property, int num_inner_functions) { function_store_.Add(start); function_store_.Add(end); function_store_.Add(num_parameters); - function_store_.Add(function_length); - function_store_.Add(FunctionEntry::EncodeFlags( - language_mode, uses_super_property, calls_eval)); + function_store_.Add( + FunctionEntry::EncodeFlags(language_mode, uses_super_property)); function_store_.Add(num_inner_functions); } diff --git a/deps/v8/src/parsing/preparse-data.h b/deps/v8/src/parsing/preparse-data.h index 954d89ef7e..b5db652c9c 100644 --- a/deps/v8/src/parsing/preparse-data.h +++ b/deps/v8/src/parsing/preparse-data.h @@ -53,14 +53,11 @@ class PreParserLogger final { PreParserLogger() : end_(-1), num_parameters_(-1), - function_length_(-1), num_inner_functions_(-1) {} - void LogFunction(int end, int num_parameters, int function_length, - int num_inner_functions) { + void LogFunction(int end, int num_parameters, int num_inner_functions) { end_ = end; num_parameters_ = num_parameters; - function_length_ = function_length; num_inner_functions_ = num_inner_functions; } @@ -68,16 +65,12 @@ class PreParserLogger final { int num_parameters() const { return num_parameters_; } - int function_length() const { - return function_length_; - } int num_inner_functions() const { return num_inner_functions_; } private: int end_; // For function entries. int num_parameters_; - int function_length_; int num_inner_functions_; }; @@ -85,9 +78,9 @@ class ParserLogger final { public: ParserLogger(); - void LogFunction(int start, int end, int num_parameters, int function_length, + void LogFunction(int start, int end, int num_parameters, LanguageMode language_mode, bool uses_super_property, - bool calls_eval, int num_inner_functions); + int num_inner_functions); ScriptData* GetScriptData(); @@ -105,26 +98,24 @@ class PreParseData final { struct FunctionData { int end; int num_parameters; - int function_length; int num_inner_functions; LanguageMode language_mode; bool uses_super_property : 1; - bool calls_eval : 1; - FunctionData() : end(-1) {} + FunctionData() : end(kNoSourcePosition) {} - FunctionData(int end, int num_parameters, int function_length, - int num_inner_functions, LanguageMode language_mode, - bool uses_super_property, bool calls_eval) + FunctionData(int end, int num_parameters, int num_inner_functions, + LanguageMode language_mode, bool uses_super_property) : end(end), num_parameters(num_parameters), - function_length(function_length), num_inner_functions(num_inner_functions), language_mode(language_mode), - uses_super_property(uses_super_property), - calls_eval(calls_eval) {} + uses_super_property(uses_super_property) {} - bool is_valid() const { return end > 0; } + bool is_valid() const { + DCHECK_IMPLIES(end < 0, end == kNoSourcePosition); + return end != kNoSourcePosition; + } }; FunctionData GetFunctionData(int start) const; diff --git a/deps/v8/src/parsing/preparsed-scope-data.cc b/deps/v8/src/parsing/preparsed-scope-data.cc index c8deb06bc7..c8ea3de22a 100644 --- a/deps/v8/src/parsing/preparsed-scope-data.cc +++ b/deps/v8/src/parsing/preparsed-scope-data.cc @@ -20,7 +20,7 @@ class VariableMaybeAssignedField class VariableContextAllocatedField : public BitField16<bool, VariableMaybeAssignedField::kNext, 1> {}; -const int kFunctionDataSize = 9; +const int kFunctionDataSize = 8; } // namespace @@ -51,21 +51,20 @@ const int kFunctionDataSize = 9; void PreParsedScopeData::SaveData(Scope* scope) { DCHECK(!has_data_); + DCHECK_NE(scope->end_position(), kNoSourcePosition); - if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { + // We're not trying to save data for default constructors because the + // PreParser doesn't construct them. + DCHECK_IMPLIES(scope->scope_type() == ScopeType::FUNCTION_SCOPE, + (scope->AsDeclarationScope()->function_kind() & + kDefaultConstructor) == 0); + + if (scope->scope_type() == ScopeType::FUNCTION_SCOPE && + !scope->AsDeclarationScope()->is_arrow_scope()) { // This cast is OK since we're not going to have more than 2^32 elements in // the data. FIXME(marja): Implement limits for the data size. function_data_positions_[scope->start_position()] = static_cast<uint32_t>(backing_store_.size()); - // FIXME(marja): Fill in the missing fields: function_length + - // num_inner_functions. - function_index_.AddFunctionData( - scope->start_position(), - PreParseData::FunctionData( - scope->end_position(), scope->num_parameters(), -1, -1, - scope->language_mode(), - scope->AsDeclarationScope()->uses_super_property(), - scope->calls_eval())); } if (!ScopeNeedsData(scope)) { @@ -80,7 +79,7 @@ void PreParsedScopeData::SaveData(Scope* scope) { // index is needed for skipping over data for a function scope when we skip // parsing of the corresponding function. size_t data_end_index = backing_store_.size(); - backing_store_.push_back(-1); + backing_store_.push_back(0); if (!scope->is_hidden()) { for (Variable* var : *scope->locals()) { @@ -92,11 +91,24 @@ void PreParsedScopeData::SaveData(Scope* scope) { SaveDataForInnerScopes(scope); - backing_store_[data_end_index] = backing_store_.size(); + // FIXME(marja): see above. + backing_store_[data_end_index] = static_cast<uint32_t>(backing_store_.size()); +} + +void PreParsedScopeData::AddSkippableFunction( + int start_position, const PreParseData::FunctionData& function_data) { + AddFunction(start_position, function_data); + skippable_functions_.insert(start_position); +} + +void PreParsedScopeData::AddFunction( + int start_position, const PreParseData::FunctionData& function_data) { + DCHECK(function_data.is_valid()); + function_index_.AddFunctionData(start_position, function_data); } void PreParsedScopeData::RestoreData(DeclarationScope* scope) const { - int index = -1; + uint32_t index = 0; DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE); @@ -107,7 +119,7 @@ void PreParsedScopeData::RestoreData(DeclarationScope* scope) const { RestoreData(scope, &index); } -void PreParsedScopeData::RestoreData(Scope* scope, int* index_ptr) const { +void PreParsedScopeData::RestoreData(Scope* scope, uint32_t* index_ptr) const { // It's possible that scope is not present in the data at all (since PreParser // doesn't create the corresponding scope). In this case, the Scope won't // contain any variables for which we need the data. @@ -115,22 +127,21 @@ void PreParsedScopeData::RestoreData(Scope* scope, int* index_ptr) const { return; } - int& index = *index_ptr; + uint32_t& index = *index_ptr; #ifdef DEBUG // Data integrity check. - if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { - // FIXME(marja): Compare the missing fields too (function length, - // num_inner_functions). + if (scope->scope_type() == ScopeType::FUNCTION_SCOPE && + !scope->AsDeclarationScope()->is_arrow_scope()) { const PreParseData::FunctionData& data = - FindFunction(scope->start_position()); + function_index_.GetFunctionData(scope->start_position()); + DCHECK(data.is_valid()); DCHECK_EQ(data.end, scope->end_position()); // FIXME(marja): unify num_parameters too and DCHECK here. DCHECK_EQ(data.language_mode, scope->language_mode()); DCHECK_EQ(data.uses_super_property, scope->AsDeclarationScope()->uses_super_property()); - DCHECK_EQ(data.calls_eval, scope->calls_eval()); - int index_from_data = -1; + uint32_t index_from_data = 0; FindFunctionData(scope->start_position(), &index_from_data); DCHECK_EQ(index_from_data, index); } @@ -140,16 +151,19 @@ void PreParsedScopeData::RestoreData(Scope* scope, int* index_ptr) const { // This scope is a function scope representing a function we want to // skip. So just skip over its data. DCHECK(!scope->must_use_preparsed_scope_data()); + // Check that we're moving forward (not backward) in the data. + DCHECK_GT(backing_store_[index + 2], index); index = backing_store_[index + 2]; return; } + DCHECK_GE(backing_store_.size(), index + 3); DCHECK_EQ(backing_store_[index++], scope->scope_type()); if (backing_store_[index++]) { scope->RecordEvalCall(); } - int data_end_index = backing_store_[index++]; + uint32_t data_end_index = backing_store_[index++]; USE(data_end_index); if (!scope->is_hidden()) { @@ -165,13 +179,14 @@ void PreParsedScopeData::RestoreData(Scope* scope, int* index_ptr) const { DCHECK_EQ(data_end_index, index); } -FixedUint32Array* PreParsedScopeData::Serialize(Isolate* isolate) const { +Handle<PodArray<uint32_t>> PreParsedScopeData::Serialize( + Isolate* isolate) const { // FIXME(marja): save space by using a byte array and converting // function_index_ to bytes. - Handle<JSTypedArray> js_array = isolate->factory()->NewJSTypedArray( - UINT32_ELEMENTS, - function_index_.size() * kFunctionDataSize + backing_store_.size() + 1); - FixedUint32Array* array = FixedUint32Array::cast(js_array->elements()); + size_t length = + function_index_.size() * kFunctionDataSize + backing_store_.size() + 1; + Handle<PodArray<uint32_t>> array = + PodArray<uint32_t>::New(isolate, static_cast<int>(length), TENURED); array->set(0, static_cast<uint32_t>(function_index_.size())); int i = 1; @@ -183,51 +198,56 @@ FixedUint32Array* PreParsedScopeData::Serialize(Isolate* isolate) const { array->set(i++, it->second); // position in data array->set(i++, function_data.end); array->set(i++, function_data.num_parameters); - array->set(i++, function_data.function_length); array->set(i++, function_data.num_inner_functions); array->set(i++, function_data.language_mode); array->set(i++, function_data.uses_super_property); - array->set(i++, function_data.calls_eval); + array->set(i++, skippable_functions_.find(item.first) != + skippable_functions_.end()); } for (size_t j = 0; j < backing_store_.size(); ++j) { array->set(i++, static_cast<uint32_t>(backing_store_[j])); } + DCHECK_EQ(array->length(), length); return array; } -void PreParsedScopeData::Deserialize(Handle<FixedUint32Array> array) { +void PreParsedScopeData::Deserialize(PodArray<uint32_t>* array) { has_data_ = true; - DCHECK(!array.is_null()); + DCHECK_NOT_NULL(array); if (array->length() == 0) { return; } - int function_count = array->get_scalar(0); + int function_count = array->get(0); CHECK(array->length() > function_count * kFunctionDataSize); if (function_count == 0) { return; } int i = 1; for (; i < function_count * kFunctionDataSize + 1; i += kFunctionDataSize) { - int start = array->get_scalar(i); - function_data_positions_[start] = array->get_scalar(i + 1); + int start = array->get(i); + function_data_positions_[start] = array->get(i + 1); function_index_.AddFunctionData( start, PreParseData::FunctionData( - array->get_scalar(i + 2), array->get_scalar(i + 3), - array->get_scalar(i + 4), array->get_scalar(i + 5), - LanguageMode(array->get_scalar(i + 6)), - array->get_scalar(i + 7), array->get_scalar(i + 8))); + array->get(i + 2), array->get(i + 3), array->get(i + 4), + LanguageMode(array->get(i + 5)), array->get(i + 6))); + if (array->get(i + 7)) { + skippable_functions_.insert(start); + } } CHECK_EQ(function_index_.size(), function_count); backing_store_.reserve(array->length() - i); for (; i < array->length(); ++i) { - backing_store_.push_back(array->get_scalar(i)); + backing_store_.push_back(array->get(i)); } } -PreParseData::FunctionData PreParsedScopeData::FindFunction( +PreParseData::FunctionData PreParsedScopeData::FindSkippableFunction( int start_pos) const { + if (skippable_functions_.find(start_pos) == skippable_functions_.end()) { + return PreParseData::FunctionData(); + } return function_index_.GetFunctionData(start_pos); } @@ -252,15 +272,17 @@ void PreParsedScopeData::SaveDataForVariable(Variable* var) { } void PreParsedScopeData::RestoreDataForVariable(Variable* var, - int* index_ptr) const { - int& index = *index_ptr; + uint32_t* index_ptr) const { + uint32_t& index = *index_ptr; #ifdef DEBUG const AstRawString* name = var->raw_name(); - DCHECK_EQ(backing_store_[index++], name->length()); + DCHECK_GT(backing_store_.size(), index + name->length()); + DCHECK_EQ(backing_store_[index++], static_cast<uint32_t>(name->length())); for (int i = 0; i < name->length(); ++i) { DCHECK_EQ(backing_store_[index++], name->raw_data()[i]); } #endif + DCHECK_GT(backing_store_.size(), index); byte variable_data = backing_store_[index++]; if (VariableIsUsedField::decode(variable_data)) { var->set_is_used(); @@ -288,7 +310,7 @@ void PreParsedScopeData::SaveDataForInnerScopes(Scope* scope) { } void PreParsedScopeData::RestoreDataForInnerScopes(Scope* scope, - int* index_ptr) const { + uint32_t* index_ptr) const { std::vector<Scope*> scopes; for (Scope* inner = scope->inner_scope(); inner != nullptr; inner = inner->sibling()) { @@ -299,7 +321,8 @@ void PreParsedScopeData::RestoreDataForInnerScopes(Scope* scope, } } -bool PreParsedScopeData::FindFunctionData(int start_pos, int* index) const { +bool PreParsedScopeData::FindFunctionData(int start_pos, + uint32_t* index) const { auto it = function_data_positions_.find(start_pos); if (it == function_data_positions_.end()) { return false; @@ -310,7 +333,9 @@ bool PreParsedScopeData::FindFunctionData(int start_pos, int* index) const { bool PreParsedScopeData::ScopeNeedsData(Scope* scope) { if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { - return true; + // Default constructors don't need data (they cannot contain inner functions + // defined by the user). Other functions do. + return !IsDefaultConstructor(scope->AsDeclarationScope()->function_kind()); } if (!scope->is_hidden()) { for (Variable* var : *scope->locals()) { diff --git a/deps/v8/src/parsing/preparsed-scope-data.h b/deps/v8/src/parsing/preparsed-scope-data.h index fb8acab696..5d4fc3a3a0 100644 --- a/deps/v8/src/parsing/preparsed-scope-data.h +++ b/deps/v8/src/parsing/preparsed-scope-data.h @@ -5,6 +5,7 @@ #ifndef V8_PARSING_PREPARSED_SCOPE_DATA_H_ #define V8_PARSING_PREPARSED_SCOPE_DATA_H_ +#include <set> #include <unordered_map> #include <vector> @@ -65,40 +66,60 @@ class PreParsedScopeData { // subscopes') variables. void SaveData(Scope* scope); + // Save data for a function we might skip later. The data is used later for + // creating a FunctionLiteral. + void AddSkippableFunction(int start_position, + const PreParseData::FunctionData& function_data); + + // Save variable allocation data for function which contains skippable + // functions. + void AddFunction(int start_position, + const PreParseData::FunctionData& function_data); + + // FIXME(marja): We need different kinds of data for the two types of + // functions. For a skippable function we need the end position + the data + // needed for creating a FunctionLiteral. For a function which contains + // skippable functions, we need the data affecting context allocation status + // of the variables (but e.g., no end position). Currently we just save the + // same data for both. Here we can save less data. + // Restores the information needed for allocating the Scopes's (and its // subscopes') variables. - void RestoreData(Scope* scope, int* index_ptr) const; + void RestoreData(Scope* scope, uint32_t* index_ptr) const; void RestoreData(DeclarationScope* scope) const; - FixedUint32Array* Serialize(Isolate* isolate) const; - void Deserialize(Handle<FixedUint32Array> array); + Handle<PodArray<uint32_t>> Serialize(Isolate* isolate) const; + void Deserialize(PodArray<uint32_t>* array); bool Consuming() const { return has_data_; } bool Producing() const { return !has_data_; } - PreParseData::FunctionData FindFunction(int start_pos) const; + PreParseData::FunctionData FindSkippableFunction(int start_pos) const; private: friend class ScopeTestHelper; void SaveDataForVariable(Variable* var); - void RestoreDataForVariable(Variable* var, int* index_ptr) const; + void RestoreDataForVariable(Variable* var, uint32_t* index_ptr) const; void SaveDataForInnerScopes(Scope* scope); - void RestoreDataForInnerScopes(Scope* scope, int* index_ptr) const; - bool FindFunctionData(int start_pos, int* index) const; + void RestoreDataForInnerScopes(Scope* scope, uint32_t* index_ptr) const; + bool FindFunctionData(int start_pos, uint32_t* index) const; static bool ScopeNeedsData(Scope* scope); static bool IsSkippedFunctionScope(Scope* scope); // TODO(marja): Make the backing store more efficient once we know exactly // what data is needed. - std::vector<byte> backing_store_; + std::vector<uint32_t> backing_store_; - // Start pos -> FunctionData. + // Start pos -> FunctionData. Used for creating FunctionLiterals for skipped + // functions (when they're actually skipped). PreParseData function_index_; // Start pos -> position in backing_store_. std::unordered_map<uint32_t, uint32_t> function_data_positions_; + // Start positions of skippable functions. + std::set<uint32_t> skippable_functions_; bool has_data_ = false; diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc index 95cf8caefd..c408af88c9 100644 --- a/deps/v8/src/parsing/preparser.cc +++ b/deps/v8/src/parsing/preparser.cc @@ -14,6 +14,7 @@ #include "src/parsing/parser-base.h" #include "src/parsing/preparse-data-format.h" #include "src/parsing/preparse-data.h" +#include "src/parsing/preparsed-scope-data.h" #include "src/parsing/preparser.h" #include "src/unicode.h" #include "src/utils.h" @@ -100,10 +101,8 @@ PreParserIdentifier PreParser::GetSymbol() const { return symbol; } -PreParser::PreParseResult PreParser::PreParseProgram(bool is_module, - int* use_counts) { +PreParser::PreParseResult PreParser::PreParseProgram(bool is_module) { DCHECK_NULL(scope_); - use_counts_ = use_counts; DeclarationScope* scope = NewScriptScope(); #ifdef DEBUG scope->set_is_being_lazily_parsed(true); @@ -122,7 +121,6 @@ PreParser::PreParseResult PreParser::PreParseProgram(bool is_module, PreParserStatementList body; ParseStatementList(body, Token::EOS, &ok); original_scope_ = nullptr; - use_counts_ = nullptr; if (stack_overflow()) return kPreParseStackOverflow; if (!ok) { ReportUnexpectedToken(scanner()->current_token()); @@ -213,6 +211,18 @@ PreParser::PreParseResult PreParser::PreParseFunction( // masks the arguments object. Declare arguments before declaring the // function var since the arguments object masks 'function arguments'. function_scope->DeclareArguments(ast_value_factory()); + + if (FLAG_experimental_preparser_scope_analysis && + preparsed_scope_data_ != nullptr) { + // We're not going to skip this function, but it might contain skippable + // functions inside it. + preparsed_scope_data_->AddFunction( + scope()->start_position(), + PreParseData::FunctionData( + scanner()->peek_location().end_pos, scope()->num_parameters(), + GetLastFunctionLiteralId(), scope()->language_mode(), + scope()->AsDeclarationScope()->uses_super_property())); + } } use_counts_ = nullptr; @@ -276,9 +286,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral( runtime_call_stats_, counters[track_unresolved_variables_][parsing_on_main_thread_]); - bool is_top_level = - scope()->AllowsLazyParsingWithoutUnresolvedVariables(original_scope_); - DeclarationScope* function_scope = NewFunctionScope(kind); function_scope->SetLanguageMode(language_mode); FunctionState function_state(&function_state_, &scope_, function_scope); @@ -326,24 +333,15 @@ PreParser::Expression PreParser::ParseFunctionLiteral( CheckStrictOctalLiteral(start_position, end_position, CHECK_OK); } - if (FLAG_use_parse_tasks && is_top_level && preparse_data_) { - preparse_data_->AddFunctionData( + if (FLAG_experimental_preparser_scope_analysis && + track_unresolved_variables_ && preparsed_scope_data_ != nullptr) { + preparsed_scope_data_->AddSkippableFunction( start_position, PreParseData::FunctionData( - end_position, formals.num_parameters(), formals.function_length, - GetLastFunctionLiteralId() - func_id, language_mode, - function_scope->uses_super_property(), - function_scope->calls_eval())); - // TODO(wiktorg) spin-off a parse task - if (FLAG_trace_parse_tasks) { - PrintF("Saved function at %d to %d with:\n", start_position, - end_position); - PrintF("\t- %d params\n", formals.num_parameters()); - PrintF("\t- %d function length\n", formals.function_length); - PrintF("\t- %d inner-funcs\n", GetLastFunctionLiteralId() - func_id); - } + end_position, scope()->num_parameters(), + GetLastFunctionLiteralId() - func_id, scope()->language_mode(), + scope()->AsDeclarationScope()->uses_super_property())); } - if (FLAG_trace_preparse) { PrintF(" [%s]: %i-%i\n", track_unresolved_variables_ ? "Preparse resolution" @@ -366,7 +364,7 @@ PreParser::LazyParsingResult PreParser::ParseStatementListAndLogFunction( int body_end = scanner()->peek_location().end_pos; DCHECK_EQ(this->scope()->is_function_scope(), formals->is_simple); log_.LogFunction(body_end, formals->num_parameters(), - formals->function_length, GetLastFunctionLiteralId()); + GetLastFunctionLiteralId()); return kLazyParsingComplete; } @@ -374,13 +372,9 @@ PreParserExpression PreParser::ExpressionFromIdentifier( PreParserIdentifier name, int start_position, InferName infer) { VariableProxy* proxy = nullptr; if (track_unresolved_variables_) { - AstNodeFactory factory(ast_value_factory()); - // Setting the Zone is necessary because zone_ might be the temp Zone, and - // AstValueFactory doesn't know about it. - factory.set_zone(zone()); DCHECK_NOT_NULL(name.string_); - proxy = scope()->NewUnresolved(&factory, name.string_, start_position, - NORMAL_VARIABLE); + proxy = scope()->NewUnresolved(factory()->ast_node_factory(), name.string_, + start_position, NORMAL_VARIABLE); } return PreParserExpression::FromIdentifier(name, proxy, zone()); } @@ -397,7 +391,7 @@ void PreParser::DeclareAndInitializeVariables( declaration_descriptor->scope->RemoveUnresolved(variable); Variable* var = scope()->DeclareVariableName( variable->raw_name(), declaration_descriptor->mode); - if (FLAG_preparser_scope_analysis) { + if (FLAG_experimental_preparser_scope_analysis) { MarkLoopVariableAsAssigned(declaration_descriptor->scope, var); // This is only necessary if there is an initializer, but we don't have // that information here. Consequently, the preparser sometimes says diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h index 637efa2655..3bb85f0b20 100644 --- a/deps/v8/src/parsing/preparser.h +++ b/deps/v8/src/parsing/preparser.h @@ -178,6 +178,11 @@ class PreParserExpression { variables); } + static PreParserExpression NewTargetExpression() { + return PreParserExpression(TypeField::encode(kExpression) | + ExpressionTypeField::encode(kNewTarget)); + } + static PreParserExpression ObjectLiteral( ZoneList<VariableProxy*>* variables) { return PreParserExpression(TypeField::encode(kObjectLiteralExpression), @@ -358,7 +363,8 @@ class PreParserExpression { kCallEvalExpression, kSuperCallReference, kNoTemplateTagExpression, - kAssignment + kAssignment, + kNewTarget }; explicit PreParserExpression(uint32_t expression_code, @@ -387,7 +393,7 @@ class PreParserExpression { // The rest of the bits are interpreted depending on the value // of the Type field, so they can share the storage. - typedef BitField<ExpressionType, TypeField::kNext, 3> ExpressionTypeField; + typedef BitField<ExpressionType, TypeField::kNext, 4> ExpressionTypeField; typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField; typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseAsmField; typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 10> @@ -538,11 +544,15 @@ class PreParserStatement { class PreParserFactory { public: - explicit PreParserFactory(AstValueFactory* ast_value_factory) - : ast_value_factory_(ast_value_factory), - zone_(ast_value_factory->zone()) {} + explicit PreParserFactory(AstValueFactory* ast_value_factory, Zone* zone) + : ast_node_factory_(ast_value_factory, zone), zone_(zone) {} + + void set_zone(Zone* zone) { + ast_node_factory_.set_zone(zone); + zone_ = zone; + } - void set_zone(Zone* zone) { zone_ = zone; } + AstNodeFactory* ast_node_factory() { return &ast_node_factory_; } PreParserExpression NewStringLiteral(PreParserIdentifier identifier, int pos) { @@ -551,10 +561,8 @@ class PreParserFactory { PreParserExpression expression = PreParserExpression::Default(); if (identifier.string_ != nullptr) { DCHECK(FLAG_lazy_inner_functions); - AstNodeFactory factory(ast_value_factory_); - factory.set_zone(zone_); - VariableProxy* variable = - factory.NewVariableProxy(identifier.string_, NORMAL_VARIABLE); + VariableProxy* variable = ast_node_factory_.NewVariableProxy( + identifier.string_, NORMAL_VARIABLE); expression.AddVariable(variable, zone_); } return expression; @@ -789,7 +797,9 @@ class PreParserFactory { } private: - AstValueFactory* ast_value_factory_; + // For creating VariableProxy objects (if + // PreParser::track_unresolved_variables_ is used). + AstNodeFactory ast_node_factory_; Zone* zone_; }; @@ -889,12 +899,12 @@ class PreParser : public ParserBase<PreParser> { AstValueFactory* ast_value_factory, PendingCompilationErrorHandler* pending_error_handler, RuntimeCallStats* runtime_call_stats, + PreParsedScopeData* preparsed_scope_data = nullptr, bool parsing_on_main_thread = true) : ParserBase<PreParser>(zone, scanner, stack_limit, nullptr, ast_value_factory, runtime_call_stats, - parsing_on_main_thread), + preparsed_scope_data, parsing_on_main_thread), use_counts_(nullptr), - preparse_data_(FLAG_use_parse_tasks ? new PreParseData() : nullptr), track_unresolved_variables_(false), pending_error_handler_(pending_error_handler) {} @@ -906,8 +916,7 @@ class PreParser : public ParserBase<PreParser> { // success (even if parsing failed, the pre-parse data successfully // captured the syntax error), and false if a stack-overflow happened // during parsing. - PreParseResult PreParseProgram(bool is_module = false, - int* use_counts = nullptr); + PreParseResult PreParseProgram(bool is_module = false); // Parses a single function literal, from the opening parentheses before // parameters to the closing brace after the body. @@ -923,8 +932,6 @@ class PreParser : public ParserBase<PreParser> { bool track_unresolved_variables, bool may_abort, int* use_counts); - const PreParseData* preparse_data() const { return preparse_data_.get(); } - private: // These types form an algebra over syntactic categories that is just // rich enough to let us recognize and propagate the constructs that @@ -941,9 +948,11 @@ class PreParser : public ParserBase<PreParser> { bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; } bool parse_lazily() const { return false; } - V8_INLINE LazyParsingResult SkipFunction( - FunctionKind kind, DeclarationScope* function_scope, int* num_parameters, - int* function_length, bool is_inner_function, bool may_abort, bool* ok) { + V8_INLINE LazyParsingResult SkipFunction(FunctionKind kind, + DeclarationScope* function_scope, + int* num_parameters, + bool is_inner_function, + bool may_abort, bool* ok) { UNREACHABLE(); return kLazyParsingComplete; } @@ -1122,16 +1131,23 @@ class PreParser : public ParserBase<PreParser> { } V8_INLINE void DeclareClassVariable(PreParserIdentifier name, ClassInfo* class_info, - int class_token_pos, bool* ok) {} + int class_token_pos, bool* ok) { + if (name.string_ != nullptr) { + DCHECK(track_unresolved_variables_); + scope()->DeclareVariableName(name.string_, CONST); + } + } V8_INLINE void DeclareClassProperty(PreParserIdentifier class_name, PreParserExpression property, ClassLiteralProperty::Kind kind, bool is_static, bool is_constructor, ClassInfo* class_info, bool* ok) { } - V8_INLINE PreParserExpression RewriteClassLiteral(PreParserIdentifier name, + V8_INLINE PreParserExpression RewriteClassLiteral(Scope* scope, + PreParserIdentifier name, ClassInfo* class_info, - int pos, bool* ok) { + int pos, int end_pos, + bool* ok) { bool has_default_constructor = !class_info->has_seen_constructor; // Account for the default constructor. if (has_default_constructor) GetNextFunctionLiteralId(); @@ -1494,12 +1510,9 @@ class PreParser : public ParserBase<PreParser> { V8_INLINE PreParserExpression ThisExpression(int pos = kNoSourcePosition) { ZoneList<VariableProxy*>* variables = nullptr; if (track_unresolved_variables_) { - AstNodeFactory factory(ast_value_factory()); - // Setting the Zone is necessary because zone_ might be the temp Zone, and - // AstValueFactory doesn't know about it. - factory.set_zone(zone()); VariableProxy* proxy = scope()->NewUnresolved( - &factory, ast_value_factory()->this_string(), pos, THIS_VARIABLE); + factory()->ast_node_factory(), ast_value_factory()->this_string(), + pos, THIS_VARIABLE); variables = new (zone()) ZoneList<VariableProxy*>(1, zone()); variables->Add(proxy, zone()); @@ -1508,15 +1521,34 @@ class PreParser : public ParserBase<PreParser> { } V8_INLINE PreParserExpression NewSuperPropertyReference(int pos) { + if (track_unresolved_variables_) { + scope()->NewUnresolved(factory()->ast_node_factory(), + ast_value_factory()->this_function_string(), pos, + NORMAL_VARIABLE); + scope()->NewUnresolved(factory()->ast_node_factory(), + ast_value_factory()->this_string(), pos, + THIS_VARIABLE); + } return PreParserExpression::Default(); } V8_INLINE PreParserExpression NewSuperCallReference(int pos) { + if (track_unresolved_variables_) { + scope()->NewUnresolved(factory()->ast_node_factory(), + ast_value_factory()->this_function_string(), pos, + NORMAL_VARIABLE); + scope()->NewUnresolved(factory()->ast_node_factory(), + ast_value_factory()->new_target_string(), pos, + NORMAL_VARIABLE); + scope()->NewUnresolved(factory()->ast_node_factory(), + ast_value_factory()->this_string(), pos, + THIS_VARIABLE); + } return PreParserExpression::SuperCallReference(); } V8_INLINE PreParserExpression NewTargetExpression(int pos) { - return PreParserExpression::Default(); + return PreParserExpression::NewTargetExpression(); } V8_INLINE PreParserExpression FunctionSentExpression(int pos) { @@ -1660,7 +1692,6 @@ class PreParser : public ParserBase<PreParser> { // Preparser's private field members. int* use_counts_; - std::unique_ptr<PreParseData> preparse_data_; bool track_unresolved_variables_; PreParserLogger log_; PendingCompilationErrorHandler* pending_error_handler_; diff --git a/deps/v8/src/parsing/rewriter.cc b/deps/v8/src/parsing/rewriter.cc index 87359f79ac..00eb29550a 100644 --- a/deps/v8/src/parsing/rewriter.cc +++ b/deps/v8/src/parsing/rewriter.cc @@ -24,7 +24,7 @@ class Processor final : public AstVisitor<Processor> { breakable_(false), zone_(ast_value_factory->zone()), closure_scope_(closure_scope), - factory_(ast_value_factory) { + factory_(ast_value_factory, ast_value_factory->zone()) { DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); InitializeAstVisitor(stack_limit); } @@ -38,7 +38,7 @@ class Processor final : public AstVisitor<Processor> { breakable_(false), zone_(ast_value_factory->zone()), closure_scope_(closure_scope), - factory_(ast_value_factory) { + factory_(ast_value_factory, zone_) { DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); InitializeAstVisitor(parser->stack_limit()); } diff --git a/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc index d3162dfbb2..e22308e8d5 100644 --- a/deps/v8/src/parsing/scanner-character-streams.cc +++ b/deps/v8/src/parsing/scanner-character-streams.cc @@ -387,8 +387,10 @@ void Utf8ExternalStreamingStream::SearchPosition(size_t position) { // checking whether the # bytes in a chunk are equal to the # chars, and if // so avoid the expensive SkipToPosition.) bool ascii_only_chunk = + chunks_[chunk_no].start.incomplete_char == + unibrow::Utf8::Utf8IncrementalBuffer(0) && (chunks_[chunk_no + 1].start.bytes - chunks_[chunk_no].start.bytes) == - (chunks_[chunk_no + 1].start.chars - chunks_[chunk_no].start.chars); + (chunks_[chunk_no + 1].start.chars - chunks_[chunk_no].start.chars); if (ascii_only_chunk) { size_t skip = position - chunks_[chunk_no].start.chars; current_ = {chunk_no, @@ -816,16 +818,20 @@ Utf16CharacterStream* ScannerStream::For(Handle<String> data) { Utf16CharacterStream* ScannerStream::For(Handle<String> data, int start_pos, int end_pos) { DCHECK(start_pos >= 0); + DCHECK(start_pos <= end_pos); DCHECK(end_pos <= data->length()); if (data->IsExternalOneByteString()) { return new ExternalOneByteStringUtf16CharacterStream( - Handle<ExternalOneByteString>::cast(data), start_pos, end_pos); + Handle<ExternalOneByteString>::cast(data), + static_cast<size_t>(start_pos), static_cast<size_t>(end_pos)); } else if (data->IsExternalTwoByteString()) { return new ExternalTwoByteStringUtf16CharacterStream( - Handle<ExternalTwoByteString>::cast(data), start_pos, end_pos); + Handle<ExternalTwoByteString>::cast(data), + static_cast<size_t>(start_pos), static_cast<size_t>(end_pos)); } else { // TODO(vogelheim): Maybe call data.Flatten() first? - return new GenericStringUtf16CharacterStream(data, start_pos, end_pos); + return new GenericStringUtf16CharacterStream( + data, static_cast<size_t>(start_pos), static_cast<size_t>(end_pos)); } } diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc index 81839990c6..8dfb74c06a 100644 --- a/deps/v8/src/parsing/scanner.cc +++ b/deps/v8/src/parsing/scanner.cc @@ -182,16 +182,14 @@ Scanner::Scanner(UnicodeCache* unicode_cache) octal_message_(MessageTemplate::kNone), found_html_comment_(false) {} -void Scanner::Initialize(Utf16CharacterStream* source) { +void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) { DCHECK_NOT_NULL(source); source_ = source; + is_module_ = is_module; // Need to capture identifiers in order to recognize "get" and "set" // in object literals. Init(); - // Skip initial whitespace allowing HTML comment ends just like - // after a newline and scan first token. has_line_terminator_before_next_ = true; - SkipWhiteSpace(); Scan(); } @@ -443,7 +441,7 @@ static inline bool IsLittleEndianByteOrderMark(uc32 c) { return c == 0xFFFE; } -bool Scanner::SkipWhiteSpace() { +Token::Value Scanner::SkipWhiteSpace() { int start_position = source_pos(); while (true) { @@ -481,11 +479,26 @@ bool Scanner::SkipWhiteSpace() { } // Treat the rest of the line as a comment. - SkipSingleLineComment(); + Token::Value token = SkipSingleHTMLComment(); + if (token == Token::ILLEGAL) { + return token; + } } // Return whether or not we skipped any characters. - return source_pos() != start_position; + if (source_pos() == start_position) { + return Token::ILLEGAL; + } + + return Token::WHITESPACE; +} + +Token::Value Scanner::SkipSingleHTMLComment() { + if (is_module_) { + ReportScannerError(source_pos(), MessageTemplate::kHtmlCommentInModule); + return Token::ILLEGAL; + } + return SkipSingleLineComment(); } Token::Value Scanner::SkipSingleLineComment() { @@ -606,7 +619,7 @@ Token::Value Scanner::ScanHtmlComment() { } found_html_comment_ = true; - return SkipSingleLineComment(); + return SkipSingleHTMLComment(); } void Scanner::Scan() { @@ -712,7 +725,7 @@ void Scanner::Scan() { if (c0_ == '>' && HasAnyLineTerminatorBeforeNext()) { // For compatibility with SpiderMonkey, we skip lines that // start with an HTML comment end '-->'. - token = SkipSingleLineComment(); + token = SkipSingleHTMLComment(); } else { token = Token::DEC; } @@ -864,10 +877,11 @@ void Scanner::Scan() { token = ScanIdentifierOrKeyword(); } else if (IsDecimalDigit(c0_)) { token = ScanNumber(false); - } else if (SkipWhiteSpace()) { - token = Token::WHITESPACE; } else { - token = Select(Token::ILLEGAL); + token = SkipWhiteSpace(); + if (token == Token::ILLEGAL) { + Advance(); + } } break; } @@ -1777,13 +1791,6 @@ double Scanner::DoubleValue() { ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY); } - -bool Scanner::ContainsDot() { - DCHECK(is_literal_one_byte()); - Vector<const uint8_t> str = literal_one_byte_string(); - return std::find(str.begin(), str.end(), '.') != str.end(); -} - bool Scanner::IsDuplicateSymbol(DuplicateFinder* duplicate_finder, AstValueFactory* ast_value_factory) const { DCHECK_NOT_NULL(duplicate_finder); diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h index 5b3b671523..03b3f316c2 100644 --- a/deps/v8/src/parsing/scanner.h +++ b/deps/v8/src/parsing/scanner.h @@ -197,7 +197,7 @@ class Scanner { explicit Scanner(UnicodeCache* scanner_contants); - void Initialize(Utf16CharacterStream* source); + void Initialize(Utf16CharacterStream* source, bool is_module); // Returns the next token and advances input. Token::Value Next(); @@ -247,7 +247,6 @@ class Scanner { AstValueFactory* ast_value_factory) const; double DoubleValue(); - bool ContainsDot(); inline bool CurrentMatches(Token::Value token) const { DCHECK(Token::IsKeyword(token)); @@ -689,7 +688,8 @@ class Scanner { // Scans a single JavaScript token. void Scan(); - bool SkipWhiteSpace(); + Token::Value SkipWhiteSpace(); + Token::Value SkipSingleHTMLComment(); Token::Value SkipSingleLineComment(); Token::Value SkipSourceURLComment(); void TryToParseSourceURLComment(); @@ -717,6 +717,8 @@ class Scanner { template <bool capture_raw> uc32 ScanUnicodeEscape(); + bool is_module_; + Token::Value ScanTemplateSpan(); // Return the current source position. |