diff options
author | Michaƫl Zasso <targos@protonmail.com> | 2018-01-24 20:16:06 +0100 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2018-01-24 15:02:20 -0800 |
commit | 4c4af643e5042d615a60c6bbc05aee9d81b903e5 (patch) | |
tree | 3fb0a97988fe4439ae3ae06f26915d1dcf8cab92 /deps/v8/src/parsing | |
parent | fa9f31a4fda5a3782c652e56e394465805ebb50f (diff) | |
download | node-new-4c4af643e5042d615a60c6bbc05aee9d81b903e5.tar.gz |
deps: update V8 to 6.4.388.40
PR-URL: https://github.com/nodejs/node/pull/17489
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/parsing')
21 files changed, 1331 insertions, 908 deletions
diff --git a/deps/v8/src/parsing/background-parsing-task.cc b/deps/v8/src/parsing/background-parsing-task.cc new file mode 100644 index 0000000000..387cd3a1c6 --- /dev/null +++ b/deps/v8/src/parsing/background-parsing-task.cc @@ -0,0 +1,111 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/parsing/background-parsing-task.h" + +#include "src/counters.h" +#include "src/objects-inl.h" +#include "src/parsing/parser.h" +#include "src/parsing/scanner-character-streams.h" +#include "src/vm-state-inl.h" + +namespace v8 { +namespace internal { + +void StreamedSource::Release() { + parser.reset(); + info.reset(); +} + +BackgroundParsingTask::BackgroundParsingTask( + StreamedSource* source, ScriptCompiler::CompileOptions options, + int stack_size, Isolate* isolate) + : source_(source), + stack_size_(stack_size), + script_data_(nullptr), + timer_(isolate->counters()->compile_script_on_background()) { + // We don't set the context to the CompilationInfo yet, because the background + // thread cannot do anything with it anyway. We set it just before compilation + // on the foreground thread. + DCHECK(options == ScriptCompiler::kProduceParserCache || + options == ScriptCompiler::kProduceCodeCache || + options == ScriptCompiler::kProduceFullCodeCache || + options == ScriptCompiler::kNoCompileOptions); + + VMState<PARSER> state(isolate); + + // Prepare the data for the internalization phase and compilation phase, which + // will happen in the main thread after parsing. + ParseInfo* info = new ParseInfo(isolate->allocator()); + info->InitFromIsolate(isolate); + if (V8_UNLIKELY(FLAG_runtime_stats)) { + info->set_runtime_call_stats(new (info->zone()) RuntimeCallStats()); + } else { + info->set_runtime_call_stats(nullptr); + } + info->set_toplevel(); + std::unique_ptr<Utf16CharacterStream> stream( + ScannerStream::For(source->source_stream.get(), source->encoding, + info->runtime_call_stats())); + info->set_character_stream(std::move(stream)); + info->set_unicode_cache(&source_->unicode_cache); + info->set_compile_options(options); + info->set_allow_lazy_parsing(); + if (V8_UNLIKELY(info->block_coverage_enabled())) { + info->AllocateSourceRangeMap(); + } + info->set_cached_data(&script_data_); + LanguageMode language_mode = construct_language_mode(FLAG_use_strict); + info->set_language_mode( + stricter_language_mode(info->language_mode(), language_mode)); + + source->info.reset(info); + allocator_ = isolate->allocator(); + + // Parser needs to stay alive for finalizing the parsing on the main + // thread. + source_->parser.reset(new Parser(source_->info.get())); + source_->parser->DeserializeScopeChain(source_->info.get(), + MaybeHandle<ScopeInfo>()); +} + +void BackgroundParsingTask::Run() { + TimedHistogramScope timer(timer_); + DisallowHeapAllocation no_allocation; + DisallowHandleAllocation no_handles; + DisallowHandleDereference no_deref; + + source_->info->set_on_background_thread(true); + + // Reset the stack limit of the parser to reflect correctly that we're on a + // background thread. + uintptr_t old_stack_limit = source_->info->stack_limit(); + uintptr_t stack_limit = GetCurrentStackPosition() - stack_size_ * KB; + source_->info->set_stack_limit(stack_limit); + source_->parser->set_stack_limit(stack_limit); + + source_->parser->ParseOnBackground(source_->info.get()); + if (FLAG_background_compile && source_->info->literal() != nullptr) { + // Parsing has succeeded, compile. + source_->outer_function_job = Compiler::CompileTopLevelOnBackgroundThread( + source_->info.get(), allocator_, &source_->inner_function_jobs); + } + + if (script_data_ != nullptr) { + source_->cached_data.reset(new ScriptCompiler::CachedData( + script_data_->data(), script_data_->length(), + ScriptCompiler::CachedData::BufferOwned)); + script_data_->ReleaseDataOwnership(); + delete script_data_; + script_data_ = nullptr; + } + + source_->info->EmitBackgroundParseStatisticsOnBackgroundThread(); + + source_->info->set_on_background_thread(false); + source_->info->set_stack_limit(old_stack_limit); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/parsing/background-parsing-task.h b/deps/v8/src/parsing/background-parsing-task.h new file mode 100644 index 0000000000..eb3ed61e2e --- /dev/null +++ b/deps/v8/src/parsing/background-parsing-task.h @@ -0,0 +1,74 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_PARSING_BACKGROUND_PARSING_TASK_H_ +#define V8_PARSING_BACKGROUND_PARSING_TASK_H_ + +#include <memory> + +#include "include/v8.h" +#include "src/base/platform/platform.h" +#include "src/base/platform/semaphore.h" +#include "src/compiler.h" +#include "src/parsing/parse-info.h" +#include "src/unicode-cache.h" + +namespace v8 { +namespace internal { + +class Parser; +class ScriptData; +class TimedHistogram; + +// Internal representation of v8::ScriptCompiler::StreamedSource. Contains all +// data which needs to be transmitted between threads for background parsing, +// finalizing it on the main thread, and compiling on the main thread. +struct StreamedSource { + StreamedSource(ScriptCompiler::ExternalSourceStream* source_stream, + ScriptCompiler::StreamedSource::Encoding encoding) + : source_stream(source_stream), encoding(encoding) {} + + void Release(); + + // Internal implementation of v8::ScriptCompiler::StreamedSource. + std::unique_ptr<ScriptCompiler::ExternalSourceStream> source_stream; + ScriptCompiler::StreamedSource::Encoding encoding; + std::unique_ptr<ScriptCompiler::CachedData> cached_data; + + // Data needed for parsing, and data needed to to be passed between thread + // between parsing and compilation. These need to be initialized before the + // compilation starts. + UnicodeCache unicode_cache; + std::unique_ptr<ParseInfo> info; + std::unique_ptr<Parser> parser; + + // Data needed for finalizing compilation after background compilation. + std::unique_ptr<CompilationJob> outer_function_job; + CompilationJobList inner_function_jobs; + + // Prevent copying. + StreamedSource(const StreamedSource&) = delete; + StreamedSource& operator=(const StreamedSource&) = delete; +}; + +class BackgroundParsingTask : public ScriptCompiler::ScriptStreamingTask { + public: + BackgroundParsingTask(StreamedSource* source, + ScriptCompiler::CompileOptions options, int stack_size, + Isolate* isolate); + + virtual void Run(); + + private: + StreamedSource* source_; // Not owned. + int stack_size_; + ScriptData* script_data_; + AccountingAllocator* allocator_; + TimedHistogram* timer_; +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_PARSING_BACKGROUND_PARSING_TASK_H_ diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h index d2dc6fa170..6c6c813b3e 100644 --- a/deps/v8/src/parsing/expression-classifier.h +++ b/deps/v8/src/parsing/expression-classifier.h @@ -424,7 +424,7 @@ class ExpressionClassifier { typename Types::Base* base_; ExpressionClassifier* previous_; Zone* zone_; - ZoneList<typename Types::Expression>* non_patterns_to_rewrite_; + ZoneList<typename Types::RewritableExpression>* non_patterns_to_rewrite_; ZoneList<Error>* reported_errors_; DuplicateFinder* duplicate_finder_; // The uint16_t for non_pattern_begin_ will not be enough in the case, diff --git a/deps/v8/src/parsing/expression-scope-reparenter.cc b/deps/v8/src/parsing/expression-scope-reparenter.cc index 6ca29611c1..18c52add11 100644 --- a/deps/v8/src/parsing/expression-scope-reparenter.cc +++ b/deps/v8/src/parsing/expression-scope-reparenter.cc @@ -27,6 +27,7 @@ class Reparenter final : public AstTraversalVisitor<Reparenter> { void VisitFunctionLiteral(FunctionLiteral* expr); void VisitClassLiteral(ClassLiteral* expr); void VisitVariableProxy(VariableProxy* expr); + void VisitRewritableExpression(RewritableExpression* expr); void VisitBlock(Block* stmt); void VisitTryCatchStatement(TryCatchStatement* stmt); @@ -45,6 +46,12 @@ void Reparenter::VisitClassLiteral(ClassLiteral* class_literal) { // scope on its scope chain. DCHECK_EQ(class_literal->constructor()->scope()->outer_scope(), class_literal->scope()); + + if (class_literal->static_fields_initializer() != nullptr) { + DCHECK_EQ( + class_literal->static_fields_initializer()->scope()->outer_scope(), + class_literal->scope()); + } #if DEBUG // The same goes for the rest of the class, but we do some // sanity checking in debug mode. @@ -72,6 +79,11 @@ void Reparenter::VisitVariableProxy(VariableProxy* proxy) { } } +void Reparenter::VisitRewritableExpression(RewritableExpression* expr) { + Visit(expr->expression()); + expr->set_scope(scope_); +} + void Reparenter::VisitBlock(Block* stmt) { if (stmt->scope() != nullptr) stmt->scope()->ReplaceOuterScope(scope_); diff --git a/deps/v8/src/parsing/func-name-inferrer.cc b/deps/v8/src/parsing/func-name-inferrer.cc index a6cc179b82..b55c5ddd5d 100644 --- a/deps/v8/src/parsing/func-name-inferrer.cc +++ b/deps/v8/src/parsing/func-name-inferrer.cc @@ -46,7 +46,7 @@ void FuncNameInferrer::PushVariableName(const AstRawString* name) { void FuncNameInferrer::RemoveAsyncKeywordFromEnd() { if (IsOpen()) { - CHECK(names_stack_.length() > 0); + CHECK_GT(names_stack_.length(), 0); CHECK(names_stack_.last().name->IsOneByteEqualTo("async")); names_stack_.RemoveLast(); } diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc index f17916ccb6..1c9d648a1e 100644 --- a/deps/v8/src/parsing/parse-info.cc +++ b/deps/v8/src/parsing/parse-info.cc @@ -53,13 +53,16 @@ ParseInfo::ParseInfo(Handle<SharedFunctionInfo> shared) set_end_position(shared->end_position()); function_literal_id_ = shared->function_literal_id(); set_language_mode(shared->language_mode()); - set_module(shared->kind() == FunctionKind::kModule); set_asm_wasm_broken(shared->is_asm_wasm_broken()); + set_requires_instance_fields_initializer( + shared->requires_instance_fields_initializer()); Handle<Script> script(Script::cast(shared->script())); set_script(script); set_native(script->type() == Script::TYPE_NATIVE); set_eval(script->compilation_type() == Script::COMPILATION_TYPE_EVAL); + set_module(script->origin_options().IsModule()); + DCHECK(!(is_eval() && is_module())); Handle<HeapObject> scope_info(shared->outer_scope_info()); if (!scope_info->IsTheHole(isolate) && @@ -90,6 +93,8 @@ ParseInfo::ParseInfo(Handle<Script> script) set_native(script->type() == Script::TYPE_NATIVE); set_eval(script->compilation_type() == Script::COMPILATION_TYPE_EVAL); + set_module(script->origin_options().IsModule()); + DCHECK(!(is_eval() && is_module())); set_collect_type_profile(script->GetIsolate()->is_collecting_type_profile() && script->IsUserJavaScript()); @@ -114,7 +119,6 @@ ParseInfo* ParseInfo::AllocateWithoutScript(Handle<SharedFunctionInfo> shared) { p->set_end_position(shared->end_position()); p->function_literal_id_ = shared->function_literal_id(); p->set_language_mode(shared->language_mode()); - p->set_module(shared->kind() == FunctionKind::kModule); // BUG(5946): This function exists as a workaround until we can // get rid of %SetCode in our native functions. The ParseInfo @@ -126,6 +130,8 @@ ParseInfo* ParseInfo::AllocateWithoutScript(Handle<SharedFunctionInfo> shared) { // We tolerate a ParseInfo without a Script in this case. p->set_native(true); p->set_eval(false); + p->set_module(false); + DCHECK_NE(shared->kind(), FunctionKind::kModule); Handle<HeapObject> scope_info(shared->outer_scope_info()); if (!scope_info->IsTheHole(isolate) && @@ -151,12 +157,27 @@ void ParseInfo::InitFromIsolate(Isolate* isolate) { set_stack_limit(isolate->stack_guard()->real_climit()); set_unicode_cache(isolate->unicode_cache()); set_runtime_call_stats(isolate->counters()->runtime_call_stats()); + set_logger(isolate->logger()); set_ast_string_constants(isolate->ast_string_constants()); if (isolate->is_block_code_coverage()) set_block_coverage_enabled(); if (isolate->is_collecting_type_profile()) set_collect_type_profile(); } -void ParseInfo::UpdateStatisticsAfterBackgroundParse(Isolate* isolate) { +void ParseInfo::EmitBackgroundParseStatisticsOnBackgroundThread() { + // If runtime call stats was enabled by tracing, emit a trace event at the + // end of background parsing on the background thread. + if (runtime_call_stats_ && + (FLAG_runtime_stats & + v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { + auto value = v8::tracing::TracedValue::Create(); + runtime_call_stats_->Dump(value.get()); + TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"), + "V8.RuntimeStats", TRACE_EVENT_SCOPE_THREAD, + "runtime-call-stats", std::move(value)); + } +} + +void ParseInfo::UpdateBackgroundParseStatisticsOnMainThread(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(); @@ -197,7 +218,7 @@ void ParseInfo::ResetCharacterStream() { character_stream_.reset(); } void ParseInfo::set_character_stream( std::unique_ptr<Utf16CharacterStream> character_stream) { - DCHECK(character_stream_.get() == nullptr); + DCHECK_NULL(character_stream_); character_stream_.swap(character_stream); } diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h index 1426f94bbf..9deea1ecac 100644 --- a/deps/v8/src/parsing/parse-info.h +++ b/deps/v8/src/parsing/parse-info.h @@ -13,6 +13,7 @@ #include "src/globals.h" #include "src/handles.h" #include "src/parsing/preparsed-scope-data.h" +#include "src/pending-compilation-error-handler.h" namespace v8 { @@ -27,6 +28,7 @@ class AstValueFactory; class DeclarationScope; class FunctionLiteral; class RuntimeCallStats; +class Logger; class ScriptData; class SourceRangeMap; class UnicodeCache; @@ -73,13 +75,17 @@ class V8_EXPORT_PRIVATE ParseInfo { FLAG_ACCESSOR(kAllowLazyParsing, allow_lazy_parsing, set_allow_lazy_parsing) FLAG_ACCESSOR(kIsNamedExpression, is_named_expression, set_is_named_expression) - FLAG_ACCESSOR(kSerializing, will_serialize, set_will_serialize) FLAG_ACCESSOR(kLazyCompile, lazy_compile, set_lazy_compile) FLAG_ACCESSOR(kCollectTypeProfile, collect_type_profile, set_collect_type_profile) FLAG_ACCESSOR(kIsAsmWasmBroken, is_asm_wasm_broken, set_asm_wasm_broken) + FLAG_ACCESSOR(kRequiresInstanceFieldsInitializer, + requires_instance_fields_initializer, + set_requires_instance_fields_initializer) FLAG_ACCESSOR(kBlockCoverageEnabled, block_coverage_enabled, set_block_coverage_enabled) + FLAG_ACCESSOR(kOnBackgroundThread, on_background_thread, + set_on_background_thread) #undef FLAG_ACCESSOR void set_parse_restriction(ParseRestriction restriction) { @@ -186,6 +192,8 @@ class V8_EXPORT_PRIVATE ParseInfo { void set_runtime_call_stats(RuntimeCallStats* runtime_call_stats) { runtime_call_stats_ = runtime_call_stats; } + Logger* logger() const { return logger_; } + void set_logger(Logger* logger) { logger_ = logger; } void AllocateSourceRangeMap(); SourceRangeMap* source_range_map() const { return source_range_map_; } @@ -193,6 +201,10 @@ class V8_EXPORT_PRIVATE ParseInfo { source_range_map_ = source_range_map; } + PendingCompilationErrorHandler* pending_error_handler() { + return &pending_error_handler_; + } + // Getters for individual compiler hints. bool is_declaration() const; FunctionKind function_kind() const; @@ -215,7 +227,7 @@ class V8_EXPORT_PRIVATE ParseInfo { return construct_language_mode(is_strict_mode()); } void set_language_mode(LanguageMode language_mode) { - STATIC_ASSERT(LANGUAGE_END == 2); + STATIC_ASSERT(LanguageModeSize == 2); set_strict_mode(is_strict(language_mode)); } @@ -229,7 +241,8 @@ class V8_EXPORT_PRIVATE ParseInfo { } } - void UpdateStatisticsAfterBackgroundParse(Isolate* isolate); + void EmitBackgroundParseStatisticsOnBackgroundThread(); + void UpdateBackgroundParseStatisticsOnMainThread(Isolate* isolate); private: // Various configuration flags for parsing. @@ -244,11 +257,12 @@ class V8_EXPORT_PRIVATE ParseInfo { kModule = 1 << 6, kAllowLazyParsing = 1 << 7, kIsNamedExpression = 1 << 8, - kSerializing = 1 << 9, - kLazyCompile = 1 << 10, - kCollectTypeProfile = 1 << 11, - kBlockCoverageEnabled = 1 << 12, - kIsAsmWasmBroken = 1 << 13, + kLazyCompile = 1 << 9, + kCollectTypeProfile = 1 << 10, + kBlockCoverageEnabled = 1 << 11, + kIsAsmWasmBroken = 1 << 12, + kRequiresInstanceFieldsInitializer = 1 << 13, + kOnBackgroundThread = 1 << 14, }; //------------- Inputs to parsing and scope analysis ----------------------- @@ -279,11 +293,13 @@ class V8_EXPORT_PRIVATE ParseInfo { const class AstStringConstants* ast_string_constants_; const AstRawString* function_name_; RuntimeCallStats* runtime_call_stats_; + Logger* logger_; SourceRangeMap* source_range_map_; // Used when block coverage is enabled. //----------- Output of parsing and scope analysis ------------------------ FunctionLiteral* literal_; std::shared_ptr<DeferredHandles> deferred_handles_; + PendingCompilationErrorHandler pending_error_handler_; void SetFlag(Flag f) { flags_ |= f; } void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; } diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index b211b85d2a..c393bc5ec2 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -14,6 +14,7 @@ #include "src/base/hashmap.h" #include "src/counters.h" #include "src/globals.h" +#include "src/log.h" #include "src/messages.h" #include "src/parsing/expression-classifier.h" #include "src/parsing/func-name-inferrer.h" @@ -236,6 +237,7 @@ class ParserBase { typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT; typedef typename Types::ClassLiteralProperty ClassLiteralPropertyT; typedef typename Types::Suspend SuspendExpressionT; + typedef typename Types::RewritableExpression RewritableExpressionT; typedef typename Types::ExpressionList ExpressionListT; typedef typename Types::FormalParameters FormalParametersT; typedef typename Types::Statement StatementT; @@ -251,8 +253,9 @@ class ParserBase { ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit, v8::Extension* extension, AstValueFactory* ast_value_factory, - RuntimeCallStats* runtime_call_stats, - bool parsing_on_main_thread = true) + PendingCompilationErrorHandler* pending_error_handler, + RuntimeCallStats* runtime_call_stats, Logger* logger, + int script_id, bool parsing_module, bool parsing_on_main_thread) : scope_(nullptr), original_scope_(nullptr), function_state_(nullptr), @@ -261,25 +264,24 @@ class ParserBase { ast_value_factory_(ast_value_factory), ast_node_factory_(ast_value_factory, zone), runtime_call_stats_(runtime_call_stats), + logger_(logger), parsing_on_main_thread_(parsing_on_main_thread), - parsing_module_(false), + parsing_module_(parsing_module), stack_limit_(stack_limit), + pending_error_handler_(pending_error_handler), zone_(zone), classifier_(nullptr), scanner_(scanner), - stack_overflow_(false), default_eager_compile_hint_(FunctionLiteral::kShouldLazyCompile), function_literal_id_(0), + script_id_(script_id), allow_natives_(false), allow_harmony_do_expressions_(false), allow_harmony_function_sent_(false), - allow_harmony_restrictive_generators_(false), - allow_harmony_class_fields_(false), - allow_harmony_object_rest_spread_(false), + allow_harmony_public_fields_(false), allow_harmony_dynamic_import_(false), allow_harmony_import_meta_(false), - allow_harmony_async_iteration_(false), - allow_harmony_template_escapes_(false) {} + allow_harmony_async_iteration_(false) {} #define ALLOW_ACCESSORS(name) \ bool allow_##name() const { return allow_##name##_; } \ @@ -288,16 +290,20 @@ class ParserBase { ALLOW_ACCESSORS(natives); ALLOW_ACCESSORS(harmony_do_expressions); ALLOW_ACCESSORS(harmony_function_sent); - ALLOW_ACCESSORS(harmony_restrictive_generators); - ALLOW_ACCESSORS(harmony_class_fields); - ALLOW_ACCESSORS(harmony_object_rest_spread); + ALLOW_ACCESSORS(harmony_public_fields); ALLOW_ACCESSORS(harmony_dynamic_import); ALLOW_ACCESSORS(harmony_import_meta); ALLOW_ACCESSORS(harmony_async_iteration); - ALLOW_ACCESSORS(harmony_template_escapes); #undef ALLOW_ACCESSORS + bool allow_harmony_bigint() const { + return scanner()->allow_harmony_bigint(); + } + void set_allow_harmony_bigint(bool allow) { + scanner()->set_allow_harmony_bigint(allow); + } + uintptr_t stack_limit() const { return stack_limit_; } void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } @@ -366,15 +372,6 @@ class ParserBase { Scope* const outer_scope_; }; - struct DestructuringAssignment { - public: - DestructuringAssignment(ExpressionT expression, Scope* scope) - : assignment(expression), scope(scope) {} - - ExpressionT assignment; - Scope* scope; - }; - class FunctionState final : public BlockState { public: FunctionState(FunctionState** function_state_stack, Scope** scope_stack, @@ -396,12 +393,12 @@ class ParserBase { void SetDestructuringAssignmentsScope(int pos, Scope* scope) { for (int i = pos; i < destructuring_assignments_to_rewrite_.length(); ++i) { - destructuring_assignments_to_rewrite_[i].scope = scope; + destructuring_assignments_to_rewrite_[i]->set_scope(scope); } } - const ZoneList<DestructuringAssignment>& - destructuring_assignments_to_rewrite() const { + const ZoneList<RewritableExpressionT>& + destructuring_assignments_to_rewrite() const { return destructuring_assignments_to_rewrite_; } @@ -409,7 +406,7 @@ class ParserBase { return &reported_errors_; } - ZoneList<ExpressionT>* non_patterns_to_rewrite() { + ZoneList<RewritableExpressionT>* non_patterns_to_rewrite() { return &non_patterns_to_rewrite_; } @@ -450,15 +447,16 @@ class ParserBase { }; private: - void AddDestructuringAssignment(DestructuringAssignment pair) { - destructuring_assignments_to_rewrite_.Add(pair, scope_->zone()); + void AddDestructuringAssignment(RewritableExpressionT expr) { + destructuring_assignments_to_rewrite_.Add(expr, scope_->zone()); } - void AddNonPatternForRewriting(ExpressionT expr, bool* ok) { + void AddNonPatternForRewriting(RewritableExpressionT expr, bool* ok) { non_patterns_to_rewrite_.Add(expr, scope_->zone()); if (non_patterns_to_rewrite_.length() >= - std::numeric_limits<uint16_t>::max()) + std::numeric_limits<uint16_t>::max()) { *ok = false; + } } // Properties count estimation. @@ -468,8 +466,8 @@ class ParserBase { FunctionState* outer_function_state_; DeclarationScope* scope_; - ZoneList<DestructuringAssignment> destructuring_assignments_to_rewrite_; - ZoneList<ExpressionT> non_patterns_to_rewrite_; + ZoneList<RewritableExpressionT> destructuring_assignments_to_rewrite_; + ZoneList<RewritableExpressionT> non_patterns_to_rewrite_; ZoneList<typename ExpressionClassifier::Error> reported_errors_; @@ -556,21 +554,43 @@ class ParserBase { : variable(nullptr), extends(parser->impl()->NullExpression()), properties(parser->impl()->NewClassPropertyList(4)), + static_fields(parser->impl()->NewClassPropertyList(4)), + instance_fields(parser->impl()->NewClassPropertyList(4)), constructor(parser->impl()->NullExpression()), has_seen_constructor(false), has_name_static_property(false), has_static_computed_names(false), - is_anonymous(false) {} + has_static_class_fields(false), + has_instance_class_fields(false), + is_anonymous(false), + static_fields_scope(nullptr), + instance_fields_scope(nullptr), + computed_field_count(0) {} Variable* variable; ExpressionT extends; typename Types::ClassPropertyList properties; + typename Types::ClassPropertyList static_fields; + typename Types::ClassPropertyList instance_fields; FunctionLiteralT constructor; + + // TODO(gsathya): Use a bitfield store all the booleans. bool has_seen_constructor; bool has_name_static_property; bool has_static_computed_names; + bool has_static_class_fields; + bool has_instance_class_fields; bool is_anonymous; + DeclarationScope* static_fields_scope; + DeclarationScope* instance_fields_scope; + int computed_field_count; }; + const AstRawString* ClassFieldVariableName(AstValueFactory* ast_value_factory, + int index) { + std::string name = ".class-field-" + std::to_string(index); + return ast_value_factory->GetOneByteString(name.c_str()); + } + DeclarationScope* NewScriptScope() const { return new (zone()) DeclarationScope(zone(), ast_value_factory()); } @@ -635,11 +655,15 @@ class ParserBase { AstValueFactory* ast_value_factory() const { return ast_value_factory_; } int position() const { return scanner_->location().beg_pos; } int peek_position() const { return scanner_->peek_location().beg_pos; } - bool stack_overflow() const { return stack_overflow_; } - void set_stack_overflow() { stack_overflow_ = true; } + bool stack_overflow() const { + return pending_error_handler()->stack_overflow(); + } + void set_stack_overflow() { pending_error_handler()->set_stack_overflow(); } + int script_id() { return script_id_; } + void set_script_id(int id) { script_id_ = id; } INLINE(Token::Value peek()) { - if (stack_overflow_) return Token::ILLEGAL; + if (stack_overflow()) return Token::ILLEGAL; return scanner()->peek(); } @@ -651,18 +675,18 @@ class ParserBase { } INLINE(Token::Value PeekAhead()) { - if (stack_overflow_) return Token::ILLEGAL; + if (stack_overflow()) return Token::ILLEGAL; return scanner()->PeekAhead(); } INLINE(Token::Value Next()) { - if (stack_overflow_) return Token::ILLEGAL; + if (stack_overflow()) return Token::ILLEGAL; { if (GetCurrentStackPosition() < stack_limit_) { // Any further calls to Next or peek will return the illegal token. // The current call must return the next token, which might already // have been peek'ed. - stack_overflow_ = true; + set_stack_overflow(); } } return scanner()->Next(); @@ -874,6 +898,13 @@ class ParserBase { return IsResumableFunction(function_state_->kind()); } + const PendingCompilationErrorHandler* pending_error_handler() const { + return pending_error_handler_; + } + PendingCompilationErrorHandler* pending_error_handler() { + return pending_error_handler_; + } + // Report syntax errors. void ReportMessage(MessageTemplate::Template message) { Scanner::Location source_location = scanner()->location(); @@ -1049,8 +1080,8 @@ class ParserBase { // This method wraps the parsing of the expression inside a new expression // classifier and calls RewriteNonPattern if parsing is successful. - // It should be used whenever we're parsing an expression that will be - // used as a non-pattern (i.e., in most cases). + // It should be used whenever we're parsing an expression that is known + // to not be a pattern or part of a pattern. V8_INLINE ExpressionT ParseExpression(bool accept_IN, bool* ok); // This method does not wrap the parsing of the expression inside a @@ -1081,11 +1112,12 @@ class ParserBase { bool* ok); ExpressionT ParseObjectLiteral(bool* ok); ClassLiteralPropertyT ParseClassPropertyDefinition( - ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name, - bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind, - bool* is_static, bool* has_name_static_property, bool* ok); - FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer, - bool* ok); + ClassLiteralChecker* checker, ClassInfo* class_info, bool has_extends, + bool* is_computed_name, bool* has_seen_constructor, + ClassLiteralProperty::Kind* property_kind, bool* is_static, + bool* has_name_static_property, bool* ok); + ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, bool is_static, + bool* ok); ObjectLiteralPropertyT ParseObjectPropertyDefinition( ObjectLiteralChecker* checker, bool* is_computed_name, bool* is_rest_property, bool* ok); @@ -1357,7 +1389,7 @@ class ParserBase { inline StatementT BuildReturnStatement(ExpressionT expr, int pos, int end_pos = kNoSourcePosition) { if (impl()->IsNull(expr)) { - expr = impl()->GetLiteralUndefined(kNoSourcePosition); + expr = factory()->NewUndefinedLiteral(kNoSourcePosition); } else if (is_async_generator()) { // In async generators, if there is an explicit operand to the return // statement, await the operand. @@ -1399,6 +1431,7 @@ class ParserBase { void CheckClassMethodName(Token::Value property, PropertyKind type, bool is_generator, bool is_async, bool is_static, bool* ok); + void CheckClassFieldName(bool is_static, bool* ok); private: bool IsConstructor() { @@ -1478,9 +1511,11 @@ class ParserBase { AstValueFactory* ast_value_factory_; // Not owned. typename Types::Factory ast_node_factory_; RuntimeCallStats* runtime_call_stats_; + internal::Logger* logger_; bool parsing_on_main_thread_; - bool parsing_module_; + const bool parsing_module_; uintptr_t stack_limit_; + PendingCompilationErrorHandler* pending_error_handler_; // Parser base's private field members. @@ -1489,22 +1524,19 @@ class ParserBase { ExpressionClassifier* classifier_; Scanner* scanner_; - bool stack_overflow_; FunctionLiteral::EagerCompileHint default_eager_compile_hint_; int function_literal_id_; + int script_id_; bool allow_natives_; bool allow_harmony_do_expressions_; bool allow_harmony_function_sent_; - bool allow_harmony_restrictive_generators_; - bool allow_harmony_class_fields_; - bool allow_harmony_object_rest_spread_; + bool allow_harmony_public_fields_; bool allow_harmony_dynamic_import_; bool allow_harmony_import_meta_; bool allow_harmony_async_iteration_; - bool allow_harmony_template_escapes_; friend class DiscardableZoneScope; }; @@ -1549,6 +1581,7 @@ void ParserBase<Impl>::GetUnexpectedTokenMessage( break; case Token::SMI: case Token::NUMBER: + case Token::BIGINT: *message = MessageTemplate::kUnexpectedTokenNumber; break; case Token::STRING: @@ -1590,7 +1623,7 @@ void ParserBase<Impl>::GetUnexpectedTokenMessage( break; default: const char* name = Token::String(token); - DCHECK(name != NULL); + DCHECK_NOT_NULL(name); *arg = name; break; } @@ -1780,6 +1813,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( case Token::FALSE_LITERAL: case Token::SMI: case Token::NUMBER: + case Token::BIGINT: BindingPatternUnexpectedToken(); return impl()->ExpressionFromLiteral(Next(), beg_pos); @@ -1881,7 +1915,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false, ok); case Token::MOD: - if (allow_natives() || extension_ != NULL) { + if (allow_natives() || extension_ != nullptr) { BindingPatternUnexpectedToken(); return ParseV8Intrinsic(ok); } @@ -1951,6 +1985,10 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) { if (impl()->IsNull(result)) { // First time through the loop. result = right; + } else if (impl()->CollapseNaryExpression(&result, right, Token::COMMA, + comma_pos, + SourceRange::Empty())) { + // Do nothing, "result" is already updated. } else { result = factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos); @@ -1992,7 +2030,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( while (peek() != Token::RBRACK) { ExpressionT elem; if (peek() == Token::COMMA) { - elem = impl()->GetLiteralTheHole(peek_position()); + elem = factory()->NewTheHoleLiteral(); } else if (peek() == Token::ELLIPSIS) { int start_pos = peek_position(); Consume(Token::ELLIPSIS); @@ -2033,8 +2071,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( ExpressionT result = factory()->NewArrayLiteral(values, first_spread_index, pos); if (first_spread_index >= 0) { - result = factory()->NewRewritableExpression(result); - impl()->QueueNonPatternForRewriting(result, ok); + auto rewritable = factory()->NewRewritableExpression(result, scope()); + impl()->QueueNonPatternForRewriting(rewritable, ok); if (!*ok) { // If the non-pattern rewriting mechanism is used in the future for // rewriting other things than spreads, this error message will have @@ -2043,6 +2081,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral( ReportMessage(MessageTemplate::kTooManySpreads); return impl()->NullExpression(); } + result = rewritable; } return result; } @@ -2079,7 +2118,7 @@ template <class Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( IdentifierT* name, PropertyKind* kind, bool* is_generator, bool* is_get, bool* is_set, bool* is_async, bool* is_computed_name, bool* ok) { - DCHECK(*kind == PropertyKind::kNotSet); + DCHECK_EQ(*kind, PropertyKind::kNotSet); DCHECK(!*is_generator); DCHECK(!*is_get); DCHECK(!*is_set); @@ -2166,8 +2205,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( } case Token::ELLIPSIS: - if (allow_harmony_object_rest_spread() && !*is_generator && !*is_async && - !*is_get && !*is_set) { + if (!*is_generator && !*is_async && !*is_get && !*is_set) { *name = impl()->NullIdentifier(); Consume(Token::ELLIPSIS); expression = ParseAssignmentExpression(true, CHECK_OK); @@ -2217,9 +2255,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( template <typename Impl> typename ParserBase<Impl>::ClassLiteralPropertyT ParserBase<Impl>::ParseClassPropertyDefinition( - ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name, - bool* has_seen_constructor, ClassLiteralProperty::Kind* property_kind, - bool* is_static, bool* has_name_static_property, bool* ok) { + ClassLiteralChecker* checker, ClassInfo* class_info, bool has_extends, + bool* is_computed_name, bool* has_seen_constructor, + ClassLiteralProperty::Kind* property_kind, bool* is_static, + bool* has_name_static_property, bool* ok) { DCHECK_NOT_NULL(has_seen_constructor); DCHECK_NOT_NULL(has_name_static_property); bool is_get = false; @@ -2273,14 +2312,17 @@ ParserBase<Impl>::ParseClassPropertyDefinition( // as an uninitialized field. case PropertyKind::kShorthandProperty: case PropertyKind::kValueProperty: - if (allow_harmony_class_fields()) { - bool has_initializer = Check(Token::ASSIGN); - ExpressionT function_literal = ParseClassFieldForInitializer( - has_initializer, CHECK_OK_CUSTOM(NullLiteralProperty)); - ExpectSemicolon(CHECK_OK_CUSTOM(NullLiteralProperty)); + if (allow_harmony_public_fields()) { *property_kind = ClassLiteralProperty::FIELD; + if (!*is_computed_name) { + checker->CheckClassFieldName(*is_static, + CHECK_OK_CUSTOM(NullLiteralProperty)); + } + ExpressionT initializer = ParseClassFieldInitializer( + class_info, *is_static, CHECK_OK_CUSTOM(NullLiteralProperty)); + ExpectSemicolon(CHECK_OK_CUSTOM(NullLiteralProperty)); ClassLiteralPropertyT result = factory()->NewClassLiteralProperty( - name_expression, function_literal, *property_kind, *is_static, + name_expression, initializer, *property_kind, *is_static, *is_computed_name); impl()->SetFunctionNameFromPropertyName(result, name); return result; @@ -2377,36 +2419,43 @@ ParserBase<Impl>::ParseClassPropertyDefinition( } template <typename Impl> -typename ParserBase<Impl>::FunctionLiteralT -ParserBase<Impl>::ParseClassFieldForInitializer(bool has_initializer, - bool* ok) { - // Makes a concise method which evaluates and returns the initialized value - // (or undefined if absent). - FunctionKind kind = FunctionKind::kConciseMethod; - DeclarationScope* initializer_scope = NewFunctionScope(kind); - initializer_scope->set_start_position(scanner()->location().end_pos); - FunctionState initializer_state(&function_state_, &scope_, initializer_scope); - DCHECK_EQ(initializer_scope, scope()); - scope()->SetLanguageMode(STRICT); - ExpressionClassifier expression_classifier(this); - ExpressionT value; - if (has_initializer) { - value = - this->ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression)); +typename ParserBase<Impl>::ExpressionT +ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, + bool is_static, bool* ok) { + DeclarationScope* initializer_scope = is_static + ? class_info->static_fields_scope + : class_info->instance_fields_scope; + + if (initializer_scope == nullptr) { + initializer_scope = NewFunctionScope(FunctionKind::kConciseMethod); + // TODO(gsathya): Make scopes be non contiguous. + initializer_scope->set_start_position(scanner()->location().end_pos); + initializer_scope->SetLanguageMode(LanguageMode::kStrict); + } + + ExpressionT initializer; + if (Check(Token::ASSIGN)) { + FunctionState initializer_state(&function_state_, &scope_, + initializer_scope); + ExpressionClassifier expression_classifier(this); + + initializer = + ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpression)); impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpression)); } else { - value = factory()->NewUndefinedLiteral(kNoSourcePosition); + initializer = factory()->NewUndefinedLiteral(kNoSourcePosition); } + initializer_scope->set_end_position(scanner()->location().end_pos); - typename Types::StatementList body = impl()->NewStatementList(1); - body->Add(factory()->NewReturnStatement(value, kNoSourcePosition), zone()); - FunctionLiteralT function_literal = factory()->NewFunctionLiteral( - impl()->EmptyIdentifierString(), initializer_scope, body, - initializer_state.expected_property_count(), 0, 0, - FunctionLiteral::kNoDuplicateParameters, - FunctionLiteral::kAnonymousExpression, default_eager_compile_hint_, - initializer_scope->start_position(), true, GetNextFunctionLiteralId()); - return function_literal; + if (is_static) { + class_info->static_fields_scope = initializer_scope; + class_info->has_static_class_fields = true; + } else { + class_info->instance_fields_scope = initializer_scope; + class_info->has_instance_class_fields = true; + } + + return initializer; } template <typename Impl> @@ -2432,7 +2481,6 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, switch (kind) { case PropertyKind::kSpreadProperty: - DCHECK(allow_harmony_object_rest_spread()); DCHECK(!is_get && !is_set && !is_generator && !is_async && !*is_computed_name); DCHECK(name_token == Token::ELLIPSIS); @@ -2441,7 +2489,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker, *is_rest_property = true; return factory()->NewObjectLiteralProperty( - impl()->GetLiteralTheHole(kNoSourcePosition), name_expression, + factory()->NewTheHoleLiteral(), name_expression, ObjectLiteralProperty::SPREAD, true); case PropertyKind::kValueProperty: { @@ -2910,7 +2958,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { impl()->CheckAssigningFunctionLiteralToProperty(expression, right); - if (fni_ != NULL) { + if (fni_ != nullptr) { // Check if the right hand side is a call to avoid inferring a // name if we're dealing with "a = function(){...}();"-like // expression. @@ -2925,17 +2973,14 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { impl()->SetFunctionNameFromIdentifierRef(right, expression); } - if (op == Token::ASSIGN_EXP) { - DCHECK(!is_destructuring_assignment); - return impl()->RewriteAssignExponentiation(expression, right, pos); - } - DCHECK_NE(op, Token::INIT); ExpressionT result = factory()->NewAssignment(op, expression, right, pos); if (is_destructuring_assignment) { - result = factory()->NewRewritableExpression(result); - impl()->QueueDestructuringAssignmentForRewriting(result); + DCHECK_NE(op, Token::ASSIGN_EXP); + auto rewritable = factory()->NewRewritableExpression(result, scope()); + impl()->QueueDestructuringAssignmentForRewriting(rewritable); + result = rewritable; } return result; @@ -3010,11 +3055,11 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, impl()->RewriteNonPattern(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); - Consume(Token::CONDITIONAL); ExpressionT left; { SourceRangeScope range_scope(scanner(), &then_range); + Consume(Token::CONDITIONAL); ExpressionClassifier classifier(this); // In parsing the first assignment expression in conditional // expressions we always accept the 'in' keyword; see ECMA-262, @@ -3023,10 +3068,10 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, AccumulateNonBindingPatternErrors(); } impl()->RewriteNonPattern(CHECK_OK); - Expect(Token::COLON, CHECK_OK); ExpressionT right; { SourceRangeScope range_scope(scanner(), &else_range); + Expect(Token::COLON, CHECK_OK); ExpressionClassifier classifier(this); right = ParseAssignmentExpression(accept_IN, CHECK_OK); AccumulateNonBindingPatternErrors(); @@ -3042,7 +3087,8 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN, template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( int prec, bool accept_IN, bool* ok) { - DCHECK(prec >= 4); + DCHECK_GE(prec, 4); + SourceRange right_range; ExpressionT x = ParseUnaryExpression(CHECK_OK); for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { // prec1 >= 4 @@ -3050,12 +3096,15 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( impl()->RewriteNonPattern(CHECK_OK); BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); + + SourceRangeScope right_range_scope(scanner(), &right_range); Token::Value op = Next(); int pos = position(); const bool is_right_associative = op == Token::EXP; const int next_prec = is_right_associative ? prec1 : prec1 + 1; ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK); + right_range_scope.Finalize(); impl()->RewriteNonPattern(CHECK_OK); if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) { @@ -3078,11 +3127,14 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( // The comparison was negated - add a NOT. x = factory()->NewUnaryOperation(Token::NOT, x, pos); } - } else if (op == Token::EXP) { - x = impl()->RewriteExponentiation(x, y, pos); + } else if (impl()->CollapseNaryExpression(&x, y, op, pos, right_range)) { + continue; } else { // We have a "normal" binary operation. x = factory()->NewBinaryOperation(op, x, y, pos); + if (op == Token::OR || op == Token::AND) { + impl()->RecordBinaryOperationSourceRange(x, right_range); + } } } } @@ -3316,7 +3368,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { factory()->NewAssignment(Token::INIT, this_expr, result, pos); } - if (fni_ != NULL) fni_->RemoveLastFunction(); + if (fni_ != nullptr) fni_->RemoveLastFunction(); break; } @@ -3518,9 +3570,15 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseImportExpressions( return impl()->NullExpression(); } - return impl()->ExpressionFromLiteral(Token::NULL_LITERAL, pos); + return impl()->ImportMetaExpression(pos); } Expect(Token::LPAREN, CHECK_OK); + if (peek() == Token::RPAREN) { + impl()->ReportMessageAt(scanner()->location(), + MessageTemplate::kImportMissingSpecifier); + *ok = false; + return impl()->NullExpression(); + } ExpressionT arg = ParseAssignmentExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); return factory()->NewImportCallExpression(arg, pos); @@ -3666,6 +3724,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters, // BindingElement[?Yield, ?GeneratorParameter] bool is_rest = parameters->has_rest; + FuncNameInferrer::State fni_state(fni_); ExpressionT pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(Void)); ValidateBindingPattern(CHECK_OK_CUSTOM(Void)); @@ -3775,12 +3834,12 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( break; case Token::CONST: Consume(Token::CONST); - DCHECK(var_context != kStatement); + DCHECK_NE(var_context, kStatement); parsing_result->descriptor.mode = CONST; break; case Token::LET: Consume(Token::LET); - DCHECK(var_context != kStatement); + DCHECK_NE(var_context, kStatement); parsing_result->descriptor.mode = LET; break; default: @@ -3857,7 +3916,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations( } // 'let x' initializes 'x' to undefined. if (parsing_result->descriptor.mode == LET) { - value = impl()->GetLiteralUndefined(position()); + value = factory()->NewUndefinedLiteral(position()); } } @@ -3979,9 +4038,9 @@ ParserBase<Impl>::ParseHoistableDeclaration( // sloppy_block_function_map. Don't add them to the map for async functions. // Generators are also supposed to be prohibited; currently doing this behind // a flag and UseCounting violations to assess web compatibility. - bool is_sloppy_block_function = - is_sloppy(language_mode()) && !scope()->is_declaration_scope() && - !is_async && !(allow_harmony_restrictive_generators() && is_generator); + bool is_sloppy_block_function = is_sloppy(language_mode()) && + !scope()->is_declaration_scope() && + !is_async && !is_generator; return impl()->DeclareFunction(variable_name, function, mode, pos, is_sloppy_block_function, names, ok); @@ -4078,18 +4137,6 @@ void ParserBase<Impl>::ParseFunctionBody( typename ParserBase<Impl>::StatementListT result, IdentifierT function_name, int pos, const FormalParametersT& parameters, FunctionKind kind, FunctionLiteral::FunctionType function_type, bool* ok) { - static const int kFunctionNameAssignmentIndex = 0; - if (function_type == FunctionLiteral::kNamedExpression) { - DCHECK(!impl()->IsNull(function_name)); - // If we have a named function expression, we add a local variable - // declaration to the body of the function with the name of the - // function and let it refer to the function itself (closure). - // Not having parsed the function body, the language mode may still change, - // so we reserve a spot and create the actual const assignment later. - DCHECK_EQ(kFunctionNameAssignmentIndex, result->length()); - result->Add(impl()->NullStatement(), zone()); - } - DeclarationScope* function_scope = scope()->AsDeclarationScope(); DeclarationScope* inner_scope = function_scope; BlockT inner_block = impl()->NullStatement(); @@ -4170,9 +4217,7 @@ void ParserBase<Impl>::ParseFunctionBody( function_scope->DeclareArguments(ast_value_factory()); } - impl()->CreateFunctionNameAssignment(function_name, pos, function_type, - function_scope, result, - kFunctionNameAssignmentIndex); + impl()->DeclareFunctionNameVar(function_name, function_type, function_scope); } template <typename Impl> @@ -4233,9 +4278,10 @@ template <typename Impl> bool ParserBase<Impl>::IsTrivialExpression() { Token::Value peek_token = peek(); if (peek_token == Token::SMI || peek_token == Token::NUMBER || - peek_token == Token::NULL_LITERAL || peek_token == Token::TRUE_LITERAL || - peek_token == Token::FALSE_LITERAL || peek_token == Token::STRING || - peek_token == Token::IDENTIFIER || peek_token == Token::THIS) { + peek_token == Token::BIGINT || peek_token == Token::NULL_LITERAL || + peek_token == Token::TRUE_LITERAL || peek_token == Token::FALSE_LITERAL || + peek_token == Token::STRING || peek_token == Token::IDENTIFIER || + peek_token == Token::THIS) { // PeekAhead() is expensive & may not always be called, so we only call it // after checking peek(). Token::Value peek_ahead = PeekAhead(); @@ -4260,6 +4306,8 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( RuntimeCallTimerScope runtime_timer( runtime_call_stats_, counters[Impl::IsPreParser()][parsing_on_main_thread_]); + base::ElapsedTimer timer; + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) { // ASI inserts `;` after arrow parameters if a line terminator is found. @@ -4302,7 +4350,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( // For arrow functions, we don't need to retrieve data about function // parameters. int dummy_num_parameters = -1; - DCHECK((kind & FunctionKind::kArrowFunction) != 0); + DCHECK_NE(kind & FunctionKind::kArrowFunction, 0); LazyParsingResult result = impl()->SkipFunction( nullptr, kind, FunctionLiteral::kAnonymousExpression, formal_parameters.scope, &dummy_num_parameters, @@ -4313,6 +4361,13 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( formal_parameters.scope->ResetAfterPreparsing(ast_value_factory_, false); + // Discard any queued destructuring assignments which appeared + // in this function's parameter list. + FunctionState* parent_state = function_state.outer(); + DCHECK_NOT_NULL(parent_state); + DCHECK_GE(parent_state->destructuring_assignments_to_rewrite().length(), + rewritable_length); + parent_state->RewindDestructuringAssignments(rewritable_length); } else { Consume(Token::LBRACE); body = impl()->NewStatementList(8); @@ -4349,23 +4404,9 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( } impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); - if (is_lazy_top_level_function) { - FunctionState* parent_state = function_state.outer(); - DCHECK_NOT_NULL(parent_state); - DCHECK_GE(parent_state->destructuring_assignments_to_rewrite().length(), - rewritable_length); - parent_state->RewindDestructuringAssignments(rewritable_length); - } - impl()->RewriteDestructuringAssignments(); } - if (FLAG_trace_preparse) { - Scope* scope = formal_parameters.scope; - PrintF(" [%s]: %i-%i (arrow function)\n", - is_lazy_top_level_function ? "Preparse no-resolution" : "Full parse", - scope->start_position(), scope->end_position()); - } FunctionLiteralT function_literal = factory()->NewFunctionLiteral( impl()->EmptyIdentifierString(), formal_parameters.scope, body, expected_property_count, formal_parameters.num_parameters(), @@ -4380,6 +4421,17 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( impl()->AddFunctionForNameInference(function_literal); + if (V8_UNLIKELY((FLAG_log_function_events))) { + Scope* scope = formal_parameters.scope; + double ms = timer.Elapsed().InMillisecondsF(); + const char* event_name = + is_lazy_top_level_function ? "preparse-no-resolution" : "parse"; + const char* name = "arrow function"; + logger_->FunctionEvent(event_name, nullptr, script_id(), ms, + scope->start_position(), scope->end_position(), name, + strlen(name)); + } + return function_literal; } @@ -4407,7 +4459,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( Scope* block_scope = NewScope(BLOCK_SCOPE); BlockState block_state(&scope_, block_scope); - RaiseLanguageMode(STRICT); + RaiseLanguageMode(LanguageMode::kStrict); ClassInfo class_info(this); class_info.is_anonymous = is_anonymous; @@ -4438,19 +4490,23 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( // property. bool is_constructor = !class_info.has_seen_constructor; ClassLiteralPropertyT property = ParseClassPropertyDefinition( - &checker, has_extends, &is_computed_name, + &checker, &class_info, has_extends, &is_computed_name, &class_info.has_seen_constructor, &property_kind, &is_static, &class_info.has_name_static_property, CHECK_OK); if (!class_info.has_static_computed_names && is_static && is_computed_name) { class_info.has_static_computed_names = true; } + if (is_computed_name && property_kind == ClassLiteralProperty::FIELD) { + class_info.computed_field_count++; + } is_constructor &= class_info.has_seen_constructor; impl()->RewriteNonPattern(CHECK_OK); AccumulateFormalParameterContainmentErrors(); impl()->DeclareClassProperty(name, property, property_kind, is_static, - is_constructor, &class_info, CHECK_OK); + is_constructor, is_computed_name, &class_info, + CHECK_OK); impl()->InferFunctionName(); } @@ -4550,9 +4606,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( // // When parsing a TemplateLiteral, we must have scanned either an initial // TEMPLATE_SPAN, or a TEMPLATE_TAIL. - CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL); + DCHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL); - bool forbid_illegal_escapes = !allow_harmony_template_escapes() || !tagged; + bool forbid_illegal_escapes = !tagged; // If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate. // In this case we may simply consume the token and build a template with a @@ -4656,7 +4712,7 @@ ParserBase<Impl>::CheckAndRewriteReferenceExpression( if (expression->IsValidReferenceExpression()) { return expression; } - if (expression->IsCall()) { + if (expression->IsCall() && !expression->AsCall()->is_tagged_template()) { // If it is a call, make it a runtime error for legacy web compatibility. // Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480 // Rewrite `expr' to `expr[throw ReferenceError]'. @@ -4763,7 +4819,7 @@ ParserBase<Impl>::ParseStatementList(StatementListT body, int end_token, if (impl()->IsUseStrictDirective(stat) && token_loc.end_pos - token_loc.beg_pos == sizeof("use strict") + 1) { // Directive "use strict" (ES5 14.1). - RaiseLanguageMode(STRICT); + RaiseLanguageMode(LanguageMode::kStrict); if (!scope()->HasSimpleParameters()) { // TC39 deemed "use strict" directives to be an error when occurring // in the body of a function with non-simple parameter list, on @@ -4783,14 +4839,14 @@ ParserBase<Impl>::ParseStatementList(StatementListT body, int end_token, // Possibly an unknown directive. // Should not change mode, but will increment usage counters // as appropriate. Ditto usages below. - RaiseLanguageMode(SLOPPY); + RaiseLanguageMode(LanguageMode::kSloppy); } else { // End of the directive prologue. directive_prologue = false; - RaiseLanguageMode(SLOPPY); + RaiseLanguageMode(LanguageMode::kSloppy); } } else { - RaiseLanguageMode(SLOPPY); + RaiseLanguageMode(LanguageMode::kSloppy); } // If we're allowed to abort, we will do so when we see a "long and @@ -5121,7 +5177,7 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( ExpectSemicolon(CHECK_OK); if (labels != nullptr) { // TODO(adamk): Also measure in the PreParser by passing something - // non-NULL as |labels|. + // non-null as |labels|. impl()->CountUsage(v8::Isolate::kLabeledExpressionStatement); } return factory()->NewExpressionStatement(expr, pos); @@ -5758,7 +5814,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) { // Initializer is reference followed by in/of. if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { - expression = impl()->CheckAndRewriteReferenceExpression( + expression = CheckAndRewriteReferenceExpression( expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); } @@ -5959,7 +6015,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( ValidateAssignmentPattern(CHECK_OK); } else { impl()->RewriteNonPattern(CHECK_OK); - each_variable = impl()->CheckAndRewriteReferenceExpression( + each_variable = CheckAndRewriteReferenceExpression( lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK); } @@ -6081,6 +6137,22 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName( } } +template <typename Impl> +void ParserBase<Impl>::ClassLiteralChecker::CheckClassFieldName(bool is_static, + bool* ok) { + if (is_static && IsPrototype()) { + this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); + *ok = false; + return; + } + + if (IsConstructor()) { + this->parser()->ReportMessage(MessageTemplate::kConstructorClassField); + *ok = false; + return; + } +} + #undef CHECK_OK #undef CHECK_OK_CUSTOM #undef CHECK_OK_VOID diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index a554d7d242..4d291a741e 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -8,7 +8,6 @@ #include <memory> #include "src/api.h" -#include "src/ast/ast-expression-rewriter.h" #include "src/ast/ast-function-literal-id-reindexer.h" #include "src/ast/ast-traversal-visitor.h" #include "src/ast/ast.h" @@ -16,6 +15,7 @@ #include "src/base/platform/platform.h" #include "src/char-predicates-inl.h" #include "src/compiler-dispatcher/compiler-dispatcher.h" +#include "src/log.h" #include "src/messages.h" #include "src/objects-inl.h" #include "src/parsing/duplicate-finder.h" @@ -173,11 +173,11 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, FunctionKind kind = call_super ? FunctionKind::kDefaultDerivedConstructor : FunctionKind::kDefaultBaseConstructor; DeclarationScope* function_scope = NewFunctionScope(kind); - SetLanguageMode(function_scope, STRICT); + SetLanguageMode(function_scope, LanguageMode::kStrict); // Set start and end position to the same value function_scope->set_start_position(pos); function_scope->set_end_position(pos); - ZoneList<Statement*>* body = NULL; + ZoneList<Statement*>* body = nullptr; { FunctionState function_state(&function_state_, &scope_, function_scope); @@ -212,7 +212,6 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, parameter_count, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, true, GetNextFunctionLiteralId()); - return function_literal; } @@ -245,10 +244,9 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y, Token::Value op, int pos) { - if ((*x)->AsLiteral() && (*x)->AsLiteral()->raw_value()->IsNumber() && - y->AsLiteral() && y->AsLiteral()->raw_value()->IsNumber()) { - double x_val = (*x)->AsLiteral()->raw_value()->AsNumber(); - double y_val = y->AsLiteral()->raw_value()->AsNumber(); + if ((*x)->IsNumberLiteral() && y->IsNumberLiteral()) { + double x_val = (*x)->AsLiteral()->AsNumber(); + double y_val = y->AsLiteral()->AsNumber(); switch (op) { case Token::ADD: *x = factory()->NewNumberLiteral(x_val + y_val, pos); @@ -308,16 +306,48 @@ bool Parser::ShortcutNumericLiteralBinaryExpression(Expression** x, return false; } +bool Parser::CollapseNaryExpression(Expression** x, Expression* y, + Token::Value op, int pos, + const SourceRange& range) { + // Filter out unsupported ops. + if (!Token::IsBinaryOp(op) || op == Token::EXP) return false; + + // Convert *x into an nary operation with the given op, returning false if + // this is not possible. + NaryOperation* nary = nullptr; + if ((*x)->IsBinaryOperation()) { + BinaryOperation* binop = (*x)->AsBinaryOperation(); + if (binop->op() != op) return false; + + nary = factory()->NewNaryOperation(op, binop->left(), 2); + nary->AddSubsequent(binop->right(), binop->position()); + ConvertBinaryToNaryOperationSourceRange(binop, nary); + *x = nary; + } else if ((*x)->IsNaryOperation()) { + nary = (*x)->AsNaryOperation(); + if (nary->op() != op) return false; + } else { + return false; + } + + // Append our current expression to the nary operation. + // TODO(leszeks): Do some literal collapsing here if we're appending Smi or + // String literals. + nary->AddSubsequent(y, pos); + AppendNaryOperationSourceRange(nary, range); + + return true; +} + Expression* Parser::BuildUnaryExpression(Expression* expression, Token::Value op, int pos) { - DCHECK(expression != NULL); - if (expression->IsLiteral()) { - const AstValue* literal = expression->AsLiteral()->raw_value(); + DCHECK_NOT_NULL(expression); + const Literal* literal = expression->AsLiteral(); + if (literal != nullptr) { if (op == Token::NOT) { // Convert the literal to a boolean condition and negate it. - bool condition = literal->BooleanValue(); - return factory()->NewBooleanLiteral(!condition, pos); - } else if (literal->IsNumber()) { + return factory()->NewBooleanLiteral(literal->ToBooleanIsFalse(), pos); + } else if (literal->IsNumberLiteral()) { // Compute some expressions involving only number literals. double value = literal->AsNumber(); switch (op) { @@ -383,6 +413,12 @@ Expression* Parser::FunctionSentExpression(int pos) { args, pos); } +Expression* Parser::ImportMetaExpression(int pos) { + return factory()->NewCallRuntime( + Runtime::kInlineGetImportMetaObject, + new (zone()) ZoneList<Expression*>(0, zone()), pos); +} + Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { switch (token) { case Token::NULL_LITERAL: @@ -399,10 +435,13 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) { double value = scanner()->DoubleValue(); return factory()->NewNumberLiteral(value, pos); } + case Token::BIGINT: + return factory()->NewBigIntLiteral( + AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos); default: DCHECK(false); } - return NULL; + return nullptr; } Expression* Parser::NewV8Intrinsic(const AstRawString* name, @@ -463,7 +502,10 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name, Parser::Parser(ParseInfo* info) : ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(), info->extension(), info->GetOrCreateAstValueFactory(), - info->runtime_call_stats(), true), + info->pending_error_handler(), + info->runtime_call_stats(), info->logger(), + info->script().is_null() ? -1 : info->script()->id(), + info->is_module(), true), scanner_(info->unicode_cache(), use_counts_), reusable_preparser_(nullptr), mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. @@ -479,7 +521,7 @@ Parser::Parser(ParseInfo* info) // Even though we were passed ParseInfo, we should not store it in // Parser - this makes sure that Isolate is not accidentally accessed via // ParseInfo during background parsing. - DCHECK(info->character_stream() != nullptr); + DCHECK_NOT_NULL(info->character_stream()); // Determine if functions can be lazily compiled. This is necessary to // allow some of our builtin JS files to be lazily compiled. These // builtins cannot be handled lazily by the parser, since we have to know @@ -500,13 +542,11 @@ Parser::Parser(ParseInfo* info) set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); set_allow_harmony_do_expressions(FLAG_harmony_do_expressions); set_allow_harmony_function_sent(FLAG_harmony_function_sent); - set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators); - set_allow_harmony_class_fields(FLAG_harmony_class_fields); - set_allow_harmony_object_rest_spread(FLAG_harmony_object_rest_spread); + set_allow_harmony_public_fields(FLAG_harmony_public_fields); set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import); set_allow_harmony_import_meta(FLAG_harmony_import_meta); set_allow_harmony_async_iteration(FLAG_harmony_async_iteration); - set_allow_harmony_template_escapes(FLAG_harmony_template_escapes); + set_allow_harmony_bigint(FLAG_harmony_bigint); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; @@ -527,7 +567,6 @@ void Parser::DeserializeScopeChain( scope = Scope::DeserializeScopeChain( zone(), *outer_scope_info, script_scope, ast_value_factory(), Scope::DeserializationMode::kScopesOnly); - DCHECK(!info->is_module() || scope->is_module_scope()); } original_scope_ = scope; } @@ -557,9 +596,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { : &RuntimeCallStats::ParseProgram); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseProgram"); base::ElapsedTimer timer; - if (FLAG_trace_parse) { - timer.Start(); - } + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); // Initialize parser state. @@ -583,23 +620,25 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { HandleSourceURLComments(isolate, info->script()); - if (FLAG_trace_parse && result != nullptr) { - double ms = timer.Elapsed().InMillisecondsF(); - if (info->is_eval()) { - PrintF("[parsing eval"); - } else if (info->script()->name()->IsString()) { - String* name = String::cast(info->script()->name()); - std::unique_ptr<char[]> name_chars = name->ToCString(); - PrintF("[parsing script: %s", name_chars.get()); - } else { - PrintF("[parsing script"); - } - PrintF(" - took %0.3f ms]\n", ms); - } if (produce_cached_parse_data() && result != nullptr) { *info->cached_data() = logger.GetScriptData(); } log_ = nullptr; + + if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) { + double ms = timer.Elapsed().InMillisecondsF(); + const char* event_name = "parse-eval"; + Script* script = *info->script(); + int start = -1; + int end = -1; + if (!info->is_eval()) { + event_name = "parse-script"; + start = 0; + end = String::cast(script->source())->length(); + } + LOG(script->GetIsolate(), + FunctionEvent(event_name, script, -1, ms, start, end, "", 0)); + } return result; } @@ -616,11 +655,10 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { DCHECK(info->function_literal_id() == FunctionLiteral::kIdTypeTopLevel || info->function_literal_id() == FunctionLiteral::kIdTypeInvalid); - FunctionLiteral* result = NULL; + FunctionLiteral* result = nullptr; { Scope* outer = original_scope_; DCHECK_NOT_NULL(outer); - parsing_module_ = info->is_module(); if (info->is_eval()) { outer = NewEvalScope(outer); } else if (parsing_module_) { @@ -638,6 +676,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { bool ok = true; int beg_pos = scanner()->location().beg_pos; if (parsing_module_) { + DCHECK(info->is_module()); // Declare the special module parameter. auto name = ast_value_factory()->empty_string(); bool is_duplicate = false; @@ -658,9 +697,8 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { zone()); ParseModuleItemList(body, &ok); - ok = ok && - module()->Validate(this->scope()->AsModuleScope(), - &pending_error_handler_, zone()); + ok = ok && module()->Validate(this->scope()->AsModuleScope(), + pending_error_handler(), zone()); } else { // Don't count the mode in the use counters--give the program a chance // to enable script-wide strict mode below. @@ -708,7 +746,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) { info->set_max_function_literal_id(GetLastFunctionLiteralId()); // Make sure the target stack is empty. - DCHECK(target_stack_ == NULL); + DCHECK_NULL(target_stack_); return result; } @@ -722,9 +760,8 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, &RuntimeCallStats::ParseFunction); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseFunction"); base::ElapsedTimer timer; - if (FLAG_trace_parse) { - timer.Start(); - } + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); + DeserializeScopeChain(info, info->maybe_outer_scope_info()); DCHECK_EQ(factory()->zone(), info->zone()); @@ -740,12 +777,18 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, result->set_inferred_name(inferred_name); } - if (FLAG_trace_parse && result != NULL) { + if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) { double ms = timer.Elapsed().InMillisecondsF(); // We need to make sure that the debug-name is available. ast_value_factory()->Internalize(isolate); - std::unique_ptr<char[]> name_chars = result->debug_name()->ToCString(); - PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms); + DeclarationScope* function_scope = result->scope(); + Script* script = *info->script(); + std::unique_ptr<char[]> function_name = result->GetDebugName(); + LOG(script->GetIsolate(), + FunctionEvent("parse-function", script, -1, ms, + function_scope->start_position(), + function_scope->end_position(), function_name.get(), + strlen(function_name.get()))); } return result; } @@ -888,6 +931,11 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind, kNoSourcePosition, function_type, info->language_mode(), &ok); } + + if (ok) { + result->set_requires_instance_fields_initializer( + info->requires_instance_fields_initializer()); + } // Make sure the results agree. DCHECK(ok == (result != nullptr)); } @@ -979,11 +1027,12 @@ void Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, // Keep track of the first reserved word encountered in case our // caller needs to report an error. if (!reserved_loc->IsValid() && - !Token::IsIdentifier(name_tok, STRICT, false, parsing_module_)) { + !Token::IsIdentifier(name_tok, LanguageMode::kStrict, false, + parsing_module_)) { *reserved_loc = scanner()->location(); } const AstRawString* local_name = ParseIdentifierName(CHECK_OK_VOID); - const AstRawString* export_name = NULL; + const AstRawString* export_name = nullptr; Scanner::Location location = scanner()->location(); if (CheckContextualKeyword(Token::AS)) { export_name = ParseIdentifierName(CHECK_OK_VOID); @@ -991,7 +1040,7 @@ void Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, // both for errors due to "a" and for errors due to "b". location.end_pos = scanner()->location().end_pos; } - if (export_name == NULL) { + if (export_name == nullptr) { export_name = local_name; } export_names->Add(export_name, zone()); @@ -1033,8 +1082,8 @@ ZoneList<const Parser::NamedImport*>* Parser::ParseNamedImports( if (CheckContextualKeyword(Token::AS)) { local_name = ParseIdentifierName(CHECK_OK); } - if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false, - parsing_module_)) { + if (!Token::IsIdentifier(scanner()->current_token(), LanguageMode::kStrict, + false, parsing_module_)) { *ok = false; ReportMessage(MessageTemplate::kUnexpectedReserved); return nullptr; @@ -1393,8 +1442,8 @@ Variable* Parser::Declare(Declaration* declaration, } bool sloppy_mode_block_scope_function_redefinition = false; Variable* variable = scope->DeclareVariable( - declaration, mode, init, allow_harmony_restrictive_generators(), - &sloppy_mode_block_scope_function_redefinition, ok); + declaration, mode, init, &sloppy_mode_block_scope_function_redefinition, + ok); if (!*ok) { // If we only have the start position of a proxy, we can't highlight the // whole variable name. Pretend its length is 1 so that we highlight at @@ -1778,25 +1827,13 @@ void Parser::ParseAndRewriteAsyncGeneratorFunctionBody( zone()); } -void Parser::CreateFunctionNameAssignment( - const AstRawString* function_name, int pos, - FunctionLiteral::FunctionType function_type, - DeclarationScope* function_scope, ZoneList<Statement*>* result, int index) { - if (function_type == FunctionLiteral::kNamedExpression) { - StatementT statement = factory()->NewEmptyStatement(kNoSourcePosition); - if (function_scope->LookupLocal(function_name) == nullptr) { - // Now that we know the language mode, we can create the const assignment - // in the previously reserved spot. - DCHECK_EQ(function_scope, scope()); - Variable* fvar = function_scope->DeclareFunctionVar(function_name); - VariableProxy* fproxy = factory()->NewVariableProxy(fvar); - statement = factory()->NewExpressionStatement( - factory()->NewAssignment(Token::INIT, fproxy, - factory()->NewThisFunction(pos), - kNoSourcePosition), - kNoSourcePosition); - } - result->Set(index, statement); +void Parser::DeclareFunctionNameVar(const AstRawString* function_name, + FunctionLiteral::FunctionType function_type, + DeclarationScope* function_scope) { + if (function_type == FunctionLiteral::kNamedExpression && + function_scope->LookupLocal(function_name) == nullptr) { + DCHECK_EQ(function_scope, scope()); + function_scope->DeclareFunctionVar(function_name); } } @@ -1851,7 +1888,7 @@ Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt, Expression* subject, Statement* body) { ForOfStatement* for_of = stmt->AsForOfStatement(); - if (for_of != NULL) { + if (for_of != nullptr) { const bool finalize = true; return InitializeForOfStatement(for_of, each, subject, body, finalize, IteratorType::kNormal, each->position()); @@ -2155,7 +2192,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // } // } - DCHECK(for_info.bound_names.length() > 0); + DCHECK_GT(for_info.bound_names.length(), 0); ZoneList<Variable*> temps(for_info.bound_names.length(), zone()); Block* outer_block = @@ -2180,7 +2217,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( temps.Add(temp, zone()); } - Variable* first = NULL; + Variable* first = nullptr; // Make statement: first = 1. if (next) { first = NewTemporary(temp_name); @@ -2205,7 +2242,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // need to know about it. This should be safe because we don't run any code // in this function that looks up break targets. ForStatement* outer_loop = - factory()->NewForStatement(NULL, kNoSourcePosition); + factory()->NewForStatement(nullptr, kNoSourcePosition); outer_block->statements()->Add(outer_loop, zone()); outer_block->set_scope(scope()); @@ -2229,7 +2266,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( Statement* assignment_statement = factory()->NewExpressionStatement(assignment, kNoSourcePosition); int declaration_pos = for_info.parsing_result.descriptor.declaration_pos; - DCHECK(declaration_pos != kNoSourcePosition); + DCHECK_NE(declaration_pos, kNoSourcePosition); decl->proxy()->var()->set_initializer_position(declaration_pos); ignore_completion_block->statements()->Add(assignment_statement, zone()); } @@ -2237,7 +2274,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // Make statement: if (first == 1) { first = 0; } else { next; } if (next) { DCHECK(first); - Expression* compare = NULL; + Expression* compare = nullptr; // Make compare expression: first == 1. { Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition); @@ -2245,7 +2282,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1, kNoSourcePosition); } - Statement* clear_first = NULL; + Statement* clear_first = nullptr; // Make statement: first = 0. { VariableProxy* first_proxy = factory()->NewVariableProxy(first); @@ -2284,7 +2321,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( inner_block->statements()->Add(ignore_completion_block, zone()); // Make cond expression for main loop: flag == 1. - Expression* flag_cond = NULL; + Expression* flag_cond = nullptr; { Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition); VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); @@ -2293,9 +2330,9 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( } // Create chain of expressions "flag = 0, temp_x = x, ..." - Statement* compound_next_statement = NULL; + Statement* compound_next_statement = nullptr; { - Expression* compound_next = NULL; + Expression* compound_next = nullptr; // Make expression: flag = 0. { VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); @@ -2324,12 +2361,12 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // Note that we re-use the original loop node, which retains its labels // and ensures that any break or continue statements in body point to // the right place. - loop->Initialize(NULL, flag_cond, compound_next_statement, body); + loop->Initialize(nullptr, flag_cond, compound_next_statement, body); inner_block->statements()->Add(loop, zone()); // Make statement: {{if (flag == 1) break;}} { - Expression* compare = NULL; + Expression* compare = nullptr; // Make compare expresion: flag == 1. { Expression* const1 = factory()->NewSmiLiteral(1, kNoSourcePosition); @@ -2348,7 +2385,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( inner_block->set_scope(inner_scope); } - outer_loop->Initialize(NULL, NULL, NULL, inner_block); + outer_loop->Initialize(nullptr, nullptr, nullptr, inner_block); return outer_block; } @@ -2357,6 +2394,7 @@ void Parser::AddArrowFunctionFormalParameters( ParserFormalParameters* parameters, Expression* expr, int end_pos, bool* ok) { // ArrowFunctionFormals :: + // Nary(Token::COMMA, VariableProxy*, Tail) // Binary(Token::COMMA, NonTailArrowFunctionFormals, Tail) // Tail // NonTailArrowFunctionFormals :: @@ -2366,9 +2404,30 @@ void Parser::AddArrowFunctionFormalParameters( // VariableProxy // Spread(VariableProxy) // - // As we need to visit the parameters in left-to-right order, we recurse on - // the left-hand side of comma expressions. + // We need to visit the parameters in left-to-right order // + + // For the Nary case, we simply visit the parameters in a loop. + if (expr->IsNaryOperation()) { + NaryOperation* nary = expr->AsNaryOperation(); + // The classifier has already run, so we know that the expression is a valid + // arrow function formals production. + DCHECK_EQ(nary->op(), Token::COMMA); + // Each op position is the end position of the *previous* expr, with the + // second (i.e. first "subsequent") op position being the end position of + // the first child expression. + Expression* next = nary->first(); + for (size_t i = 0; i < nary->subsequent_length(); ++i) { + AddArrowFunctionFormalParameters( + parameters, next, nary->subsequent_op_position(i), CHECK_OK_VOID); + next = nary->subsequent(i); + } + AddArrowFunctionFormalParameters(parameters, next, end_pos, CHECK_OK_VOID); + return; + } + + // For the binary case, we recurse on the left-hand side of binary comma + // expressions. if (expr->IsBinaryOperation()) { BinaryOperation* binop = expr->AsBinaryOperation(); // The classifier has already run, so we know that the expression is a valid @@ -2467,7 +2526,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // Anonymous functions were passed either the empty symbol or a null // handle as the function name. Remember if we were passed a non-empty // handle to decide whether to invoke function name inference. - bool should_infer_name = function_name == NULL; + bool should_infer_name = function_name == nullptr; // We want a non-null handle as the function name by default. We will handle // the "function does not have a shared name" case later. @@ -2518,8 +2577,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( const bool is_lazy = eager_compile_hint == FunctionLiteral::kShouldLazyCompile; - const bool is_top_level = - impl()->AllowsLazyParsingWithoutUnresolvedVariables(); + const bool is_top_level = AllowsLazyParsingWithoutUnresolvedVariables(); const bool is_lazy_top_level_function = is_lazy && is_top_level; const bool is_lazy_inner_function = is_lazy && !is_top_level; const bool is_expression = @@ -2531,6 +2589,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( parsing_on_main_thread_ ? &RuntimeCallStats::ParseFunctionLiteral : &RuntimeCallStats::ParseBackgroundFunctionLiteral); + base::ElapsedTimer timer; + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); // Determine whether we can still lazy parse the inner function. // The preconditions are: @@ -2631,13 +2691,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral( } DCHECK_EQ(should_preparse, temp_zoned_); - if (V8_UNLIKELY(FLAG_trace_preparse)) { - PrintF(" [%s]: %i-%i %.*s\n", - should_preparse ? (is_top_level ? "Preparse no-resolution" - : "Preparse resolution") - : "Full parse", - scope->start_position(), scope->end_position(), - function_name->byte_length(), function_name->raw_data()); + if (V8_UNLIKELY(FLAG_log_function_events)) { + double ms = timer.Elapsed().InMillisecondsF(); + const char* event_name = should_preparse + ? (is_top_level ? "preparse-no-resolution" + : "preparse-resolution") + : "full-parse"; + logger_->FunctionEvent( + event_name, nullptr, script_id(), ms, scope->start_position(), + scope->end_position(), + reinterpret_cast<const char*>(function_name->raw_data()), + function_name->byte_length()); } if (V8_UNLIKELY(FLAG_runtime_stats)) { if (should_preparse) { @@ -2764,8 +2828,8 @@ Parser::LazyParsingResult Parser::SkipFunction( DCHECK(!is_inner_function || !may_abort); PreParser::PreParseResult result = reusable_preparser()->PreParseFunction( - function_name, kind, function_type, function_scope, parsing_module_, - is_inner_function, may_abort, use_counts_, produced_preparsed_scope_data); + function_name, kind, function_type, function_scope, is_inner_function, + may_abort, use_counts_, produced_preparsed_scope_data, this->script_id()); // Return immediately if pre-parser decided to abort parsing. if (result == PreParser::kPreParseAbort) return kLazyParsingAborted; @@ -2775,7 +2839,7 @@ Parser::LazyParsingResult Parser::SkipFunction( *ok = false; return kLazyParsingComplete; } - if (pending_error_handler_.has_pending_error()) { + if (pending_error_handler()->has_pending_error()) { *ok = false; return kLazyParsingComplete; } @@ -3137,6 +3201,20 @@ void Parser::DeclareClassVariable(const AstRawString* name, } } +// TODO(gsathya): Ideally, this should just bypass scope analysis and +// allocate a slot directly on the context. We should just store this +// index in the AST, instead of storing the variable. +Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name, + bool* ok) { + VariableProxy* proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE); + Declaration* declaration = + factory()->NewVariableDeclaration(proxy, kNoSourcePosition); + Variable* var = Declare(declaration, DeclarationDescriptor::NORMAL, CONST, + Variable::DefaultInitializationFlag(CONST), CHECK_OK); + var->ForceContextAllocation(); + return var; +} + // This method declares a property of the given class. It updates the // following fields of class_info, as appropriate: // - constructor @@ -3145,7 +3223,8 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, ClassLiteralProperty* property, ClassLiteralProperty::Kind kind, bool is_static, bool is_constructor, - ClassInfo* class_info, bool* ok) { + bool is_computed_name, ClassInfo* class_info, + bool* ok) { if (is_constructor) { DCHECK(!class_info->constructor); class_info->constructor = property->value()->AsFunctionLiteral(); @@ -3156,11 +3235,44 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, return; } - if (property->kind() == ClassLiteralProperty::FIELD) { - DCHECK(allow_harmony_class_fields()); - // TODO(littledan): Implement class fields + if (kind != ClassLiteralProperty::FIELD) { + class_info->properties->Add(property, zone()); + return; + } + + DCHECK(allow_harmony_public_fields()); + + if (is_static) { + class_info->static_fields->Add(property, zone()); + } else { + class_info->instance_fields->Add(property, zone()); + } + + if (is_computed_name) { + // We create a synthetic variable name here so that scope + // analysis doesn't dedupe the vars. + Variable* computed_name_var = CreateSyntheticContextVariable( + ClassFieldVariableName(ast_value_factory(), + class_info->computed_field_count), + CHECK_OK_VOID); + property->set_computed_name_var(computed_name_var); + class_info->properties->Add(property, zone()); } - class_info->properties->Add(property, zone()); +} + +FunctionLiteral* Parser::CreateInitializerFunction( + DeclarationScope* scope, ZoneList<ClassLiteral::Property*>* fields) { + // function() { .. class fields initializer .. } + ZoneList<Statement*>* statements = NewStatementList(1); + InitializeClassFieldsStatement* static_fields = + factory()->NewInitializeClassFieldsStatement(fields, kNoSourcePosition); + statements->Add(static_fields, zone()); + return factory()->NewFunctionLiteral( + ast_value_factory()->empty_string(), scope, statements, 0, 0, 0, + FunctionLiteral::kNoDuplicateParameters, + FunctionLiteral::kAnonymousExpression, + FunctionLiteral::kShouldEagerCompile, scope->start_position(), true, + GetNextFunctionLiteralId()); } // This method generates a ClassLiteral AST node. @@ -3177,7 +3289,7 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope, int end_pos, bool* ok) { DCHECK_NOT_NULL(block_scope); DCHECK_EQ(block_scope->scope_type(), BLOCK_SCOPE); - DCHECK_EQ(block_scope->language_mode(), STRICT); + DCHECK_EQ(block_scope->language_mode(), LanguageMode::kStrict); bool has_extends = class_info->extends != nullptr; bool has_default_constructor = class_info->constructor == nullptr; @@ -3191,25 +3303,33 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope, class_info->variable->set_initializer_position(end_pos); } + FunctionLiteral* static_fields_initializer = nullptr; + if (class_info->has_static_class_fields) { + static_fields_initializer = CreateInitializerFunction( + class_info->static_fields_scope, class_info->static_fields); + } + + FunctionLiteral* instance_fields_initializer_function = nullptr; + if (class_info->has_instance_class_fields) { + instance_fields_initializer_function = CreateInitializerFunction( + class_info->instance_fields_scope, class_info->instance_fields); + class_info->constructor->set_requires_instance_fields_initializer(true); + } + ClassLiteral* class_literal = factory()->NewClassLiteral( block_scope, class_info->variable, class_info->extends, - class_info->constructor, class_info->properties, pos, end_pos, - class_info->has_name_static_property, + class_info->constructor, class_info->properties, + static_fields_initializer, instance_fields_initializer_function, pos, + end_pos, class_info->has_name_static_property, class_info->has_static_computed_names, class_info->is_anonymous); AddFunctionForNameInference(class_info->constructor); - return class_literal; } -Literal* Parser::GetLiteralUndefined(int position) { - return factory()->NewUndefinedLiteral(position); -} - - void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { Declaration* decl = scope->CheckConflictingVarDeclarations(); - if (decl != NULL) { + if (decl != nullptr) { // In ES6, conflicting variable bindings are early errors. const AstRawString* name = decl->proxy()->raw_name(); int position = decl->proxy()->position(); @@ -3263,7 +3383,7 @@ void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) { // Parser support bool Parser::TargetStackContainsLabel(const AstRawString* label) { - for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) { + for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) { if (ContainsLabel(t->statement()->labels(), label)) return true; } return false; @@ -3272,31 +3392,31 @@ bool Parser::TargetStackContainsLabel(const AstRawString* label) { BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label, bool* ok) { - bool anonymous = label == NULL; - for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) { + bool anonymous = label == nullptr; + for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) { BreakableStatement* stat = t->statement(); if ((anonymous && stat->is_target_for_anonymous()) || (!anonymous && ContainsLabel(stat->labels(), label))) { return stat; } } - return NULL; + return nullptr; } IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, bool* ok) { - bool anonymous = label == NULL; - for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) { + bool anonymous = label == nullptr; + for (ParserTarget* t = target_stack_; t != nullptr; t = t->previous()) { IterationStatement* stat = t->statement()->AsIterationStatement(); - if (stat == NULL) continue; + if (stat == nullptr) continue; DCHECK(stat->is_target_for_anonymous()); if (anonymous || ContainsLabel(stat->labels(), label)) { return stat; } } - return NULL; + return nullptr; } @@ -3311,17 +3431,6 @@ void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) { } } -void Parser::ReportErrors(Isolate* isolate, Handle<Script> script) { - if (stack_overflow()) { - isolate->StackOverflow(); - } else { - DCHECK(pending_error_handler_.has_pending_error()); - // Internalize ast values for throwing the pending error. - ast_value_factory()->Internalize(isolate); - pending_error_handler_.ThrowPendingError(isolate, script); - } -} - void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) { // Move statistics to Isolate. for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; @@ -3341,10 +3450,15 @@ void Parser::UpdateStatistics(Isolate* isolate, Handle<Script> script) { } void Parser::ParseOnBackground(ParseInfo* info) { + RuntimeCallTimerScope runtimeTimer(runtime_call_stats_, + &RuntimeCallStats::ParseBackgroundProgram); parsing_on_main_thread_ = false; + if (!info->script().is_null()) { + set_script_id(info->script()->id()); + } - DCHECK(info->literal() == NULL); - FunctionLiteral* result = NULL; + DCHECK_NULL(info->literal()); + FunctionLiteral* result = nullptr; ParserLogger logger; if (produce_cached_parse_data()) { @@ -3380,17 +3494,8 @@ void Parser::ParseOnBackground(ParseInfo* info) { // care of calling AstValueFactory::Internalize just before compilation. if (produce_cached_parse_data()) { - if (result != NULL) *info->cached_data() = logger.GetScriptData(); - log_ = NULL; - } - if (runtime_call_stats_ && - (FLAG_runtime_stats & - v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { - auto value = v8::tracing::TracedValue::Create(); - runtime_call_stats_->Dump(value.get()); - TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"), - "V8.RuntimeStats", TRACE_EVENT_SCOPE_THREAD, - "runtime-call-stats", std::move(value)); + if (result != nullptr) *info->cached_data() = logger.GetScriptData(); + log_ = nullptr; } } @@ -3400,17 +3505,13 @@ Parser::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) { void Parser::AddTemplateSpan(TemplateLiteralState* state, bool should_cook, bool tail) { - DCHECK(should_cook || allow_harmony_template_escapes()); - int pos = scanner()->location().beg_pos; int end = scanner()->location().end_pos - (tail ? 1 : 2); - const AstRawString* trv = scanner()->CurrentRawSymbol(ast_value_factory()); - Literal* raw = factory()->NewStringLiteral(trv, pos); + const AstRawString* raw = scanner()->CurrentRawSymbol(ast_value_factory()); if (should_cook) { - const AstRawString* tv = scanner()->CurrentSymbol(ast_value_factory()); - Literal* cooked = factory()->NewStringLiteral(tv, pos); + const AstRawString* cooked = scanner()->CurrentSymbol(ast_value_factory()); (*state)->AddTemplateSpan(cooked, raw, end, zone()); } else { - (*state)->AddTemplateSpan(GetLiteralUndefined(pos), raw, end, zone()); + (*state)->AddTemplateSpan(nullptr, raw, end, zone()); } } @@ -3425,46 +3526,54 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, Expression* tag) { TemplateLiteral* lit = *state; int pos = lit->position(); - const ZoneList<Literal*>* cooked_strings = lit->cooked(); - const ZoneList<Literal*>* raw_strings = lit->raw(); + const ZoneList<const AstRawString*>* cooked_strings = lit->cooked(); + const ZoneList<const AstRawString*>* raw_strings = lit->raw(); const ZoneList<Expression*>* expressions = lit->expressions(); DCHECK_EQ(cooked_strings->length(), raw_strings->length()); DCHECK_EQ(cooked_strings->length(), expressions->length() + 1); if (!tag) { - // Build tree of BinaryOps to simplify code-generation - Expression* expr = cooked_strings->at(0); + Expression* first_string = + factory()->NewStringLiteral(cooked_strings->at(0), kNoSourcePosition); + if (expressions->length() == 0) return first_string; + + // Build N-ary addition op to simplify code-generation. + // TODO(leszeks): Could we just store this expression in the + // TemplateLiteralState and build it as we go? + NaryOperation* expr = factory()->NewNaryOperation( + Token::ADD, first_string, 2 * expressions->length()); + int i = 0; while (i < expressions->length()) { Expression* sub = expressions->at(i++); - Expression* cooked_str = cooked_strings->at(i); + const AstRawString* cooked_str = cooked_strings->at(i); + DCHECK_NOT_NULL(cooked_str); // Let middle be ToString(sub). ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone()); args->Add(sub, zone()); - Expression* middle = factory()->NewCallRuntime(Runtime::kInlineToString, - args, sub->position()); + Expression* sub_to_string = factory()->NewCallRuntime( + Runtime::kInlineToString, args, sub->position()); - expr = factory()->NewBinaryOperation( - Token::ADD, factory()->NewBinaryOperation( - Token::ADD, expr, middle, expr->position()), - cooked_str, sub->position()); + expr->AddSubsequent(sub_to_string, sub->position()); + expr->AddSubsequent( + factory()->NewStringLiteral(cooked_str, kNoSourcePosition), + sub->position()); } return expr; } else { // GetTemplateObject const int32_t hash = ComputeTemplateLiteralHash(lit); - Expression* template_object = factory()->NewGetTemplateObject( - const_cast<ZoneList<Literal*>*>(cooked_strings), - const_cast<ZoneList<Literal*>*>(raw_strings), hash, pos); + Expression* template_object = + factory()->NewGetTemplateObject(cooked_strings, raw_strings, hash, pos); // Call TagFn ZoneList<Expression*>* call_args = new (zone()) ZoneList<Expression*>(expressions->length() + 1, zone()); call_args->Add(template_object, zone()); call_args->AddAll(*expressions, zone()); - return factory()->NewCall(tag, call_args, pos); + return factory()->NewTaggedTemplate(tag, call_args, pos); } } @@ -3483,7 +3592,7 @@ uint32_t HalfAvalance(uint32_t a) { } // namespace int32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) { - const ZoneList<Literal*>* raw_strings = lit->raw(); + const ZoneList<const AstRawString*>* raw_strings = lit->raw(); int total = raw_strings->length(); DCHECK_GT(total, 0); @@ -3495,8 +3604,7 @@ int32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) { running_hash, "${}", 3); } - const AstRawString* raw_string = - raw_strings->at(index)->AsLiteral()->raw_value()->AsString(); + const AstRawString* raw_string = raw_strings->at(index); if (raw_string->is_one_byte()) { const char* data = reinterpret_cast<const char*>(raw_string->raw_data()); running_hash = StringHasher::ComputeRunningHashOneByte( @@ -3700,53 +3808,18 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block, body->Add(block, zone()); } -class NonPatternRewriter : public AstExpressionRewriter { - public: - NonPatternRewriter(uintptr_t stack_limit, Parser* parser) - : AstExpressionRewriter(stack_limit), parser_(parser) {} - ~NonPatternRewriter() override {} - - private: - bool RewriteExpression(Expression* expr) override { - if (expr->IsRewritableExpression()) return true; - // Rewrite only what could have been a pattern but is not. - if (expr->IsArrayLiteral()) { - // Spread rewriting in array literals. - ArrayLiteral* lit = expr->AsArrayLiteral(); - VisitExpressions(lit->values()); - replacement_ = parser_->RewriteSpreads(lit); - return false; - } - if (expr->IsObjectLiteral()) { - return true; - } - if (expr->IsBinaryOperation() && - expr->AsBinaryOperation()->op() == Token::COMMA) { - return true; - } - // Everything else does not need rewriting. - return false; - } - - void VisitLiteralProperty(LiteralProperty* property) override { - if (property == nullptr) return; - // Do not rewrite (computed) key expressions - AST_REWRITE_PROPERTY(Expression, property, value); - } - - Parser* parser_; -}; - void Parser::RewriteNonPattern(bool* ok) { ValidateExpression(CHECK_OK_VOID); auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite(); int begin = classifier()->GetNonPatternBegin(); int end = non_patterns_to_rewrite->length(); if (begin < end) { - NonPatternRewriter rewriter(stack_limit_, this); for (int i = begin; i < end; i++) { - DCHECK(non_patterns_to_rewrite->at(i)->IsRewritableExpression()); - rewriter.Rewrite(non_patterns_to_rewrite->at(i)); + RewritableExpression* expr = non_patterns_to_rewrite->at(i); + // TODO(adamk): Make this more typesafe. + DCHECK(expr->expression()->IsArrayLiteral()); + ArrayLiteral* lit = expr->expression()->AsArrayLiteral(); + expr->Rewrite(RewriteSpreads(lit)); } non_patterns_to_rewrite->Rewind(begin); } @@ -3759,73 +3832,19 @@ void Parser::RewriteDestructuringAssignments() { for (int i = assignments.length() - 1; i >= 0; --i) { // Rewrite list in reverse, so that nested assignment patterns are rewritten // correctly. - const DestructuringAssignment& pair = assignments.at(i); - RewritableExpression* to_rewrite = - pair.assignment->AsRewritableExpression(); + RewritableExpression* to_rewrite = assignments[i]; DCHECK_NOT_NULL(to_rewrite); if (!to_rewrite->is_rewritten()) { // Since this function is called at the end of parsing the program, // pair.scope may already have been removed by FinalizeBlockScope in the // meantime. - Scope* scope = pair.scope->GetUnremovedScope(); + Scope* scope = to_rewrite->scope()->GetUnremovedScope(); BlockState block_state(&scope_, scope); RewriteDestructuringAssignment(to_rewrite); } } } -Expression* Parser::RewriteExponentiation(Expression* left, Expression* right, - int pos) { - ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); - args->Add(left, zone()); - args->Add(right, zone()); - return factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos); -} - -Expression* Parser::RewriteAssignExponentiation(Expression* left, - Expression* right, int pos) { - ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); - if (left->IsVariableProxy()) { - VariableProxy* lhs = left->AsVariableProxy(); - - Expression* result; - DCHECK_NOT_NULL(lhs->raw_name()); - result = ExpressionFromIdentifier(lhs->raw_name(), lhs->position()); - args->Add(left, zone()); - args->Add(right, zone()); - Expression* call = - factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos); - return factory()->NewAssignment(Token::ASSIGN, result, call, pos); - } else if (left->IsProperty()) { - Property* prop = left->AsProperty(); - auto temp_obj = NewTemporary(ast_value_factory()->empty_string()); - auto temp_key = NewTemporary(ast_value_factory()->empty_string()); - Expression* assign_obj = factory()->NewAssignment( - Token::ASSIGN, factory()->NewVariableProxy(temp_obj), prop->obj(), - kNoSourcePosition); - Expression* assign_key = factory()->NewAssignment( - Token::ASSIGN, factory()->NewVariableProxy(temp_key), prop->key(), - kNoSourcePosition); - args->Add(factory()->NewProperty(factory()->NewVariableProxy(temp_obj), - factory()->NewVariableProxy(temp_key), - left->position()), - zone()); - args->Add(right, zone()); - Expression* call = - factory()->NewCallRuntime(Context::MATH_POW_INDEX, args, pos); - Expression* target = factory()->NewProperty( - factory()->NewVariableProxy(temp_obj), - factory()->NewVariableProxy(temp_key), kNoSourcePosition); - Expression* assign = - factory()->NewAssignment(Token::ASSIGN, target, call, pos); - return factory()->NewBinaryOperation( - Token::COMMA, assign_obj, - factory()->NewBinaryOperation(Token::COMMA, assign_key, assign, pos), - pos); - } - UNREACHABLE(); -} - Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { // Array literals containing spreads are rewritten using do expressions, e.g. // [1, 2, 3, ...x, 4, ...y, 5] @@ -3860,8 +3879,7 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { // %AppendElement($R, value) // or, in case of a hole, // ++($R.length) - if (!value->IsLiteral() || - !value->AsLiteral()->raw_value()->IsTheHole()) { + if (!value->IsTheHoleLiteral()) { ZoneList<Expression*>* append_element_args = NewExpressionList(2); append_element_args->Add(factory()->NewVariableProxy(result), zone()); append_element_args->Add(value, zone()); @@ -3914,14 +3932,12 @@ Expression* Parser::RewriteSpreads(ArrayLiteral* lit) { return factory()->NewDoExpression(do_block, result, lit->position()); } -void Parser::QueueDestructuringAssignmentForRewriting(Expression* expr) { - DCHECK(expr->IsRewritableExpression()); - function_state_->AddDestructuringAssignment( - DestructuringAssignment(expr, scope())); +void Parser::QueueDestructuringAssignmentForRewriting( + RewritableExpression* expr) { + function_state_->AddDestructuringAssignment(expr); } -void Parser::QueueNonPatternForRewriting(Expression* expr, bool* ok) { - DCHECK(expr->IsRewritableExpression()); +void Parser::QueueNonPatternForRewriting(RewritableExpression* expr, bool* ok) { function_state_->AddNonPatternForRewriting(expr, ok); } @@ -4171,7 +4187,7 @@ void Parser::FinalizeIteratorUse(Variable* completion, Expression* condition, Block* block = factory()->NewBlock(2, true); Expression* proxy = factory()->NewVariableProxy(completion); BuildIteratorCloseForCompletion(block->statements(), iter, proxy, type); - DCHECK(block->statements()->length() == 2); + DCHECK_EQ(block->statements()->length(), 2); maybe_close = IgnoreCompletion(factory()->NewIfStatement( condition, block, factory()->NewEmptyStatement(nopos), nopos)); diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h index 296762c14d..aa800dafc5 100644 --- a/deps/v8/src/parsing/parser.h +++ b/deps/v8/src/parsing/parser.h @@ -17,7 +17,6 @@ #include "src/parsing/preparse-data-format.h" #include "src/parsing/preparse-data.h" #include "src/parsing/preparser.h" -#include "src/pending-compilation-error-handler.h" #include "src/utils.h" namespace v8 { @@ -31,6 +30,7 @@ class ParseInfo; class ScriptData; class ParserTarget; class ParserTargetScope; +class PendingCompilationErrorHandler; class PreParsedScopeData; class FunctionEntry BASE_EMBEDDED { @@ -85,7 +85,7 @@ class ParseData { if (pd->IsSane()) return pd; cached_data->Reject(); delete pd; - return NULL; + return nullptr; } void Initialize(); @@ -167,6 +167,7 @@ struct ParserTypes<Parser> { typedef ObjectLiteral::Property* ObjectLiteralProperty; typedef ClassLiteral::Property* ClassLiteralProperty; typedef v8::internal::Suspend* Suspend; + typedef v8::internal::RewritableExpression* RewritableExpression; typedef ZoneList<v8::internal::Expression*>* ExpressionList; typedef ZoneList<ObjectLiteral::Property*>* ObjectPropertyList; typedef ZoneList<ClassLiteral::Property*>* ClassPropertyList; @@ -190,9 +191,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { explicit Parser(ParseInfo* info); ~Parser() { delete reusable_preparser_; - reusable_preparser_ = NULL; + reusable_preparser_ = nullptr; delete cached_parse_data_; - cached_parse_data_ = NULL; + cached_parse_data_ = nullptr; } static bool IsPreParser() { return false; } @@ -210,8 +211,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { void DeserializeScopeChain(ParseInfo* info, MaybeHandle<ScopeInfo> maybe_outer_scope_info); - // Handle errors detected during parsing - void ReportErrors(Isolate* isolate, Handle<Script> script); // Move statistics to Isolate void UpdateStatistics(Isolate* isolate, Handle<Script> script); void HandleSourceURLComments(Isolate* isolate, Handle<Script> script); @@ -257,7 +256,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { void PrepareGeneratorVariables(); - // Returns NULL if parsing failed. + // Returns nullptr if parsing failed. FunctionLiteral* ParseProgram(Isolate* isolate, ParseInfo* info); FunctionLiteral* ParseFunction(Isolate* isolate, ParseInfo* info, @@ -283,22 +282,20 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { } PreParser* reusable_preparser() { - if (reusable_preparser_ == NULL) { + if (reusable_preparser_ == nullptr) { reusable_preparser_ = new PreParser(zone(), &scanner_, stack_limit_, ast_value_factory(), - &pending_error_handler_, runtime_call_stats_, - parsing_on_main_thread_); + pending_error_handler(), runtime_call_stats_, logger_, + -1, parsing_module_, parsing_on_main_thread_); #define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name()); SET_ALLOW(natives); SET_ALLOW(harmony_do_expressions); SET_ALLOW(harmony_function_sent); - SET_ALLOW(harmony_class_fields); - SET_ALLOW(harmony_object_rest_spread); + SET_ALLOW(harmony_public_fields); SET_ALLOW(harmony_dynamic_import); SET_ALLOW(harmony_import_meta); SET_ALLOW(harmony_async_iteration); - SET_ALLOW(harmony_template_escapes); - SET_ALLOW(harmony_restrictive_generators); + SET_ALLOW(harmony_bigint); #undef SET_ALLOW } return reusable_preparser_; @@ -348,15 +345,18 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { void ParseAndRewriteAsyncGeneratorFunctionBody(int pos, FunctionKind kind, ZoneList<Statement*>* body, bool* ok); - void CreateFunctionNameAssignment(const AstRawString* function_name, int pos, - FunctionLiteral::FunctionType function_type, - DeclarationScope* function_scope, - ZoneList<Statement*>* result, int index); + void DeclareFunctionNameVar(const AstRawString* function_name, + FunctionLiteral::FunctionType function_type, + DeclarationScope* function_scope); Statement* DeclareFunction(const AstRawString* variable_name, FunctionLiteral* function, VariableMode mode, int pos, bool is_sloppy_block_function, ZoneList<const AstRawString*>* names, bool* ok); + Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name, + bool* ok); + FunctionLiteral* CreateInitializerFunction( + DeclarationScope* scope, ZoneList<ClassLiteral::Property*>* fields); V8_INLINE Statement* DeclareClass(const AstRawString* variable_name, Expression* value, ZoneList<const AstRawString*>* names, @@ -368,6 +368,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ClassLiteralProperty* property, ClassLiteralProperty::Kind kind, bool is_static, bool is_constructor, + bool is_computed_name, ClassInfo* class_info, bool* ok); V8_INLINE Expression* RewriteClassLiteral(Scope* block_scope, const AstRawString* name, @@ -426,9 +427,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { int function_token_position, FunctionLiteral::FunctionType type, LanguageMode language_mode, bool* ok); - // Get odd-ball literals. - Literal* GetLiteralUndefined(int position); - // Check if the scope has conflicting var/let declarations from different // scopes. This covers for example // @@ -499,13 +497,13 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { TemplateLiteral(Zone* zone, int pos) : cooked_(8, zone), raw_(8, zone), expressions_(8, zone), pos_(pos) {} - const ZoneList<Literal*>* cooked() const { return &cooked_; } - const ZoneList<Literal*>* raw() const { return &raw_; } + const ZoneList<const AstRawString*>* cooked() const { return &cooked_; } + const ZoneList<const AstRawString*>* raw() const { return &raw_; } const ZoneList<Expression*>* expressions() const { return &expressions_; } int position() const { return pos_; } - void AddTemplateSpan(Literal* cooked, Literal* raw, int end, Zone* zone) { - DCHECK_NOT_NULL(cooked); + void AddTemplateSpan(const AstRawString* cooked, const AstRawString* raw, + int end, Zone* zone) { DCHECK_NOT_NULL(raw); cooked_.Add(cooked, zone); raw_.Add(raw, zone); @@ -517,8 +515,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { } private: - ZoneList<Literal*> cooked_; - ZoneList<Literal*> raw_; + ZoneList<const AstRawString*> cooked_; + ZoneList<const AstRawString*> raw_; ZoneList<Expression*> expressions_; int pos_; }; @@ -529,9 +527,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // "should_cook" means that the span can be "cooked": in tagged template // literals, both the raw and "cooked" representations are available to user // code ("cooked" meaning that escape sequences are converted to their - // interpreted values). With the --harmony-template-escapes flag, invalid - // escape sequences cause the cooked span to be represented by undefined, - // instead of being a syntax error. + // interpreted values). Invalid escape sequences cause the cooked span + // to be represented by undefined, instead of being a syntax error. // "tail" indicates that this span is the last in the literal. void AddTemplateSpan(TemplateLiteralState* state, bool should_cook, bool tail); @@ -554,20 +551,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // Rewrite all DestructuringAssignments in the current FunctionState. V8_INLINE void RewriteDestructuringAssignments(); - V8_INLINE Expression* RewriteExponentiation(Expression* left, - Expression* right, int pos); - V8_INLINE Expression* RewriteAssignExponentiation(Expression* left, - Expression* right, int pos); - - friend class NonPatternRewriter; - V8_INLINE Expression* RewriteSpreads(ArrayLiteral* lit); + Expression* RewriteSpreads(ArrayLiteral* lit); // Rewrite expressions that are not used as patterns V8_INLINE void RewriteNonPattern(bool* ok); V8_INLINE void QueueDestructuringAssignmentForRewriting( - Expression* assignment); - V8_INLINE void QueueNonPatternForRewriting(Expression* expr, bool* ok); + RewritableExpression* assignment); + V8_INLINE void QueueNonPatternForRewriting(RewritableExpression* expr, + bool* ok); friend class InitializerRewriter; void RewriteParameterInitializer(Expression* expr); @@ -623,9 +615,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // Returns true if the expression is of type "this.foo". V8_INLINE static bool IsThisProperty(Expression* expression) { - DCHECK(expression != NULL); + DCHECK_NOT_NULL(expression); Property* property = expression->AsProperty(); - return property != NULL && property->obj()->IsVariableProxy() && + return property != nullptr && property->obj()->IsVariableProxy() && property->obj()->AsVariableProxy()->is_this(); } @@ -689,8 +681,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ExpressionStatement* e_stat = statement->AsExpressionStatement(); if (e_stat == nullptr) return false; Literal* literal = e_stat->expression()->AsLiteral(); - if (literal == nullptr || !literal->raw_value()->IsString()) return false; - return arg == nullptr || literal->raw_value()->AsString() == arg; + if (literal == nullptr || !literal->IsString()) return false; + return arg == nullptr || literal->AsRawString() == arg; } V8_INLINE void GetDefaultStrings( @@ -740,7 +732,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // literal so it can be added as a constant function property. V8_INLINE static void CheckAssigningFunctionLiteralToProperty( Expression* left, Expression* right) { - DCHECK(left != NULL); + DCHECK_NOT_NULL(left); if (left->IsProperty() && right->IsFunctionLiteral()) { right->AsFunctionLiteral()->set_pretenure(); } @@ -761,6 +753,13 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { bool ShortcutNumericLiteralBinaryExpression(Expression** x, Expression* y, Token::Value op, int pos); + // Returns true if we have a binary operation between a binary/n-ary + // expression (with the same operation) and a value, which can be collapsed + // into a single n-ary expression. In that case, *x will be changed to an + // n-ary expression. + bool CollapseNaryExpression(Expression** x, Expression* y, Token::Value op, + int pos, const SourceRange& range); + // Rewrites the following types of unary expressions: // not <literal> -> true / false // + <numeric literal> -> <numeric literal> @@ -798,10 +797,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { } // Reporting errors. - V8_INLINE void ReportMessageAt(Scanner::Location source_location, - MessageTemplate::Template message, - const char* arg = NULL, - ParseErrorType error_type = kSyntaxError) { + void ReportMessageAt(Scanner::Location source_location, + MessageTemplate::Template message, + const char* arg = nullptr, + ParseErrorType error_type = kSyntaxError) { if (stack_overflow()) { // Suppress the error message (syntax error or such) in the presence of a // stack overflow. The isolate allows only one pending exception at at @@ -809,15 +808,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // and we want to report the stack overflow later. return; } - pending_error_handler_.ReportMessageAt(source_location.beg_pos, - source_location.end_pos, message, - arg, error_type); + pending_error_handler()->ReportMessageAt(source_location.beg_pos, + source_location.end_pos, message, + arg, error_type); } - V8_INLINE void ReportMessageAt(Scanner::Location source_location, - MessageTemplate::Template message, - const AstRawString* arg, - ParseErrorType error_type = kSyntaxError) { + void ReportMessageAt(Scanner::Location source_location, + MessageTemplate::Template message, + const AstRawString* arg, + ParseErrorType error_type = kSyntaxError) { if (stack_overflow()) { // Suppress the error message (syntax error or such) in the presence of a // stack overflow. The isolate allows only one pending exception at at @@ -825,9 +824,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // and we want to report the stack overflow later. return; } - pending_error_handler_.ReportMessageAt(source_location.beg_pos, - source_location.end_pos, message, - arg, error_type); + pending_error_handler()->ReportMessageAt(source_location.beg_pos, + source_location.end_pos, message, + arg, error_type); } // "null" return type creators. @@ -845,20 +844,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { return subject == nullptr; } - // Non-NULL empty string. + // Non-null empty string. V8_INLINE const AstRawString* EmptyIdentifierString() const { return ast_value_factory()->empty_string(); } - // Odd-ball literal creators. - V8_INLINE Literal* GetLiteralTheHole(int position) { - return factory()->NewTheHoleLiteral(kNoSourcePosition); - } - // Producing data during the recursive descent. V8_INLINE const AstRawString* GetSymbol() const { const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory()); - DCHECK(result != NULL); + DCHECK_NOT_NULL(result); return result; } @@ -882,6 +876,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { Expression* NewSuperCallReference(int pos); Expression* NewTargetExpression(int pos); Expression* FunctionSentExpression(int pos); + Expression* ImportMetaExpression(int pos); Literal* ExpressionFromLiteral(Token::Value token, int pos); @@ -995,7 +990,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { return function_state_->GetReportedErrorList(); } - V8_INLINE ZoneList<Expression*>* GetNonPatternList() const { + V8_INLINE ZoneList<RewritableExpression*>* GetNonPatternList() const { return function_state_->non_patterns_to_rewrite(); } @@ -1009,6 +1004,32 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { return parameters_end_pos_ != kNoSourcePosition; } + V8_INLINE void ConvertBinaryToNaryOperationSourceRange( + BinaryOperation* binary_op, NaryOperation* nary_op) { + if (source_range_map_ == nullptr) return; + DCHECK_NULL(source_range_map_->Find(nary_op)); + + BinaryOperationSourceRanges* ranges = + static_cast<BinaryOperationSourceRanges*>( + source_range_map_->Find(binary_op)); + if (ranges == nullptr) return; + + SourceRange range = ranges->GetRange(SourceRangeKind::kRight); + source_range_map_->Insert( + nary_op, new (zone()) NaryOperationSourceRanges(zone(), range)); + } + + V8_INLINE void AppendNaryOperationSourceRange(NaryOperation* node, + const SourceRange& range) { + if (source_range_map_ == nullptr) return; + NaryOperationSourceRanges* ranges = + static_cast<NaryOperationSourceRanges*>(source_range_map_->Find(node)); + if (ranges == nullptr) return; + + ranges->AddRange(range); + DCHECK_EQ(node->subsequent_length(), ranges->RangeCount()); + } + V8_INLINE void RecordBlockSourceRange(Block* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; @@ -1032,6 +1053,14 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { new (zone()) ConditionalSourceRanges(then_range, else_range)); } + V8_INLINE void RecordBinaryOperationSourceRange( + Expression* node, const SourceRange& right_range) { + if (source_range_map_ == nullptr) return; + source_range_map_->Insert(node->AsBinaryOperation(), + new (zone()) + BinaryOperationSourceRanges(right_range)); + } + V8_INLINE void RecordJumpStatementSourceRange(Statement* node, int32_t continuation_position) { if (source_range_map_ == nullptr) return; @@ -1113,8 +1142,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ScriptCompiler::CompileOptions compile_options_; ParseData* cached_parse_data_; - PendingCompilationErrorHandler pending_error_handler_; - // Other information which will be stored in Parser and moved to Isolate after // parsing. int use_counts_[v8::Isolate::kUseCounterFeatureCount]; diff --git a/deps/v8/src/parsing/parsing.cc b/deps/v8/src/parsing/parsing.cc index 7a280b00b8..bc3c6dec7b 100644 --- a/deps/v8/src/parsing/parsing.cc +++ b/deps/v8/src/parsing/parsing.cc @@ -40,7 +40,8 @@ bool ParseProgram(ParseInfo* info, Isolate* isolate) { result = parser.ParseProgram(isolate, info); info->set_literal(result); if (result == nullptr) { - parser.ReportErrors(isolate, info->script()); + info->pending_error_handler()->ReportErrors(isolate, info->script(), + info->ast_value_factory()); } else { result->scope()->AttachOuterScopeInfo(info, isolate); info->set_language_mode(info->literal()->language_mode()); @@ -74,7 +75,8 @@ bool ParseFunction(ParseInfo* info, Handle<SharedFunctionInfo> shared_info, result = parser.ParseFunction(isolate, info, shared_info); info->set_literal(result); if (result == nullptr) { - parser.ReportErrors(isolate, info->script()); + info->pending_error_handler()->ReportErrors(isolate, info->script(), + info->ast_value_factory()); } else { result->scope()->AttachOuterScopeInfo(info, isolate); } diff --git a/deps/v8/src/parsing/pattern-rewriter.cc b/deps/v8/src/parsing/pattern-rewriter.cc index 2f5d248aed..faecb5bb0c 100644 --- a/deps/v8/src/parsing/pattern-rewriter.cc +++ b/deps/v8/src/parsing/pattern-rewriter.cc @@ -131,7 +131,7 @@ void Parser::RewriteDestructuringAssignment(RewritableExpression* to_rewrite) { Expression* Parser::RewriteDestructuringAssignment(Assignment* assignment) { DCHECK_NOT_NULL(assignment); DCHECK_EQ(Token::ASSIGN, assignment->op()); - auto to_rewrite = factory()->NewRewritableExpression(assignment); + auto to_rewrite = factory()->NewRewritableExpression(assignment, scope()); RewriteDestructuringAssignment(to_rewrite); return to_rewrite->expression(); } @@ -220,7 +220,7 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { if (!*ok_) return; DCHECK_NOT_NULL(var); DCHECK(proxy->is_resolved()); - DCHECK(initializer_position_ != kNoSourcePosition); + DCHECK_NE(initializer_position_, kNoSourcePosition); var->set_initializer_position(initializer_position_); Scope* declaration_scope = @@ -419,7 +419,7 @@ void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern, DCHECK(key->IsPropertyName() || key->IsNumberLiteral()); } - DCHECK(rest_runtime_callargs != nullptr); + DCHECK_NOT_NULL(rest_runtime_callargs); rest_runtime_callargs->Add(excluded_property, zone()); } @@ -539,7 +539,7 @@ void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, } block_->statements()->Add(if_not_done, zone()); - if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) { + if (!value->IsTheHoleLiteral()) { { // completion = kAbruptCompletion; Expression* proxy = factory()->NewVariableProxy(completion); @@ -726,6 +726,7 @@ void PatternRewriter::VisitProperty(v8::internal::Property* node) { void PatternRewriter::Visit##Node(v8::internal::Node*) { UNREACHABLE(); } NOT_A_PATTERN(BinaryOperation) +NOT_A_PATTERN(NaryOperation) NOT_A_PATTERN(Block) NOT_A_PATTERN(BreakStatement) NOT_A_PATTERN(Call) @@ -772,6 +773,7 @@ NOT_A_PATTERN(WithStatement) NOT_A_PATTERN(Yield) NOT_A_PATTERN(YieldStar) NOT_A_PATTERN(Await) +NOT_A_PATTERN(InitializeClassFieldsStatement) #undef NOT_A_PATTERN } // namespace internal diff --git a/deps/v8/src/parsing/preparsed-scope-data.cc b/deps/v8/src/parsing/preparsed-scope-data.cc index 8d2ce2d1a5..7191639cf8 100644 --- a/deps/v8/src/parsing/preparsed-scope-data.cc +++ b/deps/v8/src/parsing/preparsed-scope-data.cc @@ -20,27 +20,27 @@ class ScopeCallsSloppyEvalField : public BitField<bool, 0, 1> {}; class InnerScopeCallsEvalField : public BitField<bool, ScopeCallsSloppyEvalField::kNext, 1> {}; -class VariableIsUsedField : public BitField16<bool, 0, 1> {}; -class VariableMaybeAssignedField - : public BitField16<bool, VariableIsUsedField::kNext, 1> {}; +class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {}; class VariableContextAllocatedField - : public BitField16<bool, VariableMaybeAssignedField::kNext, 1> {}; + : public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {}; const int kMagicValue = 0xc0de0de; #ifdef DEBUG const size_t kUint32Size = 5; const size_t kUint8Size = 2; +const size_t kQuarterMarker = 0; #else const size_t kUint32Size = 4; const size_t kUint8Size = 1; #endif +const int kPlaceholderSize = kUint32Size; const int kSkippableFunctionDataSize = 4 * kUint32Size + 1 * kUint8Size; -STATIC_ASSERT(LANGUAGE_END == 2); -class LanguageField : public BitField<int, 0, 1> {}; -class UsesSuperField : public BitField<bool, LanguageField::kNext, 1> {}; +class LanguageField : public BitField8<LanguageMode, 0, 1> {}; +class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {}; +STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues); } // namespace @@ -98,6 +98,7 @@ void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) { for (int i = 0; i < 4; ++i) { backing_store_.push_back(*d++); } + free_quarters_in_last_byte_ = 0; } void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) { @@ -120,6 +121,25 @@ void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) { backing_store_.push_back(kUint8Size); #endif backing_store_.push_back(data); + free_quarters_in_last_byte_ = 0; +} + +void ProducedPreParsedScopeData::ByteData::WriteQuarter(uint8_t data) { + DCHECK_LE(data, 3); + if (free_quarters_in_last_byte_ == 0) { +#ifdef DEBUG + // Save a marker in debug mode. + backing_store_.push_back(kQuarterMarker); +#endif + backing_store_.push_back(0); + free_quarters_in_last_byte_ = 3; + } else { + --free_quarters_in_last_byte_; + } + + uint8_t shift_amount = free_quarters_in_last_byte_ * 2; + DCHECK_EQ(backing_store_.back() & (3 << shift_amount), 0); + backing_store_.back() |= (data << shift_amount); } Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize( @@ -215,7 +235,7 @@ void ProducedPreParsedScopeData::AddSkippableFunction( uint8_t language_and_super = LanguageField::encode(language_mode) | UsesSuperField::encode(uses_super_property); - byte_data_->WriteUint8(language_and_super); + byte_data_->WriteQuarter(language_and_super); } void ProducedPreParsedScopeData::SaveScopeAllocationData( @@ -224,9 +244,9 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData( DCHECK(previously_produced_preparsed_scope_data_.is_null()); // The data contains a uint32 (reserved space for scope_data_start) and // function data items, kSkippableFunctionDataSize each. - DCHECK_GE(byte_data_->size(), kUint32Size); + DCHECK_GE(byte_data_->size(), kPlaceholderSize); DCHECK_LE(byte_data_->size(), std::numeric_limits<uint32_t>::max()); - DCHECK_EQ(byte_data_->size() % kSkippableFunctionDataSize, kUint32Size); + DCHECK_EQ(byte_data_->size() % kSkippableFunctionDataSize, kPlaceholderSize); if (bailed_out_) { return; @@ -235,7 +255,7 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData( uint32_t scope_data_start = static_cast<uint32_t>(byte_data_->size()); // If there are no skippable inner functions, we don't need to save anything. - if (scope_data_start == kUint32Size) { + if (scope_data_start == kPlaceholderSize) { return; } @@ -250,6 +270,10 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData( SaveDataForScope(scope); } +bool ProducedPreParsedScopeData::ContainsInnerFunctions() const { + return byte_data_->size() > kPlaceholderSize; +} + MaybeHandle<PreParsedScopeData> ProducedPreParsedScopeData::Serialize( Isolate* isolate) { if (!previously_produced_preparsed_scope_data_.is_null()) { @@ -263,7 +287,7 @@ MaybeHandle<PreParsedScopeData> ProducedPreParsedScopeData::Serialize( DCHECK(!ThisOrParentBailedOut()); - if (byte_data_->size() <= kUint32Size) { + if (byte_data_->size() <= kPlaceholderSize) { // The data contains only the placeholder. return MaybeHandle<PreParsedScopeData>(); } @@ -377,14 +401,11 @@ void ProducedPreParsedScopeData::SaveDataForVariable(Variable* var) { byte_data_->WriteUint8(name->raw_data()[i]); } #endif - // FIXME(marja): Only 3 bits needed, not a full byte. - byte variable_data = VariableIsUsedField::encode(var->is_used()) | - VariableMaybeAssignedField::encode( + byte variable_data = VariableMaybeAssignedField::encode( var->maybe_assigned() == kMaybeAssigned) | VariableContextAllocatedField::encode( var->has_forced_context_allocation()); - - byte_data_->WriteUint8(variable_data); + byte_data_->WriteQuarter(variable_data); } void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) { @@ -397,8 +418,8 @@ void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) { if (ScopeIsSkippableFunctionScope(inner)) { // Don't save data about function scopes, since they'll have their own // ProducedPreParsedScopeData where their data is saved. - DCHECK(inner->AsDeclarationScope()->produced_preparsed_scope_data() != - nullptr); + DCHECK_NOT_NULL( + inner->AsDeclarationScope()->produced_preparsed_scope_data()); continue; } scopes.push_back(inner); @@ -424,6 +445,7 @@ int32_t ConsumedPreParsedScopeData::ByteData::ReadUint32() { for (int i = 0; i < 4; ++i) { *p++ = data_->get(index_++); } + stored_quarters_ = 0; return result; } @@ -434,9 +456,29 @@ uint8_t ConsumedPreParsedScopeData::ByteData::ReadUint8() { // Check that there indeed is a byte following. DCHECK_EQ(data_->get(index_++), kUint8Size); #endif + stored_quarters_ = 0; return data_->get(index_++); } +uint8_t ConsumedPreParsedScopeData::ByteData::ReadQuarter() { + DCHECK_NOT_NULL(data_); + if (stored_quarters_ == 0) { + DCHECK_GE(RemainingBytes(), kUint8Size); +#ifdef DEBUG + // Check that there indeed are quarters following. + DCHECK_EQ(data_->get(index_++), kQuarterMarker); +#endif + stored_byte_ = data_->get(index_++); + stored_quarters_ = 4; + } + // Read the first 2 bits from stored_byte_. + uint8_t result = (stored_byte_ >> 6) & 3; + DCHECK_LE(result, 3); + --stored_quarters_; + stored_byte_ <<= 2; + return result; +} + ConsumedPreParsedScopeData::ConsumedPreParsedScopeData() : scope_data_(new ByteData()), child_index_(0) {} @@ -452,7 +494,7 @@ void ConsumedPreParsedScopeData::SetData(Handle<PreParsedScopeData> data) { DCHECK_EQ(scope_data_->ReadUint32(), kMagicValue); #endif // The first data item is scope_data_start. Skip over it. - scope_data_->SetPosition(kUint32Size); + scope_data_->SetPosition(kPlaceholderSize); } ProducedPreParsedScopeData* @@ -472,7 +514,7 @@ ConsumedPreParsedScopeData::GetDataForSkippableFunction( *num_parameters = scope_data_->ReadUint32(); *num_inner_functions = scope_data_->ReadUint32(); - uint8_t language_and_super = scope_data_->ReadUint8(); + uint8_t language_and_super = scope_data_->ReadQuarter(); *language_mode = LanguageMode(LanguageField::decode(language_and_super)); *uses_super_property = UsesSuperField::decode(language_and_super); @@ -513,13 +555,6 @@ void ConsumedPreParsedScopeData::RestoreScopeAllocationData( DCHECK_EQ(scope_data_->RemainingBytes(), 0); } -void ConsumedPreParsedScopeData::SkipFunctionDataForTesting() { - ByteData::ReadingScope reading_scope(this); - scope_data_->SetPosition(0); - uint32_t scope_data_start = scope_data_->ReadUint32(); - scope_data_->SetPosition(scope_data_start); -} - void ConsumedPreParsedScopeData::RestoreData(Scope* scope) { if (scope->is_declaration_scope() && scope->AsDeclarationScope()->is_skipped_function()) { @@ -576,15 +611,12 @@ void ConsumedPreParsedScopeData::RestoreDataForVariable(Variable* var) { DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]); } #endif - CHECK_GE(scope_data_->RemainingBytes(), kUint8Size); - uint8_t variable_data = scope_data_->ReadUint8(); - if (VariableIsUsedField::decode(variable_data)) { - var->set_is_used(); - } + uint8_t variable_data = scope_data_->ReadQuarter(); if (VariableMaybeAssignedField::decode(variable_data)) { var->set_maybe_assigned(); } if (VariableContextAllocatedField::decode(variable_data)) { + var->set_is_used(); var->ForceContextAllocation(); } } diff --git a/deps/v8/src/parsing/preparsed-scope-data.h b/deps/v8/src/parsing/preparsed-scope-data.h index 290bfba2fd..b621f069d2 100644 --- a/deps/v8/src/parsing/preparsed-scope-data.h +++ b/deps/v8/src/parsing/preparsed-scope-data.h @@ -69,10 +69,12 @@ class ProducedPreParsedScopeData : public ZoneObject { public: class ByteData : public ZoneObject { public: - explicit ByteData(Zone* zone) : backing_store_(zone) {} + explicit ByteData(Zone* zone) + : backing_store_(zone), free_quarters_in_last_byte_(0) {} void WriteUint32(uint32_t data); void WriteUint8(uint8_t data); + void WriteQuarter(uint8_t data); // For overwriting previously written data at position 0. void OverwriteFirstUint32(uint32_t data); @@ -83,6 +85,7 @@ class ProducedPreParsedScopeData : public ZoneObject { private: ZoneChunkList<uint8_t> backing_store_; + uint8_t free_quarters_in_last_byte_; }; // Create a ProducedPreParsedScopeData object which will collect data as we @@ -142,6 +145,8 @@ class ProducedPreParsedScopeData : public ZoneObject { } #endif // DEBUG + bool ContainsInnerFunctions() const; + // If there is data (if the Scope contains skippable inner functions), move // the data into the heap and return a Handle to it; otherwise return a null // MaybeHandle. @@ -179,7 +184,8 @@ class ConsumedPreParsedScopeData { public: class ByteData { public: - ByteData() : data_(nullptr), index_(0) {} + ByteData() + : data_(nullptr), index_(0), stored_quarters_(0), stored_byte_(0) {} // Reading from the ByteData is only allowed when a ReadingScope is on the // stack. This ensures that we have a DisallowHeapAllocation in place @@ -202,6 +208,7 @@ class ConsumedPreParsedScopeData { int32_t ReadUint32(); uint8_t ReadUint8(); + uint8_t ReadQuarter(); size_t RemainingBytes() const { DCHECK_NOT_NULL(data_); @@ -211,6 +218,8 @@ class ConsumedPreParsedScopeData { // private: PodArray<uint8_t>* data_; int index_; + uint8_t stored_quarters_; + uint8_t stored_byte_; }; ConsumedPreParsedScopeData(); @@ -229,11 +238,6 @@ class ConsumedPreParsedScopeData { // subscopes') variables. void RestoreScopeAllocationData(DeclarationScope* scope); - // Skips the data about skippable functions, moves straight to the scope - // allocation data. Useful for tests which don't want to verify only the scope - // allocation data. - void SkipFunctionDataForTesting(); - private: void RestoreData(Scope* scope); void RestoreDataForVariable(Variable* var); diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc index c31fd4af8e..16879e518c 100644 --- a/deps/v8/src/parsing/preparser.cc +++ b/deps/v8/src/parsing/preparser.cc @@ -87,7 +87,7 @@ PreParserIdentifier PreParser::GetSymbol() const { return symbol; } -PreParser::PreParseResult PreParser::PreParseProgram(bool is_module) { +PreParser::PreParseResult PreParser::PreParseProgram() { DCHECK_NULL(scope_); DeclarationScope* scope = NewScriptScope(); #ifdef DEBUG @@ -97,13 +97,12 @@ PreParser::PreParseResult PreParser::PreParseProgram(bool is_module) { // ModuleDeclarationInstantiation for Source Text Module Records creates a // new Module Environment Record whose outer lexical environment record is // the global scope. - if (is_module) scope = NewModuleScope(scope); + if (parsing_module_) scope = NewModuleScope(scope); FunctionState top_scope(&function_state_, &scope_, scope); original_scope_ = scope_; bool ok = true; int start_position = scanner()->peek_location().beg_pos; - parsing_module_ = is_module; PreParserStatementList body; ParseStatementList(body, Token::EOS, &ok); original_scope_ = nullptr; @@ -119,14 +118,14 @@ PreParser::PreParseResult PreParser::PreParseProgram(bool is_module) { PreParser::PreParseResult PreParser::PreParseFunction( const AstRawString* function_name, FunctionKind kind, FunctionLiteral::FunctionType function_type, - DeclarationScope* function_scope, bool parsing_module, - bool is_inner_function, bool may_abort, int* use_counts, - ProducedPreParsedScopeData** produced_preparsed_scope_data) { + DeclarationScope* function_scope, bool is_inner_function, bool may_abort, + int* use_counts, ProducedPreParsedScopeData** produced_preparsed_scope_data, + int script_id) { DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type()); - parsing_module_ = parsing_module; use_counts_ = use_counts; DCHECK(!track_unresolved_variables_); track_unresolved_variables_ = is_inner_function; + set_script_id(script_id); #ifdef DEBUG function_scope->set_is_being_lazily_parsed(true); #endif @@ -208,7 +207,7 @@ PreParser::PreParseResult PreParser::PreParseFunction( if (!IsArrowFunction(kind) && track_unresolved_variables_ && result == kLazyParsingComplete) { - CreateFunctionNameAssignment(function_name, function_type, function_scope); + DeclareFunctionNameVar(function_name, function_type, function_scope); // Declare arguments after parsing the function since lexical 'arguments' // masks the arguments object. Declare arguments before declaring the @@ -224,7 +223,7 @@ PreParser::PreParseResult PreParser::PreParseFunction( } else if (stack_overflow()) { return kPreParseStackOverflow; } else if (!*ok) { - DCHECK(pending_error_handler_->has_pending_error()); + DCHECK(pending_error_handler()->has_pending_error()); } else { DCHECK_EQ(Token::RBRACE, scanner()->peek()); @@ -279,6 +278,9 @@ PreParser::Expression PreParser::ParseFunctionLiteral( runtime_call_stats_, counters[track_unresolved_variables_][parsing_on_main_thread_]); + base::ElapsedTimer timer; + if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); + DeclarationScope* function_scope = NewFunctionScope(kind); function_scope->SetLanguageMode(language_mode); @@ -344,11 +346,23 @@ PreParser::Expression PreParser::ParseFunctionLiteral( produced_preparsed_scope_data_scope->MarkFunctionAsSkippable( end_position, GetLastFunctionLiteralId() - func_id); } - if (FLAG_trace_preparse) { - PrintF(" [%s]: %i-%i\n", - track_unresolved_variables_ ? "Preparse resolution" - : "Preparse no-resolution", - function_scope->start_position(), function_scope->end_position()); + if (V8_UNLIKELY(FLAG_log_function_events)) { + double ms = timer.Elapsed().InMillisecondsF(); + const char* event_name = track_unresolved_variables_ + ? "preparse-resolution" + : "preparse-no-resolution"; + // We might not always get a function name here. However, it can be easily + // reconstructed from the script id and the byte range in the log processor. + const char* name = ""; + size_t name_byte_length = 0; + const AstRawString* string = function_name.string_; + if (string != nullptr) { + name = reinterpret_cast<const char*>(string->raw_data()); + name_byte_length = string->byte_length(); + } + logger_->FunctionEvent( + event_name, nullptr, script_id(), ms, function_scope->start_position(), + function_scope->end_position(), name, name_byte_length); } return Expression::Default(); diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h index 275c5e9e0b..8c1d183fd6 100644 --- a/deps/v8/src/parsing/preparser.h +++ b/deps/v8/src/parsing/preparser.h @@ -192,6 +192,17 @@ class PreParserExpression { ExpressionTypeField::encode(kCallEvalExpression)); } + static PreParserExpression CallTaggedTemplate() { + return PreParserExpression( + TypeField::encode(kExpression) | + ExpressionTypeField::encode(kCallTaggedTemplateExpression)); + } + + bool is_tagged_template() const { + DCHECK(IsCall()); + return ExpressionTypeField::decode(code_) == kCallTaggedTemplateExpression; + } + static PreParserExpression SuperCallReference() { return PreParserExpression( TypeField::encode(kExpression) | @@ -255,7 +266,13 @@ class PreParserExpression { bool IsCall() const { return TypeField::decode(code_) == kExpression && (ExpressionTypeField::decode(code_) == kCallExpression || - ExpressionTypeField::decode(code_) == kCallEvalExpression); + ExpressionTypeField::decode(code_) == kCallEvalExpression || + ExpressionTypeField::decode(code_) == + kCallTaggedTemplateExpression); + } + PreParserExpression* AsCall() { + if (IsCall()) return this; + return nullptr; } bool IsSuperCallReference() const { @@ -286,6 +303,7 @@ class PreParserExpression { int position() const { return kNoSourcePosition; } void set_function_token_position(int position) {} + void set_scope(Scope* scope) {} private: enum Type { @@ -304,6 +322,7 @@ class PreParserExpression { kPropertyExpression, kCallExpression, kCallEvalExpression, + kCallTaggedTemplateExpression, kSuperCallReference, kAssignment }; @@ -382,7 +401,7 @@ inline void PreParserList<PreParserExpression>::Add( const PreParserExpression& expression, Zone* zone) { if (expression.variables_ != nullptr) { DCHECK(FLAG_lazy_inner_functions); - DCHECK(zone != nullptr); + DCHECK_NOT_NULL(zone); if (variables_ == nullptr) { variables_ = new (zone) ZoneList<VariableProxy*>(1, zone); } @@ -524,6 +543,9 @@ class PreParserFactory { PreParserExpression NewUndefinedLiteral(int pos) { return PreParserExpression::Default(); } + PreParserExpression NewTheHoleLiteral() { + return PreParserExpression::Default(); + } PreParserExpression NewRegExpLiteral(const PreParserIdentifier& js_pattern, int js_flags, int pos) { return PreParserExpression::Default(); @@ -583,7 +605,7 @@ class PreParserFactory { return PreParserExpression::Default(); } PreParserExpression NewRewritableExpression( - const PreParserExpression& expression) { + const PreParserExpression& expression, Scope* scope) { return expression; } PreParserExpression NewAssignment(Token::Value op, @@ -624,6 +646,11 @@ class PreParserFactory { } return PreParserExpression::Call(); } + PreParserExpression NewTaggedTemplate( + PreParserExpression expression, const PreParserExpressionList& arguments, + int pos) { + return PreParserExpression::CallTaggedTemplate(); + } PreParserExpression NewCallNew(const PreParserExpression& expression, const PreParserExpressionList& arguments, int pos) { @@ -805,6 +832,7 @@ struct ParserTypes<PreParser> { typedef PreParserExpression ObjectLiteralProperty; typedef PreParserExpression ClassLiteralProperty; typedef PreParserExpression Suspend; + typedef PreParserExpression RewritableExpression; typedef PreParserExpressionList ExpressionList; typedef PreParserExpressionList ObjectPropertyList; typedef PreParserExpressionList ClassPropertyList; @@ -854,14 +882,15 @@ class PreParser : public ParserBase<PreParser> { PreParser(Zone* zone, Scanner* scanner, uintptr_t stack_limit, AstValueFactory* ast_value_factory, PendingCompilationErrorHandler* pending_error_handler, - RuntimeCallStats* runtime_call_stats, + RuntimeCallStats* runtime_call_stats, Logger* logger, + int script_id = -1, bool parsing_module = false, bool parsing_on_main_thread = true) : ParserBase<PreParser>(zone, scanner, stack_limit, nullptr, - ast_value_factory, runtime_call_stats, - parsing_on_main_thread), + ast_value_factory, pending_error_handler, + runtime_call_stats, logger, script_id, + parsing_module, parsing_on_main_thread), use_counts_(nullptr), track_unresolved_variables_(false), - pending_error_handler_(pending_error_handler), produced_preparsed_scope_data_(nullptr) {} static bool IsPreParser() { return true; } @@ -872,7 +901,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); + PreParseResult PreParseProgram(); // Parses a single function literal, from the opening parentheses before // parameters to the closing brace after the body. @@ -885,9 +914,10 @@ class PreParser : public ParserBase<PreParser> { PreParseResult PreParseFunction( const AstRawString* function_name, FunctionKind kind, FunctionLiteral::FunctionType function_type, - DeclarationScope* function_scope, bool parsing_module, - bool track_unresolved_variables, bool may_abort, int* use_counts, - ProducedPreParsedScopeData** produced_preparser_scope_data); + DeclarationScope* function_scope, bool track_unresolved_variables, + bool may_abort, int* use_counts, + ProducedPreParsedScopeData** produced_preparser_scope_data, + int script_id); ProducedPreParsedScopeData* produced_preparsed_scope_data() const { return produced_preparsed_scope_data_; @@ -914,6 +944,10 @@ class PreParser : public ParserBase<PreParser> { bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; } bool parse_lazily() const { return false; } + PendingCompilationErrorHandler* pending_error_handler() { + return pending_error_handler_; + } + V8_INLINE LazyParsingResult SkipFunction(const AstRawString* name, FunctionKind kind, FunctionLiteral::FunctionType function_type, @@ -922,11 +956,12 @@ class PreParser : public ParserBase<PreParser> { bool is_inner_function, bool may_abort, bool* ok) { UNREACHABLE(); } - Expression ParseFunctionLiteral( - Identifier name, Scanner::Location function_name_location, - FunctionNameValidity function_name_validity, FunctionKind kind, - int function_token_pos, FunctionLiteral::FunctionType function_type, - LanguageMode language_mode, bool* ok); + Expression ParseFunctionLiteral(Identifier name, + Scanner::Location function_name_location, + FunctionNameValidity function_name_validity, + FunctionKind kind, int function_token_pos, + FunctionLiteral::FunctionType function_type, + LanguageMode language_mode, bool* ok); LazyParsingResult ParseStatementListAndLogFunction( PreParserFormalParameters* formals, bool maybe_abort, bool* ok); @@ -960,17 +995,6 @@ class PreParser : public ParserBase<PreParser> { V8_INLINE void RewriteDestructuringAssignments() {} - V8_INLINE PreParserExpression - RewriteExponentiation(const PreParserExpression& left, - const PreParserExpression& right, int pos) { - return left; - } - V8_INLINE PreParserExpression - RewriteAssignExponentiation(const PreParserExpression& left, - const PreParserExpression& right, int pos) { - return left; - } - V8_INLINE void PrepareGeneratorVariables() {} V8_INLINE void RewriteAsyncFunctionBody( PreParserStatementList body, PreParserStatement block, @@ -1038,27 +1062,24 @@ class PreParser : public ParserBase<PreParser> { int pos, FunctionKind kind, PreParserStatementList body, bool* ok) { ParseStatementList(body, Token::RBRACE, ok); } - V8_INLINE void CreateFunctionNameAssignment( + V8_INLINE void DeclareFunctionNameVar( const AstRawString* function_name, FunctionLiteral::FunctionType function_type, DeclarationScope* function_scope) { if (track_unresolved_variables_ && - function_type == FunctionLiteral::kNamedExpression) { - if (function_scope->LookupLocal(function_name) == nullptr) { - DCHECK_EQ(function_scope, scope()); - Variable* fvar = function_scope->DeclareFunctionVar(function_name); - fvar->set_is_used(); - } + function_type == FunctionLiteral::kNamedExpression && + function_scope->LookupLocal(function_name) == nullptr) { + DCHECK_EQ(function_scope, scope()); + function_scope->DeclareFunctionVar(function_name); } } - V8_INLINE void CreateFunctionNameAssignment( - const PreParserIdentifier& function_name, int pos, + V8_INLINE void DeclareFunctionNameVar( + const PreParserIdentifier& function_name, FunctionLiteral::FunctionType function_type, - DeclarationScope* function_scope, PreParserStatementList result, - int index) { - CreateFunctionNameAssignment(function_name.string_, function_type, - function_scope); + DeclarationScope* function_scope) { + DeclareFunctionNameVar(function_name.string_, function_type, + function_scope); } V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body, @@ -1118,7 +1139,16 @@ class PreParser : public ParserBase<PreParser> { const PreParserExpression& property, ClassLiteralProperty::Kind kind, bool is_static, bool is_constructor, - ClassInfo* class_info, bool* ok) {} + bool is_computed_name, + ClassInfo* class_info, bool* ok) { + if (kind == ClassLiteralProperty::FIELD && is_computed_name) { + scope()->DeclareVariableName( + ClassFieldVariableName(ast_value_factory(), + class_info->computed_field_count), + CONST); + } + } + V8_INLINE PreParserExpression RewriteClassLiteral(Scope* scope, const PreParserIdentifier& name, ClassInfo* class_info, int pos, int end_pos, bool* ok) { @@ -1134,12 +1164,18 @@ class PreParser : public ParserBase<PreParser> { FunctionKind kind = has_extends ? FunctionKind::kDefaultDerivedConstructor : FunctionKind::kDefaultBaseConstructor; DeclarationScope* function_scope = NewFunctionScope(kind); - SetLanguageMode(function_scope, STRICT); + SetLanguageMode(function_scope, LanguageMode::kStrict); function_scope->set_start_position(pos); function_scope->set_end_position(pos); FunctionState function_state(&function_state_, &scope_, function_scope); GetNextFunctionLiteralId(); } + if (class_info->has_static_class_fields) { + GetNextFunctionLiteralId(); + } + if (class_info->has_instance_class_fields) { + GetNextFunctionLiteralId(); + } return PreParserExpression::Default(); } @@ -1265,6 +1301,13 @@ class PreParser : public ParserBase<PreParser> { return false; } + V8_INLINE NaryOperation* CollapseNaryExpression(PreParserExpression* x, + PreParserExpression y, + Token::Value op, int pos, + const SourceRange& range) { + return nullptr; + } + V8_INLINE PreParserExpression BuildUnaryExpression( const PreParserExpression& expression, Token::Value op, int pos) { return PreParserExpression::Default(); @@ -1381,13 +1424,13 @@ class PreParser : public ParserBase<PreParser> { } // Reporting errors. - V8_INLINE void ReportMessageAt(Scanner::Location source_location, - MessageTemplate::Template message, - const char* arg = NULL, - ParseErrorType error_type = kSyntaxError) { - pending_error_handler_->ReportMessageAt(source_location.beg_pos, - source_location.end_pos, message, - arg, error_type); + void ReportMessageAt(Scanner::Location source_location, + MessageTemplate::Template message, + const char* arg = nullptr, + ParseErrorType error_type = kSyntaxError) { + pending_error_handler()->ReportMessageAt(source_location.beg_pos, + source_location.end_pos, message, + arg, error_type); } V8_INLINE void ReportMessageAt(Scanner::Location source_location, @@ -1427,15 +1470,6 @@ class PreParser : public ParserBase<PreParser> { return PreParserIdentifier::Default(); } - // Odd-ball literal creators. - V8_INLINE PreParserExpression GetLiteralTheHole(int position) { - return PreParserExpression::Default(); - } - - V8_INLINE PreParserExpression GetLiteralUndefined(int position) { - return PreParserExpression::Default(); - } - // Producing data during the recursive descent. PreParserIdentifier GetSymbol() const; @@ -1495,6 +1529,10 @@ class PreParser : public ParserBase<PreParser> { return PreParserExpression::Default(); } + V8_INLINE PreParserExpression ImportMetaExpression(int pos) { + return PreParserExpression::Default(); + } + V8_INLINE PreParserExpression ExpressionFromLiteral(Token::Value token, int pos) { return PreParserExpression::Default(); @@ -1650,7 +1688,6 @@ class PreParser : public ParserBase<PreParser> { int* use_counts_; bool track_unresolved_variables_; PreParserLogger log_; - PendingCompilationErrorHandler* pending_error_handler_; ProducedPreParsedScopeData* produced_preparsed_scope_data_; }; diff --git a/deps/v8/src/parsing/rewriter.cc b/deps/v8/src/parsing/rewriter.cc index ddf60a5004..c31d0ea21d 100644 --- a/deps/v8/src/parsing/rewriter.cc +++ b/deps/v8/src/parsing/rewriter.cc @@ -263,6 +263,9 @@ void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone()); node->finally_block()->statements()->Add( factory()->NewExpressionStatement(restore, kNoSourcePosition), zone()); + // We can't tell whether the finally-block is guaranteed to set .result, so + // reset is_set_ before visiting the try-block. + is_set_ = false; } Visit(node->try_block()); node->set_try_block(replacement_->AsBlock()); @@ -335,6 +338,10 @@ void Processor::VisitDebuggerStatement(DebuggerStatement* node) { replacement_ = node; } +void Processor::VisitInitializeClassFieldsStatement( + InitializeClassFieldsStatement* node) { + replacement_ = node; +} // Expressions are never visited. #define DEF_VISIT(type) \ @@ -359,7 +366,9 @@ bool Rewriter::Rewrite(ParseInfo* info) { RuntimeCallTimerScope runtimeTimer( info->runtime_call_stats(), - &RuntimeCallStats::CompileRewriteReturnResult); + info->on_background_thread() + ? &RuntimeCallStats::CompileBackgroundRewriteReturnResult + : &RuntimeCallStats::CompileRewriteReturnResult); FunctionLiteral* function = info->literal(); DCHECK_NOT_NULL(function); diff --git a/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc index 5229aed780..c5175c4de7 100644 --- a/deps/v8/src/parsing/scanner-character-streams.cc +++ b/deps/v8/src/parsing/scanner-character-streams.cc @@ -310,7 +310,7 @@ void Utf8ExternalStreamingStream::FillBufferFromCurrentChunk() { unibrow::uchar t = unibrow::Utf8::ValueOfIncrementalFinish(¤t_.pos.incomplete_char); if (t != unibrow::Utf8::kBufferEmpty) { - DCHECK(t < unibrow::Utf16::kMaxNonSurrogateCharCode); + DCHECK_LT(t, unibrow::Utf16::kMaxNonSurrogateCharCode); *cursor = static_cast<uc16>(t); buffer_end_++; current_.pos.chars++; @@ -835,9 +835,9 @@ 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()); + DCHECK_GE(start_pos, 0); + DCHECK_LE(start_pos, end_pos); + DCHECK_LE(end_pos, data->length()); if (data->IsExternalOneByteString()) { return new ExternalOneByteStringUtf16CharacterStream( Handle<ExternalOneByteString>::cast(data), diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc index f0ce0012ae..8030b93889 100644 --- a/deps/v8/src/parsing/scanner.cc +++ b/deps/v8/src/parsing/scanner.cc @@ -13,6 +13,7 @@ #include "src/ast/ast-value-factory.h" #include "src/char-predicates-inl.h" #include "src/conversions-inl.h" +#include "src/objects/bigint.h" #include "src/parsing/duplicate-finder.h" // For Scanner::FindSymbol #include "src/unicode-cache-inl.h" @@ -196,6 +197,7 @@ Scanner::Scanner(UnicodeCache* unicode_cache, int* use_counts) octal_pos_(Location::invalid()), octal_message_(MessageTemplate::kNone), found_html_comment_(false), + allow_harmony_bigint_(false), use_counts_(use_counts) {} void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) { @@ -211,7 +213,7 @@ void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) { template <bool capture_raw, bool unicode> uc32 Scanner::ScanHexNumber(int expected_length) { - DCHECK(expected_length <= 4); // prevent overflow + DCHECK_LE(expected_length, 4); // prevent overflow int begin = source_pos() - 2; uc32 x = 0; @@ -582,7 +584,7 @@ void Scanner::TryToParseSourceURLComment() { Token::Value Scanner::SkipMultiLineComment() { - DCHECK(c0_ == '*'); + DCHECK_EQ(c0_, '*'); Advance(); while (c0_ != kEndOfInput) { @@ -608,7 +610,7 @@ Token::Value Scanner::SkipMultiLineComment() { Token::Value Scanner::ScanHtmlComment() { // Check for <!-- comments. - DCHECK(c0_ == '!'); + DCHECK_EQ(c0_, '!'); Advance(); if (c0_ != '-') { PushBack('!'); // undo Advance() @@ -626,8 +628,8 @@ Token::Value Scanner::ScanHtmlComment() { } void Scanner::Scan() { - next_.literal_chars = NULL; - next_.raw_literal_chars = NULL; + next_.literal_chars = nullptr; + next_.raw_literal_chars = nullptr; next_.invalid_template_escape_message = MessageTemplate::kNone; Token::Value token; do { @@ -934,6 +936,7 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const { case Token::FUTURE_STRICT_RESERVED_WORD: case Token::IDENTIFIER: case Token::NUMBER: + case Token::BIGINT: case Token::REGEXP_LITERAL: case Token::SMI: case Token::STRING: @@ -1185,8 +1188,8 @@ Token::Value Scanner::ScanTemplateSpan() { Token::Value Scanner::ScanTemplateStart() { - DCHECK(next_next_.token == Token::UNINITIALIZED); - DCHECK(c0_ == '`'); + DCHECK_EQ(next_next_.token, Token::UNINITIALIZED); + DCHECK_EQ(c0_, '`'); next_.location.beg_pos = source_pos(); Advance(); // Consume ` return ScanTemplateSpan(); @@ -1321,14 +1324,31 @@ Token::Value Scanner::ScanNumber(bool seen_period) { ScanDecimalDigits(); // optional if (c0_ == '.') { + seen_period = true; AddLiteralCharAdvance(); ScanDecimalDigits(); // optional } } } - // scan exponent, if any - if (c0_ == 'e' || c0_ == 'E') { + bool is_bigint = false; + if (allow_harmony_bigint() && c0_ == 'n' && !seen_period && + (kind == DECIMAL || kind == HEX || kind == OCTAL || kind == BINARY)) { + // Check that the literal is within our limits for BigInt length. + // For simplicity, use 4 bits per character to calculate the maximum + // allowed literal length. + static const int kMaxBigIntCharacters = BigInt::kMaxLengthBits / 4; + int length = source_pos() - start_pos - (kind != DECIMAL ? 2 : 0); + if (length > kMaxBigIntCharacters) { + ReportScannerError(Location(start_pos, source_pos()), + MessageTemplate::kBigIntTooBig); + return Token::ILLEGAL; + } + + is_bigint = true; + Advance(); + } else if (c0_ == 'e' || c0_ == 'E') { + // scan exponent, if any DCHECK(kind != HEX); // 'e'/'E' must be scanned as part of the hex number if (!(kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO)) return Token::ILLEGAL; @@ -1357,7 +1377,8 @@ Token::Value Scanner::ScanNumber(bool seen_period) { octal_pos_ = Location(start_pos, source_pos()); octal_message_ = MessageTemplate::kStrictDecimalWithLeadingZero; } - return Token::NUMBER; + + return is_bigint ? Token::BIGINT : Token::NUMBER; } @@ -1481,7 +1502,7 @@ uc32 Scanner::ScanUnicodeEscape() { static Token::Value KeywordOrIdentifierToken(const uint8_t* input, int input_length) { - DCHECK(input_length >= 1); + DCHECK_GE(input_length, 1); const int kMinLength = 2; const int kMaxLength = 11; if (input_length < kMinLength || input_length > kMaxLength) { @@ -1728,11 +1749,7 @@ Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() { flag = RegExp::kMultiline; break; case 's': - if (FLAG_harmony_regexp_dotall) { - flag = RegExp::kDotAll; - } else { - return Nothing<RegExp::Flags>(); - } + flag = RegExp::kDotAll; break; case 'u': flag = RegExp::kUnicode; @@ -1787,6 +1804,16 @@ double Scanner::DoubleValue() { ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY); } +const char* Scanner::CurrentLiteralAsCString(Zone* zone) const { + DCHECK(is_literal_one_byte()); + Vector<const uint8_t> vector = literal_one_byte_string(); + int length = vector.length(); + char* buffer = zone->NewArray<char>(length + 1); + memcpy(buffer, vector.start(), length); + buffer[length] = '\0'; + return buffer; +} + 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 200054d893..08d77c686b 100644 --- a/deps/v8/src/parsing/scanner.h +++ b/deps/v8/src/parsing/scanner.h @@ -260,6 +260,8 @@ class Scanner { double DoubleValue(); + const char* CurrentLiteralAsCString(Zone* zone) const; + inline bool CurrentMatches(Token::Value token) const { DCHECK(Token::IsKeyword(token)); return current_.token == token; @@ -356,6 +358,9 @@ class Scanner { bool FoundHtmlComment() const { return found_html_comment_; } + bool allow_harmony_bigint() const { return allow_harmony_bigint_; } + void set_allow_harmony_bigint(bool allow) { allow_harmony_bigint_ = allow; } + private: // Scoped helper for saving & restoring scanner error state. // This is used for tagged template literals, in which normally forbidden @@ -409,7 +414,7 @@ class Scanner { Vector<const uint16_t> two_byte_literal() const { DCHECK(!is_one_byte_); - DCHECK((position_ & 0x1) == 0); + DCHECK_EQ(position_ & 0x1, 0); return Vector<const uint16_t>( reinterpret_cast<const uint16_t*>(backing_store_.start()), position_ >> 1); @@ -494,18 +499,18 @@ class Scanner { // Initialize current_ to not refer to a literal. current_.token = Token::UNINITIALIZED; current_.contextual_token = Token::UNINITIALIZED; - current_.literal_chars = NULL; - current_.raw_literal_chars = NULL; + current_.literal_chars = nullptr; + current_.raw_literal_chars = nullptr; current_.invalid_template_escape_message = MessageTemplate::kNone; next_.token = Token::UNINITIALIZED; next_.contextual_token = Token::UNINITIALIZED; - next_.literal_chars = NULL; - next_.raw_literal_chars = NULL; + next_.literal_chars = nullptr; + next_.raw_literal_chars = nullptr; next_.invalid_template_escape_message = MessageTemplate::kNone; next_next_.token = Token::UNINITIALIZED; next_next_.contextual_token = Token::UNINITIALIZED; - next_next_.literal_chars = NULL; - next_next_.raw_literal_chars = NULL; + next_next_.literal_chars = nullptr; + next_next_.raw_literal_chars = nullptr; next_next_.invalid_template_escape_message = MessageTemplate::kNone; found_html_comment_ = false; scanner_error_ = MessageTemplate::kNone; @@ -572,8 +577,8 @@ class Scanner { // Stops scanning of a literal and drop the collected characters, // e.g., due to an encountered error. inline void DropLiteral() { - next_.literal_chars = NULL; - next_.raw_literal_chars = NULL; + next_.literal_chars = nullptr; + next_.raw_literal_chars = nullptr; } inline void AddLiteralCharAdvance() { @@ -662,10 +667,6 @@ class Scanner { bool is_literal_one_byte() const { return !current_.literal_chars || current_.literal_chars->is_one_byte(); } - int literal_length() const { - if (current_.literal_chars) return current_.literal_chars->length(); - return Token::StringLength(current_.token); - } // Returns the literal string for the next token (the token that // would be returned if Next() were called). Vector<const uint8_t> next_literal_one_byte_string() const { @@ -801,6 +802,9 @@ class Scanner { // Whether this scanner encountered an HTML comment. bool found_html_comment_; + // Whether to recognize BIGINT tokens. + bool allow_harmony_bigint_; + int* use_counts_; MessageTemplate::Template scanner_error_; diff --git a/deps/v8/src/parsing/token.h b/deps/v8/src/parsing/token.h index 4cc4db288a..e4a4a5e587 100644 --- a/deps/v8/src/parsing/token.h +++ b/deps/v8/src/parsing/token.h @@ -14,7 +14,7 @@ namespace internal { // TOKEN_LIST takes a list of 3 macros M, all of which satisfy the // same signature M(name, string, precedence), where name is the // symbolic token name, string is the corresponding syntactic symbol -// (or NULL, for literals), and precedence is the precedence (or 0). +// (or nullptr, for literals), and precedence is the precedence (or 0). // The parameters are invoked for token categories as follows: // // T: Non-keyword tokens @@ -32,171 +32,172 @@ namespace internal { #define IGNORE_TOKEN(name, string, precedence) -#define TOKEN_LIST(T, K, C) \ - /* End of source indicator. */ \ - T(EOS, "EOS", 0) \ - \ - /* Punctuators (ECMA-262, section 7.7, page 15). */ \ - T(LPAREN, "(", 0) \ - T(RPAREN, ")", 0) \ - T(LBRACK, "[", 0) \ - T(RBRACK, "]", 0) \ - T(LBRACE, "{", 0) \ - T(RBRACE, "}", 0) \ - T(COLON, ":", 0) \ - T(SEMICOLON, ";", 0) \ - T(PERIOD, ".", 0) \ - T(ELLIPSIS, "...", 0) \ - T(CONDITIONAL, "?", 3) \ - T(INC, "++", 0) \ - T(DEC, "--", 0) \ - T(ARROW, "=>", 0) \ - \ - /* Assignment operators. */ \ - /* IsAssignmentOp() relies on this block of enum values being */ \ - /* contiguous and sorted in the same order! */ \ - T(INIT, "=init", 2) /* AST-use only. */ \ - T(ASSIGN, "=", 2) \ - T(ASSIGN_BIT_OR, "|=", 2) \ - T(ASSIGN_BIT_XOR, "^=", 2) \ - T(ASSIGN_BIT_AND, "&=", 2) \ - T(ASSIGN_SHL, "<<=", 2) \ - T(ASSIGN_SAR, ">>=", 2) \ - T(ASSIGN_SHR, ">>>=", 2) \ - T(ASSIGN_ADD, "+=", 2) \ - T(ASSIGN_SUB, "-=", 2) \ - T(ASSIGN_MUL, "*=", 2) \ - T(ASSIGN_DIV, "/=", 2) \ - T(ASSIGN_MOD, "%=", 2) \ - T(ASSIGN_EXP, "**=", 2) \ - \ - /* Binary operators sorted by precedence. */ \ - /* IsBinaryOp() relies on this block of enum values */ \ - /* being contiguous and sorted in the same order! */ \ - T(COMMA, ",", 1) \ - T(OR, "||", 4) \ - T(AND, "&&", 5) \ - T(BIT_OR, "|", 6) \ - T(BIT_XOR, "^", 7) \ - T(BIT_AND, "&", 8) \ - T(SHL, "<<", 11) \ - T(SAR, ">>", 11) \ - T(SHR, ">>>", 11) \ - T(ADD, "+", 12) \ - T(SUB, "-", 12) \ - T(MUL, "*", 13) \ - T(DIV, "/", 13) \ - T(MOD, "%", 13) \ - T(EXP, "**", 14) \ - \ - /* Compare operators sorted by precedence. */ \ - /* IsCompareOp() relies on this block of enum values */ \ - /* being contiguous and sorted in the same order! */ \ - T(EQ, "==", 9) \ - T(NE, "!=", 9) \ - T(EQ_STRICT, "===", 9) \ - T(NE_STRICT, "!==", 9) \ - T(LT, "<", 10) \ - T(GT, ">", 10) \ - T(LTE, "<=", 10) \ - T(GTE, ">=", 10) \ - K(INSTANCEOF, "instanceof", 10) \ - K(IN, "in", 10) \ - \ - /* Unary operators. */ \ - /* IsUnaryOp() relies on this block of enum values */ \ - /* being contiguous and sorted in the same order! */ \ - T(NOT, "!", 0) \ - T(BIT_NOT, "~", 0) \ - K(DELETE, "delete", 0) \ - K(TYPEOF, "typeof", 0) \ - K(VOID, "void", 0) \ - \ - /* Keywords (ECMA-262, section 7.5.2, page 13). */ \ - K(BREAK, "break", 0) \ - K(CASE, "case", 0) \ - K(CATCH, "catch", 0) \ - K(CONTINUE, "continue", 0) \ - K(DEBUGGER, "debugger", 0) \ - K(DEFAULT, "default", 0) \ - /* DELETE */ \ - K(DO, "do", 0) \ - K(ELSE, "else", 0) \ - K(FINALLY, "finally", 0) \ - K(FOR, "for", 0) \ - K(FUNCTION, "function", 0) \ - K(IF, "if", 0) \ - /* IN */ \ - /* INSTANCEOF */ \ - K(NEW, "new", 0) \ - K(RETURN, "return", 0) \ - K(SWITCH, "switch", 0) \ - K(THIS, "this", 0) \ - K(THROW, "throw", 0) \ - K(TRY, "try", 0) \ - /* TYPEOF */ \ - K(VAR, "var", 0) \ - /* VOID */ \ - K(WHILE, "while", 0) \ - K(WITH, "with", 0) \ - \ - /* Literals (ECMA-262, section 7.8, page 16). */ \ - K(NULL_LITERAL, "null", 0) \ - K(TRUE_LITERAL, "true", 0) \ - K(FALSE_LITERAL, "false", 0) \ - T(NUMBER, NULL, 0) \ - T(SMI, NULL, 0) \ - T(STRING, NULL, 0) \ - \ - /* Identifiers (not keywords or future reserved words). */ \ - T(IDENTIFIER, NULL, 0) \ - \ - /* Future reserved words (ECMA-262, section 7.6.1.2). */ \ - T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \ - K(ASYNC, "async", 0) \ - /* `await` is a reserved word in module code only */ \ - K(AWAIT, "await", 0) \ - K(CLASS, "class", 0) \ - K(CONST, "const", 0) \ - K(ENUM, "enum", 0) \ - K(EXPORT, "export", 0) \ - K(EXTENDS, "extends", 0) \ - K(IMPORT, "import", 0) \ - K(LET, "let", 0) \ - K(STATIC, "static", 0) \ - K(YIELD, "yield", 0) \ - K(SUPER, "super", 0) \ - \ - /* Illegal token - not able to scan. */ \ - T(ILLEGAL, "ILLEGAL", 0) \ - T(ESCAPED_KEYWORD, NULL, 0) \ - T(ESCAPED_STRICT_RESERVED_WORD, NULL, 0) \ - \ - /* Scanner-internal use only. */ \ - T(WHITESPACE, NULL, 0) \ - T(UNINITIALIZED, NULL, 0) \ - T(REGEXP_LITERAL, NULL, 0) \ - \ - /* ES6 Template Literals */ \ - T(TEMPLATE_SPAN, NULL, 0) \ - T(TEMPLATE_TAIL, NULL, 0) \ - \ - /* Contextual keyword tokens */ \ - C(GET, "get", 0) \ - C(SET, "set", 0) \ - C(OF, "of", 0) \ - C(TARGET, "target", 0) \ - C(SENT, "sent", 0) \ - C(META, "meta", 0) \ - C(AS, "as", 0) \ - C(FROM, "from", 0) \ - C(NAME, "name", 0) \ - C(PROTO_UNDERSCORED, "__proto__", 0) \ - C(CONSTRUCTOR, "constructor", 0) \ - C(PROTOTYPE, "prototype", 0) \ - C(EVAL, "eval", 0) \ - C(ARGUMENTS, "arguments", 0) \ - C(UNDEFINED, "undefined", 0) \ +#define TOKEN_LIST(T, K, C) \ + /* End of source indicator. */ \ + T(EOS, "EOS", 0) \ + \ + /* Punctuators (ECMA-262, section 7.7, page 15). */ \ + T(LPAREN, "(", 0) \ + T(RPAREN, ")", 0) \ + T(LBRACK, "[", 0) \ + T(RBRACK, "]", 0) \ + T(LBRACE, "{", 0) \ + T(RBRACE, "}", 0) \ + T(COLON, ":", 0) \ + T(SEMICOLON, ";", 0) \ + T(PERIOD, ".", 0) \ + T(ELLIPSIS, "...", 0) \ + T(CONDITIONAL, "?", 3) \ + T(INC, "++", 0) \ + T(DEC, "--", 0) \ + T(ARROW, "=>", 0) \ + \ + /* Assignment operators. */ \ + /* IsAssignmentOp() relies on this block of enum values being */ \ + /* contiguous and sorted in the same order! */ \ + T(INIT, "=init", 2) /* AST-use only. */ \ + T(ASSIGN, "=", 2) \ + T(ASSIGN_BIT_OR, "|=", 2) \ + T(ASSIGN_BIT_XOR, "^=", 2) \ + T(ASSIGN_BIT_AND, "&=", 2) \ + T(ASSIGN_SHL, "<<=", 2) \ + T(ASSIGN_SAR, ">>=", 2) \ + T(ASSIGN_SHR, ">>>=", 2) \ + T(ASSIGN_ADD, "+=", 2) \ + T(ASSIGN_SUB, "-=", 2) \ + T(ASSIGN_MUL, "*=", 2) \ + T(ASSIGN_DIV, "/=", 2) \ + T(ASSIGN_MOD, "%=", 2) \ + T(ASSIGN_EXP, "**=", 2) \ + \ + /* Binary operators sorted by precedence. */ \ + /* IsBinaryOp() relies on this block of enum values */ \ + /* being contiguous and sorted in the same order! */ \ + T(COMMA, ",", 1) \ + T(OR, "||", 4) \ + T(AND, "&&", 5) \ + T(BIT_OR, "|", 6) \ + T(BIT_XOR, "^", 7) \ + T(BIT_AND, "&", 8) \ + T(SHL, "<<", 11) \ + T(SAR, ">>", 11) \ + T(SHR, ">>>", 11) \ + T(ADD, "+", 12) \ + T(SUB, "-", 12) \ + T(MUL, "*", 13) \ + T(DIV, "/", 13) \ + T(MOD, "%", 13) \ + T(EXP, "**", 14) \ + \ + /* Compare operators sorted by precedence. */ \ + /* IsCompareOp() relies on this block of enum values */ \ + /* being contiguous and sorted in the same order! */ \ + T(EQ, "==", 9) \ + T(NE, "!=", 9) \ + T(EQ_STRICT, "===", 9) \ + T(NE_STRICT, "!==", 9) \ + T(LT, "<", 10) \ + T(GT, ">", 10) \ + T(LTE, "<=", 10) \ + T(GTE, ">=", 10) \ + K(INSTANCEOF, "instanceof", 10) \ + K(IN, "in", 10) \ + \ + /* Unary operators. */ \ + /* IsUnaryOp() relies on this block of enum values */ \ + /* being contiguous and sorted in the same order! */ \ + T(NOT, "!", 0) \ + T(BIT_NOT, "~", 0) \ + K(DELETE, "delete", 0) \ + K(TYPEOF, "typeof", 0) \ + K(VOID, "void", 0) \ + \ + /* Keywords (ECMA-262, section 7.5.2, page 13). */ \ + K(BREAK, "break", 0) \ + K(CASE, "case", 0) \ + K(CATCH, "catch", 0) \ + K(CONTINUE, "continue", 0) \ + K(DEBUGGER, "debugger", 0) \ + K(DEFAULT, "default", 0) \ + /* DELETE */ \ + K(DO, "do", 0) \ + K(ELSE, "else", 0) \ + K(FINALLY, "finally", 0) \ + K(FOR, "for", 0) \ + K(FUNCTION, "function", 0) \ + K(IF, "if", 0) \ + /* IN */ \ + /* INSTANCEOF */ \ + K(NEW, "new", 0) \ + K(RETURN, "return", 0) \ + K(SWITCH, "switch", 0) \ + K(THIS, "this", 0) \ + K(THROW, "throw", 0) \ + K(TRY, "try", 0) \ + /* TYPEOF */ \ + K(VAR, "var", 0) \ + /* VOID */ \ + K(WHILE, "while", 0) \ + K(WITH, "with", 0) \ + \ + /* Literals (ECMA-262, section 7.8, page 16). */ \ + K(NULL_LITERAL, "null", 0) \ + K(TRUE_LITERAL, "true", 0) \ + K(FALSE_LITERAL, "false", 0) \ + T(NUMBER, nullptr, 0) \ + T(SMI, nullptr, 0) \ + T(STRING, nullptr, 0) \ + T(BIGINT, nullptr, 0) \ + \ + /* Identifiers (not keywords or future reserved words). */ \ + T(IDENTIFIER, nullptr, 0) \ + \ + /* Future reserved words (ECMA-262, section 7.6.1.2). */ \ + T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \ + K(ASYNC, "async", 0) \ + /* `await` is a reserved word in module code only */ \ + K(AWAIT, "await", 0) \ + K(CLASS, "class", 0) \ + K(CONST, "const", 0) \ + K(ENUM, "enum", 0) \ + K(EXPORT, "export", 0) \ + K(EXTENDS, "extends", 0) \ + K(IMPORT, "import", 0) \ + K(LET, "let", 0) \ + K(STATIC, "static", 0) \ + K(YIELD, "yield", 0) \ + K(SUPER, "super", 0) \ + \ + /* Illegal token - not able to scan. */ \ + T(ILLEGAL, "ILLEGAL", 0) \ + T(ESCAPED_KEYWORD, nullptr, 0) \ + T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \ + \ + /* Scanner-internal use only. */ \ + T(WHITESPACE, nullptr, 0) \ + T(UNINITIALIZED, nullptr, 0) \ + T(REGEXP_LITERAL, nullptr, 0) \ + \ + /* ES6 Template Literals */ \ + T(TEMPLATE_SPAN, nullptr, 0) \ + T(TEMPLATE_TAIL, nullptr, 0) \ + \ + /* Contextual keyword tokens */ \ + C(GET, "get", 0) \ + C(SET, "set", 0) \ + C(OF, "of", 0) \ + C(TARGET, "target", 0) \ + C(SENT, "sent", 0) \ + C(META, "meta", 0) \ + C(AS, "as", 0) \ + C(FROM, "from", 0) \ + C(NAME, "name", 0) \ + C(PROTO_UNDERSCORED, "__proto__", 0) \ + C(CONSTRUCTOR, "constructor", 0) \ + C(PROTOTYPE, "prototype", 0) \ + C(EVAL, "eval", 0) \ + C(ARGUMENTS, "arguments", 0) \ + C(UNDEFINED, "undefined", 0) \ C(ANONYMOUS, "anonymous", 0) class Token { @@ -246,10 +247,6 @@ class Token { static bool IsBinaryOp(Value op) { return COMMA <= op && op <= EXP; } - static bool IsTruncatingBinaryOp(Value op) { - return BIT_OR <= op && op <= SHR; - } - static bool IsCompareOp(Value op) { return EQ <= op && op <= IN; } @@ -262,62 +259,6 @@ class Token { return op == EQ || op == EQ_STRICT; } - static bool IsInequalityOp(Value op) { - return op == NE || op == NE_STRICT; - } - - static bool IsArithmeticCompareOp(Value op) { - return IsOrderedRelationalCompareOp(op) || - IsEqualityOp(op) || IsInequalityOp(op); - } - - static Value NegateCompareOp(Value op) { - DCHECK(IsArithmeticCompareOp(op)); - switch (op) { - case EQ: return NE; - case NE: return EQ; - case EQ_STRICT: return NE_STRICT; - case NE_STRICT: return EQ_STRICT; - case LT: return GTE; - case GT: return LTE; - case LTE: return GT; - case GTE: return LT; - default: - UNREACHABLE(); - } - } - - static Value ReverseCompareOp(Value op) { - DCHECK(IsArithmeticCompareOp(op)); - switch (op) { - case EQ: return EQ; - case NE: return NE; - case EQ_STRICT: return EQ_STRICT; - case NE_STRICT: return NE_STRICT; - case LT: return GT; - case GT: return LT; - case LTE: return GTE; - case GTE: return LTE; - default: - UNREACHABLE(); - } - } - - static bool EvalComparison(Value op, double op1, double op2) { - DCHECK(IsArithmeticCompareOp(op)); - switch (op) { - case Token::EQ: - case Token::EQ_STRICT: return (op1 == op2); - case Token::NE: return (op1 != op2); - case Token::LT: return (op1 < op2); - case Token::GT: return (op1 > op2); - case Token::LTE: return (op1 <= op2); - case Token::GTE: return (op1 >= op2); - default: - UNREACHABLE(); - } - } - static Value BinaryOpForAssignment(Value op) { DCHECK(IsAssignmentOp(op)); switch (op) { @@ -343,6 +284,8 @@ class Token { return Token::DIV; case Token::ASSIGN_MOD: return Token::MOD; + case Token::ASSIGN_EXP: + return Token::EXP; default: UNREACHABLE(); } @@ -365,7 +308,7 @@ class Token { } // Returns a string corresponding to the JS token string - // (.e., "<" for the token LT) or NULL if the token doesn't + // (.e., "<" for the token LT) or nullptr if the token doesn't // have a (unique) string (e.g. an IDENTIFIER). static const char* String(Value tok) { DCHECK(tok < NUM_TOKENS); // tok is unsigned. |