diff options
Diffstat (limited to 'deps/v8/src/parsing')
21 files changed, 885 insertions, 899 deletions
diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h index 522b650be7..7833dbc8d3 100644 --- a/deps/v8/src/parsing/expression-classifier.h +++ b/deps/v8/src/parsing/expression-classifier.h @@ -7,6 +7,7 @@ #include "src/messages.h" #include "src/parsing/scanner.h" +#include "src/zone/zone-containers.h" namespace v8 { namespace internal { @@ -61,18 +62,15 @@ class ExpressionClassifier { : location(Scanner::Location::invalid()), message(MessageTemplate::kNone), kind(kUnusedError), - type(kSyntaxError), arg(nullptr) {} V8_INLINE explicit Error(Scanner::Location loc, MessageTemplate::Template msg, ErrorKind k, - const char* a = nullptr, - ParseErrorType t = kSyntaxError) - : location(loc), message(msg), kind(k), type(t), arg(a) {} + const char* a = nullptr) + : location(loc), message(msg), kind(k), arg(a) {} Scanner::Location location; - MessageTemplate::Template message : 26; + MessageTemplate::Template message : 28; unsigned kind : 4; - ParseErrorType type : 2; const char* arg; }; @@ -88,10 +86,6 @@ class ExpressionClassifier { }; // clang-format on - enum FunctionProperties : unsigned { - NonSimpleParameter = 1 << 0 - }; - explicit ExpressionClassifier(typename Types::Base* base, DuplicateFinder* duplicate_finder = nullptr) : base_(base), @@ -100,9 +94,9 @@ class ExpressionClassifier { reported_errors_(base->impl()->GetReportedErrorList()), duplicate_finder_(duplicate_finder), invalid_productions_(0), - function_properties_(0) { + is_non_simple_parameter_list_(0) { base->classifier_ = this; - reported_errors_begin_ = reported_errors_end_ = reported_errors_->length(); + reported_errors_begin_ = reported_errors_end_ = reported_errors_->size(); } V8_INLINE ~ExpressionClassifier() { @@ -193,11 +187,11 @@ class ExpressionClassifier { } V8_INLINE bool is_simple_parameter_list() const { - return !(function_properties_ & NonSimpleParameter); + return !is_non_simple_parameter_list_; } V8_INLINE void RecordNonSimpleParameter() { - function_properties_ |= NonSimpleParameter; + is_non_simple_parameter_list_ = 1; } void RecordExpressionError(const Scanner::Location& loc, @@ -208,14 +202,6 @@ class ExpressionClassifier { Add(Error(loc, message, kExpressionProduction, arg)); } - void RecordExpressionError(const Scanner::Location& loc, - MessageTemplate::Template message, - ParseErrorType type, const char* arg = nullptr) { - if (!is_valid_expression()) return; - invalid_productions_ |= ExpressionProduction; - Add(Error(loc, message, kExpressionProduction, arg, type)); - } - void RecordFormalParameterInitializerError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { @@ -292,7 +278,7 @@ class ExpressionClassifier { void Accumulate(ExpressionClassifier* inner, unsigned productions) { DCHECK_EQ(inner->reported_errors_, reported_errors_); DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_); - DCHECK_EQ(inner->reported_errors_end_, reported_errors_->length()); + DCHECK_EQ(inner->reported_errors_end_, reported_errors_->size()); // Propagate errors from inner, but don't overwrite already recorded // errors. unsigned non_arrow_inner_invalid_productions = @@ -305,9 +291,9 @@ class ExpressionClassifier { bool copy_BP_to_AFP = false; if (productions & ArrowFormalParametersProduction && is_valid_arrow_formal_parameters()) { - // Also copy function properties if expecting an arrow function - // parameter. - function_properties_ |= inner->function_properties_; + // Also whether we've seen any non-simple parameters + // if expecting an arrow function parameter. + is_non_simple_parameter_list_ |= inner->is_non_simple_parameter_list_; if (!inner->is_valid_binding_pattern()) { copy_BP_to_AFP = true; invalid_productions_ |= ArrowFormalParametersProduction; @@ -352,14 +338,14 @@ class ExpressionClassifier { } } } - reported_errors_->Rewind(reported_errors_end_); + reported_errors_->resize(reported_errors_end_); inner->reported_errors_begin_ = inner->reported_errors_end_ = reported_errors_end_; } V8_INLINE void Discard() { - if (reported_errors_end_ == reported_errors_->length()) { - reported_errors_->Rewind(reported_errors_begin_); + if (reported_errors_end_ == reported_errors_->size()) { + reported_errors_->resize(reported_errors_begin_); reported_errors_end_ = reported_errors_begin_; } DCHECK_EQ(reported_errors_begin_, reported_errors_end_); @@ -389,8 +375,8 @@ class ExpressionClassifier { // Adds e to the end of the list of reported errors for this classifier. // It is expected that this classifier is the last one in the stack. V8_INLINE void Add(const Error& e) { - DCHECK_EQ(reported_errors_end_, reported_errors_->length()); - reported_errors_->Add(e, zone_); + DCHECK_EQ(reported_errors_end_, reported_errors_->size()); + reported_errors_->push_back(e); reported_errors_end_++; } @@ -400,7 +386,7 @@ class ExpressionClassifier { // in an inner classifier) or it could be an existing error (in case a // copy is needed). V8_INLINE void Copy(int i) { - DCHECK_LT(i, reported_errors_->length()); + DCHECK_LT(i, reported_errors_->size()); if (reported_errors_end_ != i) reported_errors_->at(reported_errors_end_) = reported_errors_->at(i); reported_errors_end_++; @@ -409,10 +395,10 @@ class ExpressionClassifier { typename Types::Base* base_; ExpressionClassifier* previous_; Zone* zone_; - ZoneList<Error>* reported_errors_; + ZoneVector<Error>* reported_errors_; DuplicateFinder* duplicate_finder_; - unsigned invalid_productions_ : 14; - unsigned function_properties_ : 2; + unsigned invalid_productions_ : 15; + unsigned is_non_simple_parameter_list_ : 1; // The uint16_t for reported_errors_begin_ and reported_errors_end_ will // not be enough in the case of a long series of expressions using nested // classifiers, e.g., a long sequence of assignments, as in: diff --git a/deps/v8/src/parsing/func-name-inferrer.cc b/deps/v8/src/parsing/func-name-inferrer.cc index 4920877610..7d476f1e64 100644 --- a/deps/v8/src/parsing/func-name-inferrer.cc +++ b/deps/v8/src/parsing/func-name-inferrer.cc @@ -14,72 +14,74 @@ namespace internal { FuncNameInferrer::FuncNameInferrer(AstValueFactory* ast_value_factory, Zone* zone) : ast_value_factory_(ast_value_factory), - entries_stack_(10, zone), - names_stack_(5, zone), - funcs_to_infer_(4, zone), - zone_(zone) { -} - + entries_stack_(zone), + names_stack_(zone), + funcs_to_infer_(zone), + zone_(zone) {} void FuncNameInferrer::PushEnclosingName(const AstRawString* name) { // Enclosing name is a name of a constructor function. To check // that it is really a constructor, we check that it is not empty // and starts with a capital letter. if (!name->IsEmpty() && unibrow::Uppercase::Is(name->FirstCharacter())) { - names_stack_.Add(Name(name, kEnclosingConstructorName), zone()); + names_stack_.push_back(Name(name, kEnclosingConstructorName)); } } void FuncNameInferrer::PushLiteralName(const AstRawString* name) { if (IsOpen() && name != ast_value_factory_->prototype_string()) { - names_stack_.Add(Name(name, kLiteralName), zone()); + names_stack_.push_back(Name(name, kLiteralName)); } } void FuncNameInferrer::PushVariableName(const AstRawString* name) { if (IsOpen() && name != ast_value_factory_->dot_result_string()) { - names_stack_.Add(Name(name, kVariableName), zone()); + names_stack_.push_back(Name(name, kVariableName)); } } void FuncNameInferrer::RemoveAsyncKeywordFromEnd() { if (IsOpen()) { - CHECK_GT(names_stack_.length(), 0); - CHECK(names_stack_.last().name->IsOneByteEqualTo("async")); - names_stack_.RemoveLast(); + CHECK_GT(names_stack_.size(), 0); + CHECK(names_stack_.back().name->IsOneByteEqualTo("async")); + names_stack_.pop_back(); } } void FuncNameInferrer::Leave() { DCHECK(IsOpen()); - names_stack_.Rewind(entries_stack_.RemoveLast()); - if (entries_stack_.is_empty()) funcs_to_infer_.Clear(); + size_t last_entry = entries_stack_.back(); + entries_stack_.pop_back(); + names_stack_.Rewind(last_entry); + if (entries_stack_.is_empty()) funcs_to_infer_.Rewind(); } const AstConsString* FuncNameInferrer::MakeNameFromStack() { AstConsString* result = ast_value_factory_->NewConsString(); - for (int pos = 0; pos < names_stack_.length(); pos++) { + auto it = names_stack_.begin(); + while (it != names_stack_.end()) { + // Advance the iterator to be able to peek the next value. + auto current = it++; // Skip consecutive variable declarations. - if (pos + 1 < names_stack_.length() && - names_stack_.at(pos).type == kVariableName && - names_stack_.at(pos + 1).type == kVariableName) { + if (it != names_stack_.end() && current->type == kVariableName && + it->type == kVariableName) { continue; } // Add name. Separate names with ".". if (!result->IsEmpty()) { result->AddString(zone(), ast_value_factory_->dot_string()); } - result->AddString(zone(), names_stack_.at(pos).name); + result->AddString(zone(), current->name); } return result; } void FuncNameInferrer::InferFunctionsNames() { const AstConsString* func_name = MakeNameFromStack(); - for (int i = 0; i < funcs_to_infer_.length(); ++i) { - funcs_to_infer_[i]->set_raw_inferred_name(func_name); + for (FunctionLiteral* func : funcs_to_infer_) { + func->set_raw_inferred_name(func_name); } funcs_to_infer_.Rewind(0); } diff --git a/deps/v8/src/parsing/func-name-inferrer.h b/deps/v8/src/parsing/func-name-inferrer.h index 21c4da3be9..8f0f428a05 100644 --- a/deps/v8/src/parsing/func-name-inferrer.h +++ b/deps/v8/src/parsing/func-name-inferrer.h @@ -5,6 +5,7 @@ #ifndef V8_PARSING_FUNC_NAME_INFERRER_H_ #define V8_PARSING_FUNC_NAME_INFERRER_H_ +#include "src/zone/zone-chunk-list.h" #include "src/zone/zone.h" namespace v8 { @@ -62,13 +63,13 @@ class FuncNameInferrer : public ZoneObject { // Adds a function to infer name for. void AddFunction(FunctionLiteral* func_to_infer) { if (IsOpen()) { - funcs_to_infer_.Add(func_to_infer, zone()); + funcs_to_infer_.push_back(func_to_infer); } } void RemoveLastFunction() { if (IsOpen() && !funcs_to_infer_.is_empty()) { - funcs_to_infer_.RemoveLast(); + funcs_to_infer_.pop_back(); } } @@ -94,7 +95,7 @@ class FuncNameInferrer : public ZoneObject { NameType type; }; - void Enter() { entries_stack_.Add(names_stack_.length(), zone()); } + void Enter() { entries_stack_.push_back(names_stack_.size()); } void Leave(); @@ -107,9 +108,9 @@ class FuncNameInferrer : public ZoneObject { void InferFunctionsNames(); AstValueFactory* ast_value_factory_; - ZoneList<int> entries_stack_; - ZoneList<Name> names_stack_; - ZoneList<FunctionLiteral*> funcs_to_infer_; + ZoneChunkList<size_t> entries_stack_; + ZoneChunkList<Name> names_stack_; + ZoneChunkList<FunctionLiteral*> funcs_to_infer_; Zone* zone_; DISALLOW_COPY_AND_ASSIGN(FuncNameInferrer); diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc index ee7e4b1569..0a58c4f0bd 100644 --- a/deps/v8/src/parsing/parse-info.cc +++ b/deps/v8/src/parsing/parse-info.cc @@ -4,10 +4,10 @@ #include "src/parsing/parse-info.h" -#include "src/api.h" #include "src/ast/ast-source-ranges.h" #include "src/ast/ast-value-factory.h" #include "src/ast/ast.h" +#include "src/base/template-utils.h" #include "src/heap/heap-inl.h" #include "src/objects-inl.h" #include "src/objects/scope-info.h" @@ -17,14 +17,14 @@ namespace v8 { namespace internal { ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator) - : zone_(std::make_shared<Zone>(zone_allocator, ZONE_NAME)), + : zone_(base::make_unique<Zone>(zone_allocator, ZONE_NAME)), flags_(0), extension_(nullptr), script_scope_(nullptr), unicode_cache_(nullptr), stack_limit_(0), hash_seed_(0), - function_flags_(0), + function_kind_(FunctionKind::kNormalFunction), script_id_(-1), start_position_(0), end_position_(0), @@ -65,11 +65,14 @@ ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared) set_wrapped_as_function(shared->is_wrapped()); set_allow_lazy_parsing(FLAG_lazy_inner_functions); set_is_named_expression(shared->is_named_expression()); - set_function_flags(shared->flags()); set_start_position(shared->StartPosition()); set_end_position(shared->EndPosition()); function_literal_id_ = shared->FunctionLiteralId(isolate); set_language_mode(shared->language_mode()); + set_function_kind(shared->kind()); + set_declaration(shared->is_declaration()); + set_requires_instance_fields_initializer( + shared->requires_instance_fields_initializer()); set_asm_wasm_broken(shared->is_asm_wasm_broken()); Handle<Script> script(Script::cast(shared->script()), isolate); @@ -100,19 +103,6 @@ ParseInfo::~ParseInfo() {} DeclarationScope* ParseInfo::scope() const { return literal()->scope(); } -bool ParseInfo::is_declaration() const { - return SharedFunctionInfo::IsDeclarationBit::decode(function_flags_); -} - -FunctionKind ParseInfo::function_kind() const { - return SharedFunctionInfo::FunctionKindBits::decode(function_flags_); -} - -bool ParseInfo::requires_instance_fields_initializer() const { - return SharedFunctionInfo::RequiresInstanceFieldsInitializer::decode( - function_flags_); -} - 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. @@ -141,11 +131,6 @@ void ParseInfo::UpdateBackgroundParseStatisticsOnMainThread(Isolate* isolate) { set_runtime_call_stats(main_call_stats); } -void ParseInfo::ShareZone(ParseInfo* other) { - DCHECK_EQ(0, zone_->allocation_size()); - zone_ = other->zone_; -} - Handle<Script> ParseInfo::CreateScript(Isolate* isolate, Handle<String> source, ScriptOriginOptions origin_options, NativesFlag natives) { @@ -186,11 +171,6 @@ AstValueFactory* ParseInfo::GetOrCreateAstValueFactory() { return ast_value_factory(); } -void ParseInfo::ShareAstValueFactory(ParseInfo* other) { - DCHECK(!ast_value_factory_.get()); - ast_value_factory_ = other->ast_value_factory_; -} - void ParseInfo::AllocateSourceRangeMap() { DCHECK(block_coverage_enabled()); set_source_range_map(new (zone()) SourceRangeMap(zone())); diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h index 4abf3a1fb0..64a50806f5 100644 --- a/deps/v8/src/parsing/parse-info.h +++ b/deps/v8/src/parsing/parse-info.h @@ -54,12 +54,6 @@ class V8_EXPORT_PRIVATE ParseInfo { Zone* zone() const { return zone_.get(); } - // Sets this parse info to share the same zone as |other| - void ShareZone(ParseInfo* other); - - // Sets this parse info to share the same ast value factory as |other| - void ShareAstValueFactory(ParseInfo* other); - // Convenience accessor methods for flags. #define FLAG_ACCESSOR(flag, getter, setter) \ bool getter() const { return GetFlag(flag); } \ @@ -86,6 +80,10 @@ class V8_EXPORT_PRIVATE ParseInfo { FLAG_ACCESSOR(kWrappedAsFunction, is_wrapped_as_function, set_wrapped_as_function) FLAG_ACCESSOR(kAllowEvalCache, allow_eval_cache, set_allow_eval_cache) + FLAG_ACCESSOR(kIsDeclaration, is_declaration, set_declaration) + FLAG_ACCESSOR(kRequiresInstanceFieldsInitializer, + requires_instance_fields_initializer, + set_requires_instance_fields_initializer); #undef FLAG_ACCESSOR void set_parse_restriction(ParseRestriction restriction) { @@ -143,11 +141,6 @@ class V8_EXPORT_PRIVATE ParseInfo { uint64_t hash_seed() const { return hash_seed_; } void set_hash_seed(uint64_t hash_seed) { hash_seed_ = hash_seed; } - int function_flags() const { return function_flags_; } - void set_function_flags(int function_flags) { - function_flags_ = function_flags; - } - int start_position() const { return start_position_; } void set_start_position(int start_position) { start_position_ = start_position; @@ -166,6 +159,11 @@ class V8_EXPORT_PRIVATE ParseInfo { function_literal_id_ = function_literal_id; } + FunctionKind function_kind() const { return function_kind_; } + void set_function_kind(FunctionKind function_kind) { + function_kind_ = function_kind; + } + int max_function_literal_id() const { return max_function_literal_id_; } void set_max_function_literal_id(int max_function_literal_id) { max_function_literal_id_ = max_function_literal_id; @@ -196,11 +194,6 @@ class V8_EXPORT_PRIVATE ParseInfo { return &pending_error_handler_; } - // Getters for individual function flags. - bool is_declaration() const; - FunctionKind function_kind() const; - bool requires_instance_fields_initializer() const; - //-------------------------------------------------------------------------- // TODO(titzer): these should not be part of ParseInfo. //-------------------------------------------------------------------------- @@ -249,19 +242,19 @@ class V8_EXPORT_PRIVATE ParseInfo { kOnBackgroundThread = 1 << 13, kWrappedAsFunction = 1 << 14, // Implicitly wrapped as function. kAllowEvalCache = 1 << 15, + kIsDeclaration = 1 << 16, + kRequiresInstanceFieldsInitializer = 1 << 17, }; //------------- Inputs to parsing and scope analysis ----------------------- - std::shared_ptr<Zone> zone_; + std::unique_ptr<Zone> zone_; unsigned flags_; v8::Extension* extension_; DeclarationScope* script_scope_; UnicodeCache* unicode_cache_; uintptr_t stack_limit_; uint64_t hash_seed_; - // TODO(leszeks): Move any remaining flags used here either to the flags_ - // field or to other fields. - int function_flags_; + FunctionKind function_kind_; int script_id_; int start_position_; int end_position_; @@ -276,7 +269,7 @@ class V8_EXPORT_PRIVATE ParseInfo { //----------- Inputs+Outputs of parsing and scope analysis ----------------- std::unique_ptr<Utf16CharacterStream> character_stream_; ConsumedPreParsedScopeData consumed_preparsed_scope_data_; - std::shared_ptr<AstValueFactory> ast_value_factory_; + std::unique_ptr<AstValueFactory> ast_value_factory_; const class AstStringConstants* ast_string_constants_; const AstRawString* function_name_; RuntimeCallStats* runtime_call_stats_; @@ -285,7 +278,6 @@ class V8_EXPORT_PRIVATE ParseInfo { //----------- Output of parsing and scope analysis ------------------------ FunctionLiteral* literal_; - std::shared_ptr<DeferredHandles> deferred_handles_; PendingCompilationErrorHandler pending_error_handler_; void SetFlag(Flag f) { flags_ |= f; } diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index 6f6cff8e20..9d13724f06 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -21,6 +21,7 @@ #include "src/parsing/func-name-inferrer.h" #include "src/parsing/scanner.h" #include "src/parsing/token.h" +#include "src/zone/zone-chunk-list.h" namespace v8 { namespace internal { @@ -416,21 +417,23 @@ class ParserBase { void AdoptDestructuringAssignmentsFromParentState(int pos) { const auto& outer_assignments = outer_function_state_->destructuring_assignments_to_rewrite_; - DCHECK_GE(outer_assignments.length(), pos); - for (int i = pos; i < outer_assignments.length(); ++i) { - auto expr = outer_assignments[i]; + DCHECK_GE(outer_assignments.size(), pos); + auto it = outer_assignments.begin(); + it.Advance(pos); + for (; it != outer_assignments.end(); ++it) { + auto expr = *it; expr->set_scope(scope_); - destructuring_assignments_to_rewrite_.Add(expr, scope_->zone()); + destructuring_assignments_to_rewrite_.push_back(expr); } outer_function_state_->RewindDestructuringAssignments(pos); } - const ZoneList<RewritableExpressionT>& + const ZoneChunkList<RewritableExpressionT>& destructuring_assignments_to_rewrite() const { return destructuring_assignments_to_rewrite_; } - ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() { + ZoneVector<typename ExpressionClassifier::Error>* GetReportedErrorList() { return &reported_errors_; } @@ -472,26 +475,27 @@ class ParserBase { private: void AddDestructuringAssignment(RewritableExpressionT expr) { - destructuring_assignments_to_rewrite_.Add(expr, scope_->zone()); + destructuring_assignments_to_rewrite_.push_back(expr); } // Properties count estimation. int expected_property_count_; + // How many suspends are needed for this function. + int suspend_count_; + FunctionState** function_state_stack_; FunctionState* outer_function_state_; DeclarationScope* scope_; - ZoneList<RewritableExpressionT> destructuring_assignments_to_rewrite_; + ZoneChunkList<RewritableExpressionT> destructuring_assignments_to_rewrite_; - ZoneList<typename ExpressionClassifier::Error> reported_errors_; + // We use a ZoneVector here because we need to do a lot of random access. + ZoneVector<typename ExpressionClassifier::Error> reported_errors_; // A reason, if any, why this function should not be optimized. BailoutReason dont_optimize_reason_; - // How many suspends are needed for this function. - int suspend_count_; - // Record whether the next (=== immediately following) function literal is // preceded by a parenthesis / exclamation mark. Also record the previous // state. @@ -594,7 +598,6 @@ class ParserBase { 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; @@ -745,8 +748,7 @@ class ParserBase { Next(); return; } - if (scanner()->HasAnyLineTerminatorBeforeNext() || - tok == Token::RBRACE || + if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::RBRACE || tok == Token::EOS) { return; } @@ -959,8 +961,7 @@ class ParserBase { void ReportClassifierError( const typename ExpressionClassifier::Error& error) { - impl()->ReportMessageAt(error.location, error.message, error.arg, - error.type); + impl()->ReportMessageAt(error.location, error.message, error.arg); } void ValidateExpression(bool* ok) { @@ -1089,7 +1090,7 @@ class ParserBase { function_state_->kind(), is_strict_reserved, is_await, ok); } - IdentifierT ParseIdentifierName(bool* ok); + V8_INLINE IdentifierT ParseIdentifierName(bool* ok); ExpressionT ParseIdentifierNameOrPrivateName(bool* ok); @@ -1135,8 +1136,7 @@ class ParserBase { ClassLiteralPropertyT ParseClassPropertyDefinition( ClassLiteralChecker* checker, ClassInfo* class_info, IdentifierT* property_name, 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); + ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok); ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, bool is_static, bool* ok); ObjectLiteralPropertyT ParseObjectPropertyDefinition( @@ -1152,15 +1152,15 @@ class ParserBase { ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); ExpressionT ParseYieldExpression(bool accept_IN, bool* ok); - ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); + V8_INLINE ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok); ExpressionT ParseUnaryExpression(bool* ok); - ExpressionT ParsePostfixExpression(bool* ok); - ExpressionT ParseLeftHandSideExpression(bool* ok); + V8_INLINE ExpressionT ParsePostfixExpression(bool* ok); + V8_INLINE ExpressionT ParseLeftHandSideExpression(bool* ok); ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async, bool* ok); - ExpressionT ParseMemberExpression(bool* is_async, bool* ok); - ExpressionT ParseMemberExpressionContinuation(ExpressionT expression, - bool* is_async, bool* ok); + V8_INLINE ExpressionT ParseMemberExpression(bool* is_async, bool* ok); + V8_INLINE ExpressionT ParseMemberExpressionContinuation( + ExpressionT expression, bool* is_async, bool* ok); // `rewritable_length`: length of the destructuring_assignments_to_rewrite() // queue in the parent function state, prior to parsing of formal parameters. @@ -1183,7 +1183,7 @@ class ParserBase { ExpressionT ParseImportExpressions(bool* ok); ExpressionT ParseNewTargetExpression(bool* ok); - void ParseFormalParameter(FormalParametersT* parameters, bool* ok); + V8_INLINE void ParseFormalParameter(FormalParametersT* parameters, bool* ok); void ParseFormalParameterList(FormalParametersT* parameters, bool* ok); void CheckArityRestrictions(int param_count, FunctionKind function_type, bool has_rest, int formals_start_pos, @@ -1228,14 +1228,19 @@ class ParserBase { USE(result); DCHECK_EQ(result, kLazyParsingComplete); } - LazyParsingResult ParseStatementList(StatementListT body, - Token::Value end_token, bool may_abort, - bool* ok); + V8_INLINE LazyParsingResult ParseStatementList(StatementListT body, + Token::Value end_token, + bool may_abort, bool* ok); StatementT ParseStatementListItem(bool* ok); - StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, bool* ok) { - return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok); + + StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, + bool* ok) { + return ParseStatement(labels, own_labels, + kDisallowLabelledFunctionStatement, ok); } StatementT ParseStatement(ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok); BlockT ParseBlock(ZonePtrList<const AstRawString>* labels, bool* ok); @@ -1259,6 +1264,7 @@ class ParserBase { StatementT ParseExpressionOrLabelledStatement( ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok); StatementT ParseIfStatement(ZonePtrList<const AstRawString>* labels, bool* ok); @@ -1269,34 +1275,41 @@ class ParserBase { StatementT ParseWithStatement(ZonePtrList<const AstRawString>* labels, bool* ok); StatementT ParseDoWhileStatement(ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseWhileStatement(ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseThrowStatement(bool* ok); StatementT ParseSwitchStatement(ZonePtrList<const AstRawString>* labels, bool* ok); - StatementT ParseTryStatement(bool* ok); + V8_INLINE StatementT ParseTryStatement(bool* ok); StatementT ParseForStatement(ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - Scope* inner_block_scope, bool* ok); + ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope, + bool* ok); StatementT ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, - ForInfo* for_info, ZonePtrList<const AstRawString>* labels, bool* ok); + ForInfo* for_info, ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok); // Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }' // "for (<init>;" is assumed to have been parser already. - ForStatementT ParseStandardForLoop(int stmt_pos, - ZonePtrList<const AstRawString>* labels, - ExpressionT* cond, StatementT* next, - StatementT* body, bool* ok); + ForStatementT ParseStandardForLoop( + int stmt_pos, ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, + StatementT* next, StatementT* body, bool* ok); // Same as the above, but handles those cases where <init> is a // lexical variable declaration. StatementT ParseStandardForLoopWithLexicalDeclarations( int stmt_pos, StatementT init, ForInfo* for_info, - ZonePtrList<const AstRawString>* labels, bool* ok); + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok); StatementT ParseForAwaitStatement(ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok); bool IsNextLetKeyword(); @@ -1574,17 +1587,18 @@ ParserBase<Impl>::FunctionState::FunctionState( DeclarationScope* scope) : BlockState(scope_stack, scope), expected_property_count_(0), + suspend_count_(0), function_state_stack_(function_state_stack), outer_function_state_(*function_state_stack), scope_(scope), - destructuring_assignments_to_rewrite_(16, scope->zone()), - reported_errors_(16, scope->zone()), + destructuring_assignments_to_rewrite_(scope->zone()), + reported_errors_(scope_->zone()), dont_optimize_reason_(BailoutReason::kNoReason), - suspend_count_(0), next_function_is_likely_called_(false), previous_function_was_likely_called_(false), contains_function_or_eval_(false) { *function_state_stack = this; + reported_errors_.reserve(16); if (outer_function_state_) { outer_function_state_->previous_function_was_likely_called_ = outer_function_state_->next_function_is_likely_called_; @@ -1875,7 +1889,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( return impl()->ExpressionFromLiteral(Next(), beg_pos); case Token::ASYNC: - if (!scanner()->HasAnyLineTerminatorAfterNext() && + if (!scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { BindingPatternUnexpectedToken(); Consume(Token::ASYNC); @@ -2179,10 +2193,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( int pos = peek_position(); if (!*is_generator && token == Token::ASYNC && - !scanner()->HasAnyLineTerminatorAfterNext()) { + !scanner()->HasLineTerminatorAfterNext()) { Consume(Token::ASYNC); token = peek(); - if (token == Token::MUL && !scanner()->HasAnyLineTerminatorBeforeNext()) { + if (token == Token::MUL && !scanner()->HasLineTerminatorBeforeNext()) { Consume(Token::MUL); token = peek(); *is_generator = true; @@ -2300,11 +2314,9 @@ template <typename Impl> typename ParserBase<Impl>::ClassLiteralPropertyT ParserBase<Impl>::ParseClassPropertyDefinition( ClassLiteralChecker* checker, ClassInfo* class_info, IdentifierT* name, - 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 has_extends, bool* is_computed_name, + ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok) { + DCHECK_NOT_NULL(class_info); bool is_get = false; bool is_set = false; bool is_generator = false; @@ -2353,8 +2365,9 @@ ParserBase<Impl>::ParseClassPropertyDefinition( CHECK_OK_CUSTOM(NullLiteralProperty)); } - if (!*has_name_static_property && *is_static && impl()->IsName(*name)) { - *has_name_static_property = true; + if (!class_info->has_name_static_property && *is_static && + impl()->IsName(*name)) { + class_info->has_name_static_property = true; } switch (kind) { @@ -2416,7 +2429,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition( FunctionKind kind = MethodKindFor(is_generator, is_async); if (!*is_static && impl()->IsConstructor(*name)) { - *has_seen_constructor = true; + class_info->has_seen_constructor = true; kind = has_extends ? FunctionKind::kDerivedConstructor : FunctionKind::kBaseConstructor; } @@ -2875,11 +2888,11 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { this, classifier()->duplicate_finder()); Scope::Snapshot scope_snapshot(scope()); - int rewritable_length = - function_state_->destructuring_assignments_to_rewrite().length(); + int rewritable_length = static_cast<int>( + function_state_->destructuring_assignments_to_rewrite().size()); bool is_async = peek() == Token::ASYNC && - !scanner()->HasAnyLineTerminatorAfterNext() && + !scanner()->HasLineTerminatorAfterNext() && IsValidArrowFormalParametersStart(PeekAhead()); bool parenthesized_formals = peek() == Token::LPAREN; @@ -3056,7 +3069,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression( // The following initialization is necessary. ExpressionT expression = impl()->NullExpression(); bool delegating = false; // yield* - if (!scanner()->HasAnyLineTerminatorBeforeNext()) { + if (!scanner()->HasLineTerminatorBeforeNext()) { if (Check(Token::MUL)) delegating = true; switch (peek()) { case Token::EOS: @@ -3307,8 +3320,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression( int lhs_beg_pos = peek_position(); ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK); - if (!scanner()->HasAnyLineTerminatorBeforeNext() && - Token::IsCountOp(peek())) { + if (!scanner()->HasLineTerminatorBeforeNext() && Token::IsCountOp(peek())) { BindingPatternUnexpectedToken(); ArrowFormalParametersUnexpectedToken(); @@ -3375,6 +3387,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) { // function literal eagerly, we can also compile it eagerly. if (result->IsFunctionLiteral()) { result->AsFunctionLiteral()->SetShouldEagerCompile(); + result->AsFunctionLiteral()->mark_as_iife(); } } Scanner::Location spread_pos; @@ -4168,7 +4181,7 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration( // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::ASYNC); int pos = position(); - if (scanner()->HasAnyLineTerminatorBeforeNext()) { + if (scanner()->HasLineTerminatorBeforeNext()) { *ok = false; impl()->ReportUnexpectedToken(scanner()->current_token()); return impl()->NullStatement(); @@ -4360,7 +4373,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( base::ElapsedTimer timer; if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start(); - if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) { + if (peek() == Token::ARROW && scanner_->HasLineTerminatorBeforeNext()) { // ASI inserts `;` after arrow parameters if a line terminator is found. // `=> ...` is never a valid expression, so report as syntax error. // If next token is not `=>`, it's a syntax error anyways. @@ -4547,8 +4560,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral( bool is_constructor = !class_info.has_seen_constructor; ClassLiteralPropertyT property = ParseClassPropertyDefinition( &checker, &class_info, &property_name, has_extends, &is_computed_name, - &class_info.has_seen_constructor, &property_kind, &is_static, - &class_info.has_name_static_property, CHECK_OK); + &property_kind, &is_static, CHECK_OK); if (!class_info.has_static_computed_names && is_static && is_computed_name) { class_info.has_static_computed_names = true; @@ -4971,7 +4983,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem( break; case Token::ASYNC: if (PeekAhead() == Token::FUNCTION && - !scanner()->HasAnyLineTerminatorAfterNext()) { + !scanner()->HasLineTerminatorAfterNext()) { Consume(Token::ASYNC); return ParseAsyncFunctionDeclaration(nullptr, false, ok); } @@ -4979,12 +4991,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem( default: break; } - return ParseStatement(nullptr, kAllowLabelledFunctionStatement, ok); + return ParseStatement(nullptr, nullptr, kAllowLabelledFunctionStatement, ok); } template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok) { // Statement :: // Block @@ -5003,6 +5016,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( // TryStatement // DebuggerStatement + // {own_labels} is always a subset of {labels}. + DCHECK_IMPLIES(labels == nullptr, own_labels == nullptr); + // Note: Since labels can only be used by 'break' and 'continue' // statements, which themselves are only valid within blocks, // iterations or 'switch' statements (i.e., BreakableStatements), @@ -5018,14 +5034,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( case Token::IF: return ParseIfStatement(labels, ok); case Token::DO: - return ParseDoWhileStatement(labels, ok); + return ParseDoWhileStatement(labels, own_labels, ok); case Token::WHILE: - return ParseWhileStatement(labels, ok); + return ParseWhileStatement(labels, own_labels, ok); case Token::FOR: if (V8_UNLIKELY(is_async_function() && PeekAhead() == Token::AWAIT)) { - return ParseForAwaitStatement(labels, ok); + return ParseForAwaitStatement(labels, own_labels, ok); } - return ParseForStatement(labels, ok); + return ParseForStatement(labels, own_labels, ok); case Token::CONTINUE: return ParseContinueStatement(ok); case Token::BREAK: @@ -5068,7 +5084,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( case Token::VAR: return ParseVariableStatement(kStatement, nullptr, ok); case Token::ASYNC: - if (!scanner()->HasAnyLineTerminatorAfterNext() && + if (!scanner()->HasLineTerminatorAfterNext() && PeekAhead() == Token::FUNCTION) { impl()->ReportMessageAt( scanner()->peek_location(), @@ -5078,7 +5094,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement( } V8_FALLTHROUGH; default: - return ParseExpressionOrLabelledStatement(labels, allow_function, ok); + return ParseExpressionOrLabelledStatement(labels, own_labels, + allow_function, ok); } } @@ -5118,7 +5135,7 @@ template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement( ZonePtrList<const AstRawString>* labels, bool* ok) { if (is_strict(language_mode()) || peek() != Token::FUNCTION) { - return ParseStatement(labels, ok); + return ParseStatement(labels, nullptr, ok); } else { // Make a block around the statement for a lexical binding // is introduced by a FunctionDeclaration. @@ -5178,6 +5195,7 @@ template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseExpressionOrLabelledStatement( ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, AllowLabelledFunctionStatement allow_function, bool* ok) { // ExpressionStatement | LabelledStatement :: // Expression ';' @@ -5203,7 +5221,7 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( // However, ASI may insert a line break before an identifier or a brace. if (next_next != Token::LBRACK && ((next_next != Token::LBRACE && next_next != Token::IDENTIFIER) || - scanner_->HasAnyLineTerminatorAfterNext())) { + scanner_->HasLineTerminatorAfterNext())) { break; } impl()->ReportMessageAt(scanner()->peek_location(), @@ -5221,22 +5239,22 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement( impl()->IsIdentifier(expr)) { // The whole expression was a single identifier, and not, e.g., // something starting with an identifier or a parenthesized identifier. - labels = impl()->DeclareLabel(labels, impl()->AsIdentifierExpression(expr), - CHECK_OK); + impl()->DeclareLabel(&labels, &own_labels, + impl()->AsIdentifierExpression(expr), CHECK_OK); Consume(Token::COLON); // ES#sec-labelled-function-declarations Labelled Function Declarations if (peek() == Token::FUNCTION && is_sloppy(language_mode()) && allow_function == kAllowLabelledFunctionStatement) { return ParseFunctionDeclaration(ok); } - return ParseStatement(labels, allow_function, ok); + return ParseStatement(labels, own_labels, allow_function, ok); } // If we have an extension, we allow a native function declaration. // A native function declaration starts with "native function" with // no line-terminator between the two words. if (extension_ != nullptr && peek() == Token::FUNCTION && - !scanner()->HasAnyLineTerminatorBeforeNext() && impl()->IsNative(expr) && + !scanner()->HasLineTerminatorBeforeNext() && impl()->IsNative(expr) && !scanner()->literal_contains_escapes()) { return ParseNativeDeclaration(ok); } @@ -5289,7 +5307,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement( Expect(Token::CONTINUE, CHECK_OK); IdentifierT label = impl()->NullIdentifier(); Token::Value tok = peek(); - if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON && + if (!scanner()->HasLineTerminatorBeforeNext() && tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { // ECMA allows "eval" or "arguments" as labels even in strict mode. label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); @@ -5326,7 +5344,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement( Expect(Token::BREAK, CHECK_OK); IdentifierT label = impl()->NullIdentifier(); Token::Value tok = peek(); - if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON && + if (!scanner()->HasLineTerminatorBeforeNext() && tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { // ECMA allows "eval" or "arguments" as labels even in strict mode. label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); @@ -5380,7 +5398,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement( Token::Value tok = peek(); ExpressionT return_value = impl()->NullExpression(); - if (scanner()->HasAnyLineTerminatorBeforeNext() || tok == Token::SEMICOLON || + if (scanner()->HasLineTerminatorBeforeNext() || tok == Token::SEMICOLON || tok == Token::RBRACE || tok == Token::EOS) { if (IsDerivedConstructor(function_state_->kind())) { return_value = impl()->ThisExpression(loc.beg_pos); @@ -5421,7 +5439,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( { BlockState block_state(&scope_, with_scope); with_scope->set_start_position(scanner()->peek_location().beg_pos); - body = ParseStatement(labels, CHECK_OK); + body = ParseStatement(labels, nullptr, CHECK_OK); with_scope->set_end_position(scanner()->location().end_pos); } return factory()->NewWithStatement(with_scope, expr, body, pos); @@ -5429,11 +5447,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok) { // DoStatement :: // 'do' Statement 'while' '(' Expression ')' ';' - auto loop = factory()->NewDoWhileStatement(labels, peek_position()); + auto loop = + factory()->NewDoWhileStatement(labels, own_labels, peek_position()); typename Types::Target target(this, loop); SourceRange body_range; @@ -5442,7 +5462,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( Expect(Token::DO, CHECK_OK); { SourceRangeScope range_scope(scanner(), &body_range); - body = ParseStatement(nullptr, CHECK_OK); + body = ParseStatement(nullptr, nullptr, CHECK_OK); } Expect(Token::WHILE, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); @@ -5464,11 +5484,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok) { // WhileStatement :: // 'while' '(' Expression ')' Statement - auto loop = factory()->NewWhileStatement(labels, peek_position()); + auto loop = factory()->NewWhileStatement(labels, own_labels, peek_position()); typename Types::Target target(this, loop); SourceRange body_range; @@ -5480,7 +5501,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement( Expect(Token::RPAREN, CHECK_OK); { SourceRangeScope range_scope(scanner(), &body_range); - body = ParseStatement(nullptr, CHECK_OK); + body = ParseStatement(nullptr, nullptr, CHECK_OK); } loop->Initialize(cond, body); @@ -5497,7 +5518,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement( Expect(Token::THROW, CHECK_OK); int pos = position(); - if (scanner()->HasAnyLineTerminatorBeforeNext()) { + if (scanner()->HasLineTerminatorBeforeNext()) { ReportMessage(MessageTemplate::kNewlineAfterThrow); *ok = false; return impl()->NullStatement(); @@ -5679,7 +5700,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok) { // Either a standard for loop // for (<init>; <cond>; <next>) { ... } // or a for-each loop @@ -5719,8 +5741,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( if (CheckInOrOf(&for_info.mode)) { scope()->set_is_hidden(); - return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, - inner_block_scope, ok); + return ParseForEachStatementWithDeclarations( + stmt_pos, &for_info, labels, own_labels, inner_block_scope, ok); } Expect(Token::SEMICOLON, CHECK_OK); @@ -5732,8 +5754,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( // No variable declarations will have been created in inner_block_scope. DCHECK_NULL(finalized); USE(finalized); - return ParseStandardForLoopWithLexicalDeclarations(stmt_pos, init, - &for_info, labels, ok); + return ParseStandardForLoopWithLexicalDeclarations( + stmt_pos, init, &for_info, labels, own_labels, ok); } StatementT init = impl()->NullStatement(); @@ -5745,7 +5767,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( if (CheckInOrOf(&for_info.mode)) { return ParseForEachStatementWithDeclarations(stmt_pos, &for_info, labels, - nullptr, ok); + own_labels, nullptr, ok); } init = impl()->BuildInitializationBlock(&for_info.parsing_result, nullptr, @@ -5768,9 +5790,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( } if (is_for_each) { - return ParseForEachStatementWithoutDeclarations(stmt_pos, expression, - lhs_beg_pos, lhs_end_pos, - &for_info, labels, ok); + return ParseForEachStatementWithoutDeclarations( + stmt_pos, expression, lhs_beg_pos, lhs_end_pos, &for_info, labels, + own_labels, ok); } // Initializer is just an expression. init = factory()->NewExpressionStatement(expression, lhs_beg_pos); @@ -5782,8 +5804,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ExpressionT cond = impl()->NullExpression(); StatementT next = impl()->NullStatement(); StatementT body = impl()->NullStatement(); - ForStatementT loop = - ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK); + ForStatementT loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, + &next, &body, CHECK_OK); loop->Initialize(init, cond, next, body); return loop; } @@ -5792,7 +5814,8 @@ template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithDeclarations( int stmt_pos, ForInfo* for_info, ZonePtrList<const AstRawString>* labels, - Scope* inner_block_scope, bool* ok) { + ZonePtrList<const AstRawString>* own_labels, Scope* inner_block_scope, + bool* ok) { // Just one declaration followed by in/of. if (for_info->parsing_result.declarations.size() != 1) { impl()->ReportMessageAt(for_info->parsing_result.bindings_loc, @@ -5820,7 +5843,8 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( BlockT init_block = impl()->RewriteForVarInLegacy(*for_info); - auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); + auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, + stmt_pos); typename Types::Target target(this, loop); ExpressionT enumerable = impl()->NullExpression(); @@ -5850,7 +5874,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); - StatementT body = ParseStatement(nullptr, CHECK_OK); + StatementT body = ParseStatement(nullptr, nullptr, CHECK_OK); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); impl()->DesugarBindingInForEachStatement(for_info, &body_block, @@ -5888,7 +5912,8 @@ template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, - ForInfo* for_info, ZonePtrList<const AstRawString>* labels, bool* ok) { + ForInfo* for_info, ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok) { // Initializer is reference followed by in/of. if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { expression = CheckAndRewriteReferenceExpression( @@ -5896,7 +5921,8 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( kSyntaxError, CHECK_OK); } - auto loop = factory()->NewForEachStatement(for_info->mode, labels, stmt_pos); + auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, + stmt_pos); typename Types::Target target(this, loop); ExpressionT enumerable = impl()->NullExpression(); @@ -5915,7 +5941,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); - body = ParseStatement(nullptr, CHECK_OK); + body = ParseStatement(nullptr, nullptr, CHECK_OK); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); } return impl()->InitializeForEachStatement(loop, expression, enumerable, body); @@ -5925,7 +5951,8 @@ template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( int stmt_pos, StatementT init, ForInfo* for_info, - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok) { // The condition and the next statement of the for loop must be parsed // in a new scope. Scope* inner_scope = NewScope(BLOCK_SCOPE); @@ -5936,8 +5963,8 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( { BlockState block_state(&scope_, inner_scope); scope()->set_start_position(scanner()->location().beg_pos); - loop = - ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK); + loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, + &body, CHECK_OK); scope()->set_end_position(scanner()->location().end_pos); } @@ -5980,9 +6007,10 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( template <typename Impl> typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( - int stmt_pos, ZonePtrList<const AstRawString>* labels, ExpressionT* cond, + int stmt_pos, ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, ExpressionT* cond, StatementT* next, StatementT* body, bool* ok) { - ForStatementT loop = factory()->NewForStatement(labels, stmt_pos); + ForStatementT loop = factory()->NewForStatement(labels, own_labels, stmt_pos); typename Types::Target target(this, loop); if (peek() != Token::SEMICOLON) { @@ -5999,7 +6027,7 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop( SourceRange body_range; { SourceRangeScope range_scope(scanner(), &body_range); - *body = ParseStatement(nullptr, CHECK_OK); + *body = ParseStatement(nullptr, nullptr, CHECK_OK); } impl()->RecordIterationStatementSourceRange(loop, body_range); @@ -6019,7 +6047,8 @@ void ParserBase<Impl>::MarkLoopVariableAsAssigned( template <typename Impl> typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( - ZonePtrList<const AstRawString>* labels, bool* ok) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, bool* ok) { // for await '(' ForDeclaration of AssignmentExpression ')' DCHECK(is_async_function()); @@ -6036,7 +6065,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( scope()->set_start_position(scanner()->location().beg_pos); scope()->set_is_hidden(); - auto loop = factory()->NewForOfStatement(labels, stmt_pos); + auto loop = factory()->NewForOfStatement(labels, own_labels, stmt_pos); typename Types::Target target(this, loop); ExpressionT each_variable = impl()->NullExpression(); @@ -6119,7 +6148,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( SourceRange body_range; SourceRangeScope range_scope(scanner(), &body_range); - body = ParseStatement(nullptr, CHECK_OK); + body = ParseStatement(nullptr, nullptr, CHECK_OK); scope()->set_end_position(scanner()->location().end_pos); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index dacce7d38f..41ff551091 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -412,7 +412,8 @@ Parser::Parser(ParseInfo* info) info->runtime_call_stats(), info->logger(), info->script().is_null() ? -1 : info->script()->id(), info->is_module(), true), - scanner_(info->unicode_cache()), + scanner_(info->unicode_cache(), info->character_stream(), + info->is_module()), reusable_preparser_(nullptr), mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly. source_range_map_(info->source_range_map()), @@ -507,7 +508,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { // Initialize parser state. DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info()); - scanner_.Initialize(info->character_stream(), info->is_module()); + scanner_.Initialize(); FunctionLiteral* result = DoParseProgram(isolate, info); MaybeResetCharacterStream(info, result); @@ -701,7 +702,7 @@ FunctionLiteral* Parser::ParseFunction(Isolate* isolate, ParseInfo* info, // Initialize parser state. Handle<String> name(shared_info->Name(), isolate); info->set_function_name(ast_value_factory()->GetString(name)); - scanner_.Initialize(info->character_stream(), info->is_module()); + scanner_.Initialize(); FunctionLiteral* result = DoParseFunction(isolate, info, info->function_name()); @@ -775,7 +776,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, if (IsArrowFunction(kind)) { if (IsAsyncFunction(kind)) { - DCHECK(!scanner()->HasAnyLineTerminatorAfterNext()); + DCHECK(!scanner()->HasLineTerminatorAfterNext()); if (!Check(Token::ASYNC)) { CHECK(stack_overflow()); return nullptr; @@ -798,7 +799,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, ParserFormalParameters formals(scope); // The outer FunctionState should not contain destructuring assignments. DCHECK_EQ(0, - function_state.destructuring_assignments_to_rewrite().length()); + function_state.destructuring_assignments_to_rewrite().size()); { // Parsing patterns as variable reference expression creates // NewUnresolved references in current scope. Enter arrow function @@ -943,10 +944,8 @@ const AstRawString* Parser::ParseModuleSpecifier(bool* ok) { return GetSymbol(); } -void Parser::ParseExportClause(ZonePtrList<const AstRawString>* export_names, - ZoneList<Scanner::Location>* export_locations, - ZonePtrList<const AstRawString>* local_names, - Scanner::Location* reserved_loc, bool* ok) { +ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause( + Scanner::Location* reserved_loc, bool* ok) { // ExportClause : // '{' '}' // '{' ExportsList '}' @@ -959,8 +958,10 @@ void Parser::ParseExportClause(ZonePtrList<const AstRawString>* export_names, // ExportSpecifier : // IdentifierName // IdentifierName 'as' IdentifierName + ZoneChunkList<ExportClauseData>* export_data = + new (zone()) ZoneChunkList<ExportClauseData>(zone()); - Expect(Token::LBRACE, CHECK_OK_VOID); + Expect(Token::LBRACE, CHECK_OK); Token::Value name_tok; while ((name_tok = peek()) != Token::RBRACE) { @@ -971,11 +972,11 @@ void Parser::ParseExportClause(ZonePtrList<const AstRawString>* export_names, parsing_module_)) { *reserved_loc = scanner()->location(); } - const AstRawString* local_name = ParseIdentifierName(CHECK_OK_VOID); + const AstRawString* local_name = ParseIdentifierName(CHECK_OK); const AstRawString* export_name = nullptr; Scanner::Location location = scanner()->location(); if (CheckContextualKeyword(Token::AS)) { - export_name = ParseIdentifierName(CHECK_OK_VOID); + export_name = ParseIdentifierName(CHECK_OK); // Set the location to the whole "a as b" string, so that it makes sense // both for errors due to "a" and for errors due to "b". location.end_pos = scanner()->location().end_pos; @@ -983,14 +984,13 @@ void Parser::ParseExportClause(ZonePtrList<const AstRawString>* export_names, if (export_name == nullptr) { export_name = local_name; } - export_names->Add(export_name, zone()); - local_names->Add(local_name, zone()); - export_locations->Add(location, zone()); + export_data->push_back({export_name, local_name, location}); if (peek() == Token::RBRACE) break; - Expect(Token::COMMA, CHECK_OK_VOID); + Expect(Token::COMMA, CHECK_OK); } - Expect(Token::RBRACE, CHECK_OK_VOID); + Expect(Token::RBRACE, CHECK_OK); + return export_data; } ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos, @@ -1179,7 +1179,7 @@ Statement* Parser::ParseExportDefault(bool* ok) { case Token::ASYNC: if (PeekAhead() == Token::FUNCTION && - !scanner()->HasAnyLineTerminatorAfterNext()) { + !scanner()->HasLineTerminatorAfterNext()) { Consume(Token::ASYNC); result = ParseAsyncFunctionDeclaration(&local_names, true, CHECK_OK); break; @@ -1264,11 +1264,8 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { // encountered, and then throw a SyntaxError if we are in the // non-FromClause case. Scanner::Location reserved_loc = Scanner::Location::invalid(); - ZonePtrList<const AstRawString> export_names(1, zone()); - ZoneList<Scanner::Location> export_locations(1, zone()); - ZonePtrList<const AstRawString> original_names(1, zone()); - ParseExportClause(&export_names, &export_locations, &original_names, - &reserved_loc, CHECK_OK); + ZoneChunkList<ExportClauseData>* export_data = + ParseExportClause(&reserved_loc, CHECK_OK); const AstRawString* module_specifier = nullptr; Scanner::Location specifier_loc; if (CheckContextualKeyword(Token::FROM)) { @@ -1281,21 +1278,18 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { return nullptr; } ExpectSemicolon(CHECK_OK); - const int length = export_names.length(); - DCHECK_EQ(length, original_names.length()); - DCHECK_EQ(length, export_locations.length()); if (module_specifier == nullptr) { - for (int i = 0; i < length; ++i) { - module()->AddExport(original_names[i], export_names[i], - export_locations[i], zone()); + for (const ExportClauseData& data : *export_data) { + module()->AddExport(data.local_name, data.export_name, data.location, + zone()); } - } else if (length == 0) { + } else if (export_data->is_empty()) { module()->AddEmptyImport(module_specifier, specifier_loc); } else { - for (int i = 0; i < length; ++i) { - module()->AddExport(original_names[i], export_names[i], - module_specifier, export_locations[i], - specifier_loc, zone()); + for (const ExportClauseData& data : *export_data) { + module()->AddExport(data.local_name, data.export_name, + module_specifier, data.location, specifier_loc, + zone()); } } return factory()->NewEmptyStatement(pos); @@ -1410,7 +1404,7 @@ Block* Parser::BuildInitializationBlock( DeclarationParsingResult* parsing_result, ZonePtrList<const AstRawString>* names, bool* ok) { Block* result = factory()->NewBlock(1, true); - for (auto declaration : parsing_result->declarations) { + for (const auto& declaration : parsing_result->declarations) { DeclareAndInitializeVariables(result, &(parsing_result->descriptor), &declaration, names, CHECK_OK); } @@ -1473,29 +1467,40 @@ Statement* Parser::DeclareNative(const AstRawString* name, int pos, bool* ok) { pos); } -ZonePtrList<const AstRawString>* Parser::DeclareLabel( - ZonePtrList<const AstRawString>* labels, VariableProxy* var, bool* ok) { +void Parser::DeclareLabel(ZonePtrList<const AstRawString>** labels, + ZonePtrList<const AstRawString>** own_labels, + VariableProxy* var, bool* ok) { DCHECK(IsIdentifier(var)); const AstRawString* label = var->raw_name(); + // TODO(1240780): We don't check for redeclaration of labels // during preparsing since keeping track of the set of active // labels requires nontrivial changes to the way scopes are // structured. However, these are probably changes we want to // make later anyway so we should go back and fix this then. - if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { + if (ContainsLabel(*labels, label) || TargetStackContainsLabel(label)) { ReportMessage(MessageTemplate::kLabelRedeclaration, label); *ok = false; - return nullptr; + return; } - if (labels == nullptr) { - labels = new (zone()) ZonePtrList<const AstRawString>(1, zone()); + + // Add {label} to both {labels} and {own_labels}. + if (*labels == nullptr) { + DCHECK_NULL(*own_labels); + *labels = new (zone()) ZonePtrList<const AstRawString>(1, zone()); + *own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone()); + } else { + if (*own_labels == nullptr) { + *own_labels = new (zone()) ZonePtrList<const AstRawString>(1, zone()); + } } - labels->Add(label, zone()); + (*labels)->Add(label, zone()); + (*own_labels)->Add(label, zone()); + // Remove the "ghost" variable that turned out to be a label // from the top scope. This way, we don't try to resolve it // during the scope processing. scope()->RemoveUnresolved(var); - return labels; } bool Parser::ContainsLabel(ZonePtrList<const AstRawString>* labels, @@ -2194,7 +2199,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(nullptr, kNoSourcePosition); + factory()->NewForStatement(nullptr, nullptr, kNoSourcePosition); outer_block->statements()->Add(outer_loop, zone()); outer_block->set_scope(scope()); @@ -3396,9 +3401,10 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, if (stat == nullptr) continue; DCHECK(stat->is_target_for_anonymous()); - if (anonymous || ContainsLabel(stat->labels(), label)) { + if (anonymous || ContainsLabel(stat->own_labels(), label)) { return stat; } + if (ContainsLabel(stat->labels(), label)) break; } return nullptr; } @@ -3442,7 +3448,7 @@ void Parser::ParseOnBackground(ParseInfo* info) { DCHECK_NULL(info->literal()); FunctionLiteral* result = nullptr; - scanner_.Initialize(info->character_stream(), info->is_module()); + scanner_.Initialize(); DCHECK(info->maybe_outer_scope_info().is_null()); DCHECK(original_scope_); @@ -3652,10 +3658,11 @@ void Parser::RewriteAsyncFunctionBody(ZonePtrList<Statement>* body, void Parser::RewriteDestructuringAssignments() { const auto& assignments = function_state_->destructuring_assignments_to_rewrite(); - for (int i = assignments.length() - 1; i >= 0; --i) { + auto it = assignments.rbegin(); + for (; it != assignments.rend(); ++it) { // Rewrite list in reverse, so that nested assignment patterns are rewritten // correctly. - RewritableExpression* to_rewrite = assignments[i]; + RewritableExpression* to_rewrite = *it; DCHECK_NOT_NULL(to_rewrite); if (!to_rewrite->is_rewritten()) { // Since this function is called at the end of parsing the program, diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h index 2dec83b274..00e73f37a2 100644 --- a/deps/v8/src/parsing/parser.h +++ b/deps/v8/src/parsing/parser.h @@ -14,9 +14,9 @@ #include "src/globals.h" #include "src/parsing/parser-base.h" #include "src/parsing/parsing.h" -#include "src/parsing/preparse-data.h" #include "src/parsing/preparser.h" #include "src/utils.h" +#include "src/zone/zone-chunk-list.h" namespace v8 { @@ -262,10 +262,13 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { void ParseImportDeclaration(bool* ok); Statement* ParseExportDeclaration(bool* ok); Statement* ParseExportDefault(bool* ok); - void ParseExportClause(ZonePtrList<const AstRawString>* export_names, - ZoneList<Scanner::Location>* export_locations, - ZonePtrList<const AstRawString>* local_names, - Scanner::Location* reserved_loc, bool* ok); + struct ExportClauseData { + const AstRawString* export_name; + const AstRawString* local_name; + Scanner::Location location; + }; + ZoneChunkList<ExportClauseData>* ParseExportClause( + Scanner::Location* reserved_loc, bool* ok); struct NamedImport : public ZoneObject { const AstRawString* import_name; const AstRawString* local_name; @@ -280,8 +283,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result, ZonePtrList<const AstRawString>* names, bool* ok); - ZonePtrList<const AstRawString>* DeclareLabel( - ZonePtrList<const AstRawString>* labels, VariableProxy* expr, bool* ok); + void DeclareLabel(ZonePtrList<const AstRawString>** labels, + ZonePtrList<const AstRawString>** own_labels, + VariableProxy* expr, bool* ok); bool ContainsLabel(ZonePtrList<const AstRawString>* labels, const AstRawString* label); Expression* RewriteReturn(Expression* return_value, int pos); @@ -954,7 +958,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { void SetFunctionNameFromIdentifierRef(Expression* value, Expression* identifier); - V8_INLINE ZoneList<typename ExpressionClassifier::Error>* + V8_INLINE ZoneVector<typename ExpressionClassifier::Error>* GetReportedErrorList() const { return function_state_->GetReportedErrorList(); } diff --git a/deps/v8/src/parsing/pattern-rewriter.cc b/deps/v8/src/parsing/pattern-rewriter.cc index b981b6d12e..ed3231c151 100644 --- a/deps/v8/src/parsing/pattern-rewriter.cc +++ b/deps/v8/src/parsing/pattern-rewriter.cc @@ -671,7 +671,8 @@ void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node, // #maybe_store_and_unset_done; // #increment_index; // } - WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos); + WhileStatement* loop = + factory()->NewWhileStatement(nullptr, nullptr, nopos); { Expression* condition = factory()->NewUnaryOperation( Token::NOT, factory()->NewVariableProxy(done), nopos); diff --git a/deps/v8/src/parsing/preparse-data.cc b/deps/v8/src/parsing/preparse-data.cc deleted file mode 100644 index e39218111d..0000000000 --- a/deps/v8/src/parsing/preparse-data.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2010 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/preparse-data.h" -#include "src/base/hashmap.h" -#include "src/base/logging.h" -#include "src/globals.h" -#include "src/objects-inl.h" -#include "src/parsing/parser.h" - -namespace v8 { -namespace internal { - -PreParseData::FunctionData PreParseData::GetFunctionData(int start) const { - auto it = functions_.find(start); - if (it != functions_.end()) { - return it->second; - } - return FunctionData(); -} - -void PreParseData::AddFunctionData(int start, FunctionData&& data) { - DCHECK(data.is_valid()); - functions_[start] = std::move(data); -} - -void PreParseData::AddFunctionData(int start, const FunctionData& data) { - DCHECK(data.is_valid()); - functions_[start] = data; -} - -size_t PreParseData::size() const { return functions_.size(); } - -PreParseData::const_iterator PreParseData::begin() const { - return functions_.begin(); -} - -PreParseData::const_iterator PreParseData::end() const { - return functions_.end(); -} - -} // namespace internal -} // namespace v8. diff --git a/deps/v8/src/parsing/preparse-data.h b/deps/v8/src/parsing/preparse-data.h deleted file mode 100644 index 0e40c76927..0000000000 --- a/deps/v8/src/parsing/preparse-data.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2011 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_PREPARSE_DATA_H_ -#define V8_PARSING_PREPARSE_DATA_H_ - -#include <unordered_map> - -#include "src/allocation.h" -#include "src/base/hashmap.h" -#include "src/collector.h" -#include "src/messages.h" -namespace v8 { -namespace internal { - -class PreParserLogger final { - public: - PreParserLogger() - : end_(-1), - num_parameters_(-1), - num_inner_functions_(-1) {} - - void LogFunction(int end, int num_parameters, int num_inner_functions) { - end_ = end; - num_parameters_ = num_parameters; - num_inner_functions_ = num_inner_functions; - } - - int end() const { return end_; } - int num_parameters() const { - return num_parameters_; - } - int num_inner_functions() const { return num_inner_functions_; } - - private: - int end_; - // For function entries. - int num_parameters_; - int num_inner_functions_; -}; - -class PreParseData final { - public: - struct FunctionData { - int end; - int num_parameters; - int num_inner_functions; - LanguageMode language_mode; - bool uses_super_property : 1; - - FunctionData() : end(kNoSourcePosition) {} - - FunctionData(int end, int num_parameters, int num_inner_functions, - LanguageMode language_mode, bool uses_super_property) - : end(end), - num_parameters(num_parameters), - num_inner_functions(num_inner_functions), - language_mode(language_mode), - uses_super_property(uses_super_property) {} - - bool is_valid() const { - DCHECK_IMPLIES(end < 0, end == kNoSourcePosition); - return end != kNoSourcePosition; - } - }; - - FunctionData GetFunctionData(int start) const; - void AddFunctionData(int start, FunctionData&& data); - void AddFunctionData(int start, const FunctionData& data); - size_t size() const; - - typedef std::unordered_map<int, FunctionData>::const_iterator const_iterator; - const_iterator begin() const; - const_iterator end() const; - - private: - std::unordered_map<int, FunctionData> functions_; -}; - -} // namespace internal -} // namespace v8. - -#endif // V8_PARSING_PREPARSE_DATA_H_ diff --git a/deps/v8/src/parsing/preparsed-scope-data.cc b/deps/v8/src/parsing/preparsed-scope-data.cc index 0dab3f9ee1..90e8819e32 100644 --- a/deps/v8/src/parsing/preparsed-scope-data.cc +++ b/deps/v8/src/parsing/preparsed-scope-data.cc @@ -481,6 +481,11 @@ uint8_t ConsumedPreParsedScopeData::ByteData::ReadQuarter() { return result; } +size_t ConsumedPreParsedScopeData::ByteData::RemainingBytes() const { + DCHECK_NOT_NULL(data_); + return data_->length() - index_; +} + ConsumedPreParsedScopeData::ConsumedPreParsedScopeData() : isolate_(nullptr), scope_data_(new ByteData()), child_index_(0) {} @@ -577,7 +582,7 @@ void ConsumedPreParsedScopeData::RestoreData(Scope* scope) { if (scope_data_->RemainingBytes() < kUint8Size) { // Temporary debugging code for detecting inconsistent data. Write debug // information on the stack, then crash. - data_->GetIsolate()->PushStackTraceAndDie(); + isolate_->PushStackTraceAndDie(); } // scope_type is stored only in debug mode. diff --git a/deps/v8/src/parsing/preparsed-scope-data.h b/deps/v8/src/parsing/preparsed-scope-data.h index 6ad0f491f8..61d67291a4 100644 --- a/deps/v8/src/parsing/preparsed-scope-data.h +++ b/deps/v8/src/parsing/preparsed-scope-data.h @@ -12,7 +12,6 @@ #include "src/globals.h" #include "src/handles.h" #include "src/objects/shared-function-info.h" -#include "src/parsing/preparse-data.h" #include "src/zone/zone-chunk-list.h" namespace v8 { @@ -212,10 +211,7 @@ class ConsumedPreParsedScopeData { uint8_t ReadUint8(); uint8_t ReadQuarter(); - size_t RemainingBytes() const { - DCHECK_NOT_NULL(data_); - return data_->length() - index_; - } + size_t RemainingBytes() const; // private: PodArray<uint8_t>* data_; diff --git a/deps/v8/src/parsing/preparser-logger.h b/deps/v8/src/parsing/preparser-logger.h new file mode 100644 index 0000000000..55394ca2be --- /dev/null +++ b/deps/v8/src/parsing/preparser-logger.h @@ -0,0 +1,35 @@ +// Copyright 2018 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_PREPARSER_LOGGER_H_ +#define V8_PARSING_PREPARSER_LOGGER_H_ + +namespace v8 { +namespace internal { + +class PreParserLogger final { + public: + PreParserLogger() : end_(-1), num_parameters_(-1), num_inner_functions_(-1) {} + + void LogFunction(int end, int num_parameters, int num_inner_functions) { + end_ = end; + num_parameters_ = num_parameters; + num_inner_functions_ = num_inner_functions; + } + + int end() const { return end_; } + int num_parameters() const { return num_parameters_; } + int num_inner_functions() const { return num_inner_functions_; } + + private: + int end_; + // For function entries. + int num_parameters_; + int num_inner_functions_; +}; + +} // namespace internal +} // namespace v8. + +#endif // V8_PARSING_PREPARSER_LOGGER_H_ diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc index 832d2033f2..d449c8d76b 100644 --- a/deps/v8/src/parsing/preparser.cc +++ b/deps/v8/src/parsing/preparser.cc @@ -11,7 +11,6 @@ #include "src/globals.h" #include "src/parsing/duplicate-finder.h" #include "src/parsing/parser-base.h" -#include "src/parsing/preparse-data.h" #include "src/parsing/preparsed-scope-data.h" #include "src/parsing/preparser.h" #include "src/unicode.h" diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h index aa4f06d354..10c42fa940 100644 --- a/deps/v8/src/parsing/preparser.h +++ b/deps/v8/src/parsing/preparser.h @@ -8,8 +8,9 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/parsing/parser-base.h" -#include "src/parsing/preparse-data.h" +#include "src/parsing/preparser-logger.h" #include "src/pending-compilation-error-handler.h" +#include "src/zone/zone-containers.h" namespace v8 { namespace internal { @@ -64,7 +65,7 @@ class PreParserIdentifier { bool IsPrivateName() const { return type_ == kPrivateNameIdentifier; } private: - enum Type { + enum Type : uint8_t { kNullIdentifier, kUnknownIdentifier, kEvalIdentifier, @@ -76,10 +77,11 @@ class PreParserIdentifier { kPrivateNameIdentifier }; - explicit PreParserIdentifier(Type type) : type_(type), string_(nullptr) {} - Type type_; + explicit PreParserIdentifier(Type type) : string_(nullptr), type_(type) {} // Only non-nullptr when PreParser.track_unresolved_variables_ is true. const AstRawString* string_; + + Type type_; friend class PreParserExpression; friend class PreParser; friend class PreParserFactory; @@ -341,6 +343,7 @@ class PreParserExpression { // More dummy implementations of things PreParser doesn't need to track: void SetShouldEagerCompile() {} + void mark_as_iife() {} int position() const { return kNoSourcePosition; } void set_function_token_position(int position) {} @@ -400,7 +403,7 @@ class PreParserExpression { typedef BitField<ExpressionType, TypeField::kNext, 4> ExpressionTypeField; typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField; typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseAsmField; - typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 10> + typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 8> IdentifierTypeField; typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField; @@ -787,12 +790,14 @@ class PreParserFactory { } PreParserStatement NewDoWhileStatement( - ZonePtrList<const AstRawString>* labels, int pos) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, int pos) { return PreParserStatement::Default(); } - PreParserStatement NewWhileStatement(ZonePtrList<const AstRawString>* labels, - int pos) { + PreParserStatement NewWhileStatement( + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, int pos) { return PreParserStatement::Default(); } @@ -807,25 +812,28 @@ class PreParserFactory { return PreParserStatement::Default(); } - PreParserStatement NewForStatement(ZonePtrList<const AstRawString>* labels, - int pos) { + PreParserStatement NewForStatement( + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, int pos) { return PreParserStatement::Default(); } PreParserStatement NewForEachStatement( ForEachStatement::VisitMode visit_mode, - ZonePtrList<const AstRawString>* labels, int pos) { + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, int pos) { return PreParserStatement::Default(); } - PreParserStatement NewForOfStatement(ZonePtrList<const AstRawString>* labels, - int pos) { + PreParserStatement NewForOfStatement( + ZonePtrList<const AstRawString>* labels, + ZonePtrList<const AstRawString>* own_labels, int pos) { return PreParserStatement::Default(); } - PreParserExpression NewCallRuntime(Runtime::FunctionId id, - ZoneList<PreParserExpression>* arguments, - int pos) { + PreParserExpression NewCallRuntime( + Runtime::FunctionId id, ZoneChunkList<PreParserExpression>* arguments, + int pos) { return PreParserExpression::Default(); } @@ -1070,12 +1078,11 @@ class PreParser : public ParserBase<PreParser> { const DeclarationParsingResult::Declaration* declaration, ZonePtrList<const AstRawString>* names, bool* ok); - V8_INLINE ZonePtrList<const AstRawString>* DeclareLabel( - ZonePtrList<const AstRawString>* labels, const PreParserExpression& expr, - bool* ok) { + V8_INLINE void DeclareLabel(ZonePtrList<const AstRawString>** labels, + ZonePtrList<const AstRawString>** own_labels, + const PreParserExpression& expr, bool* ok) { DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait()); DCHECK(IsIdentifier(expr)); - return labels; } // TODO(nikolaos): The preparser currently does not keep track of labels. @@ -1726,7 +1733,7 @@ class PreParser : public ParserBase<PreParser> { const PreParserExpression& value, const PreParserExpression& identifier) { } - V8_INLINE ZoneList<typename ExpressionClassifier::Error>* + V8_INLINE ZoneVector<typename ExpressionClassifier::Error>* GetReportedErrorList() const { return function_state_->GetReportedErrorList(); } diff --git a/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc index 052b6007ae..d38fdd7c42 100644 --- a/deps/v8/src/parsing/scanner-character-streams.cc +++ b/deps/v8/src/parsing/scanner-character-streams.cc @@ -88,8 +88,8 @@ class ExternalStringStream { template <typename Char> class ChunkedStream { public: - explicit ChunkedStream(ScriptCompiler::ExternalSourceStream* source, - RuntimeCallStats* stats) + ChunkedStream(ScriptCompiler::ExternalSourceStream* source, + RuntimeCallStats* stats) : source_(source), stats_(stats) {} Range<Char> GetDataAt(size_t pos) { @@ -100,15 +100,15 @@ class ChunkedStream { } ~ChunkedStream() { - for (size_t i = 0; i < chunks_.size(); i++) { - delete[] chunks_[i].data; - } + for (Chunk& chunk : chunks_) delete[] chunk.data; } static const bool kCanAccessHeap = false; private: struct Chunk { + Chunk(const Char* const data, size_t position, size_t length) + : data(data), position(position), length(length) {} const Char* const data; // The logical position of data. const size_t position; @@ -117,7 +117,7 @@ class ChunkedStream { }; Chunk FindChunk(size_t position) { - if (chunks_.empty()) FetchChunk(size_t{0}); + while (V8_UNLIKELY(chunks_.empty())) FetchChunk(size_t{0}); // Walk forwards while the position is in front of the current chunk. while (position >= chunks_.back().end_position() && @@ -134,6 +134,14 @@ class ChunkedStream { UNREACHABLE(); } + virtual void ProcessChunk(const uint8_t* data, size_t position, + size_t length) { + // Incoming data has to be aligned to Char size. + DCHECK_EQ(0, length % sizeof(Char)); + chunks_.emplace_back(reinterpret_cast<const Char*>(data), position, + length / sizeof(Char)); + } + void FetchChunk(size_t position) { const uint8_t* data = nullptr; size_t length; @@ -142,21 +150,110 @@ class ChunkedStream { RuntimeCallCounterId::kGetMoreDataCallback); length = source_->GetMoreData(&data); } - // Incoming data has to be aligned to Char size. - DCHECK_EQ(0, length % sizeof(Char)); - chunks_.push_back( - {reinterpret_cast<const Char*>(data), position, length / sizeof(Char)}); + ProcessChunk(data, position, length); } - std::vector<struct Chunk> chunks_; ScriptCompiler::ExternalSourceStream* source_; RuntimeCallStats* stats_; + + protected: + std::vector<struct Chunk> chunks_; +}; + +template <typename Char> +class Utf8ChunkedStream : public ChunkedStream<uint16_t> { + public: + Utf8ChunkedStream(ScriptCompiler::ExternalSourceStream* source, + RuntimeCallStats* stats) + : ChunkedStream<uint16_t>(source, stats) {} + + STATIC_ASSERT(sizeof(Char) == sizeof(uint16_t)); + void ProcessChunk(const uint8_t* data, size_t position, size_t length) final { + if (length == 0) { + unibrow::uchar t = unibrow::Utf8::ValueOfIncrementalFinish(&state_); + if (t != unibrow::Utf8::kBufferEmpty) { + DCHECK_EQ(t, unibrow::Utf8::kBadChar); + incomplete_char_ = 0; + uint16_t* result = new uint16_t[1]; + result[0] = unibrow::Utf8::kBadChar; + chunks_.emplace_back(result, position, 1); + position++; + } + chunks_.emplace_back(nullptr, position, 0); + delete[] data; + return; + } + + // First count the number of complete characters that can be produced. + + unibrow::Utf8::State state = state_; + uint32_t incomplete_char = incomplete_char_; + bool seen_bom = seen_bom_; + + size_t i = 0; + size_t chars = 0; + while (i < length) { + unibrow::uchar t = unibrow::Utf8::ValueOfIncremental(data[i], &i, &state, + &incomplete_char); + if (!seen_bom && t == kUtf8Bom && position + chars == 0) { + seen_bom = true; + // BOM detected at beginning of the stream. Don't copy it. + } else if (t != unibrow::Utf8::kIncomplete) { + chars++; + if (t > unibrow::Utf16::kMaxNonSurrogateCharCode) chars++; + } + } + + // Process the data. + + // If there aren't any complete characters, update the state without + // producing a chunk. + if (chars == 0) { + state_ = state; + incomplete_char_ = incomplete_char; + seen_bom_ = seen_bom; + delete[] data; + return; + } + + // Update the state and produce a chunk with complete characters. + uint16_t* result = new uint16_t[chars]; + uint16_t* cursor = result; + i = 0; + + while (i < length) { + unibrow::uchar t = unibrow::Utf8::ValueOfIncremental(data[i], &i, &state_, + &incomplete_char_); + if (V8_LIKELY(t < kUtf8Bom)) { + *(cursor++) = static_cast<uc16>(t); // The by most frequent case. + } else if (t == unibrow::Utf8::kIncomplete) { + continue; + } else if (!seen_bom_ && t == kUtf8Bom && position == 0 && + cursor == result) { + // BOM detected at beginning of the stream. Don't copy it. + seen_bom_ = true; + } else if (t <= unibrow::Utf16::kMaxNonSurrogateCharCode) { + *(cursor++) = static_cast<uc16>(t); + } else { + *(cursor++) = unibrow::Utf16::LeadSurrogate(t); + *(cursor++) = unibrow::Utf16::TrailSurrogate(t); + } + } + + chunks_.emplace_back(result, position, chars); + delete[] data; + } + + private: + uint32_t incomplete_char_ = 0; + unibrow::Utf8::State state_ = unibrow::Utf8::State::kAccept; + bool seen_bom_ = false; }; // Provides a buffered utf-16 view on the bytes from the underlying ByteStream. // Chars are buffered if either the underlying stream isn't utf-16 or the // underlying utf-16 stream might move (is on-heap). -template <typename Char, template <typename T> class ByteStream> +template <template <typename T> class ByteStream> class BufferedCharacterStream : public Utf16CharacterStream { public: template <class... TArgs> @@ -165,13 +262,13 @@ class BufferedCharacterStream : public Utf16CharacterStream { } protected: - bool ReadBlock() override { + bool ReadBlock() final { size_t position = pos(); buffer_pos_ = position; buffer_start_ = &buffer_[0]; buffer_cursor_ = buffer_start_; - Range<Char> range = byte_stream_.GetDataAt(position); + Range<uint8_t> range = byte_stream_.GetDataAt(position); if (range.length() == 0) { buffer_end_ = buffer_start_; return false; @@ -183,14 +280,12 @@ class BufferedCharacterStream : public Utf16CharacterStream { return true; } - bool can_access_heap() override { - return ByteStream<uint16_t>::kCanAccessHeap; - } + bool can_access_heap() final { return ByteStream<uint8_t>::kCanAccessHeap; } private: static const size_t kBufferSize = 512; uc16 buffer_[kBufferSize]; - ByteStream<Char> byte_stream_; + ByteStream<uint8_t> byte_stream_; }; // Provides a unbuffered utf-16 view on the bytes from the underlying @@ -200,12 +295,11 @@ class UnbufferedCharacterStream : public Utf16CharacterStream { public: template <class... TArgs> UnbufferedCharacterStream(size_t pos, TArgs... args) : byte_stream_(args...) { - DCHECK(!ByteStream<uint16_t>::kCanAccessHeap); buffer_pos_ = pos; } protected: - bool ReadBlock() override { + bool ReadBlock() final { size_t position = pos(); buffer_pos_ = position; Range<uint16_t> range = byte_stream_.GetDataAt(position); @@ -219,12 +313,50 @@ class UnbufferedCharacterStream : public Utf16CharacterStream { return true; } - bool can_access_heap() override { return false; } + bool can_access_heap() final { return ByteStream<uint16_t>::kCanAccessHeap; } - private: ByteStream<uint16_t> byte_stream_; }; +// Provides a unbuffered utf-16 view on the bytes from the underlying +// ByteStream. +class RelocatingCharacterStream + : public UnbufferedCharacterStream<OnHeapStream> { + public: + template <class... TArgs> + RelocatingCharacterStream(Isolate* isolate, size_t pos, TArgs... args) + : UnbufferedCharacterStream<OnHeapStream>(pos, args...), + isolate_(isolate) { + isolate->heap()->AddGCEpilogueCallback(UpdateBufferPointersCallback, + v8::kGCTypeAll, this); + } + + private: + ~RelocatingCharacterStream() final { + isolate_->heap()->RemoveGCEpilogueCallback(UpdateBufferPointersCallback, + this); + } + + static void UpdateBufferPointersCallback(v8::Isolate* v8_isolate, + v8::GCType type, + v8::GCCallbackFlags flags, + void* stream) { + reinterpret_cast<RelocatingCharacterStream*>(stream) + ->UpdateBufferPointers(); + } + + void UpdateBufferPointers() { + Range<uint16_t> range = byte_stream_.GetDataAt(0); + if (range.start != buffer_start_) { + buffer_cursor_ = (buffer_cursor_ - buffer_start_) + range.start; + buffer_start_ = range.start; + buffer_end_ = range.end; + } + } + + Isolate* isolate_; +}; + // ---------------------------------------------------------------------------- // BufferedUtf16CharacterStreams // @@ -240,7 +372,7 @@ class BufferedUtf16CharacterStream : public Utf16CharacterStream { protected: static const size_t kBufferSize = 512; - bool ReadBlock() override; + bool ReadBlock() final; // FillBuffer should read up to kBufferSize characters at position and store // them into buffer_[0..]. It returns the number of characters stored. @@ -285,14 +417,14 @@ class Utf8ExternalStreamingStream : public BufferedUtf16CharacterStream { : current_({0, {0, 0, 0, unibrow::Utf8::State::kAccept}}), source_stream_(source_stream), stats_(stats) {} - ~Utf8ExternalStreamingStream() override { + ~Utf8ExternalStreamingStream() final { for (size_t i = 0; i < chunks_.size(); i++) delete[] chunks_[i].data; } - bool can_access_heap() override { return false; } + bool can_access_heap() final { return false; } protected: - size_t FillBuffer(size_t position) override; + size_t FillBuffer(size_t position) final; private: // A position within the data stream. It stores: @@ -571,7 +703,7 @@ Utf16CharacterStream* ScannerStream::For(Isolate* isolate, Handle<String> data, data = String::Flatten(isolate, data); } if (data->IsExternalOneByteString()) { - return new BufferedCharacterStream<uint8_t, ExternalStringStream>( + return new BufferedCharacterStream<ExternalStringStream>( static_cast<size_t>(start_pos), ExternalOneByteString::cast(*data)->GetChars() + start_offset, static_cast<size_t>(end_pos)); @@ -581,13 +713,14 @@ Utf16CharacterStream* ScannerStream::For(Isolate* isolate, Handle<String> data, ExternalTwoByteString::cast(*data)->GetChars() + start_offset, static_cast<size_t>(end_pos)); } else if (data->IsSeqOneByteString()) { - return new BufferedCharacterStream<uint8_t, OnHeapStream>( + return new BufferedCharacterStream<OnHeapStream>( static_cast<size_t>(start_pos), Handle<SeqOneByteString>::cast(data), start_offset, static_cast<size_t>(end_pos)); } else if (data->IsSeqTwoByteString()) { - return new BufferedCharacterStream<uint16_t, OnHeapStream>( - static_cast<size_t>(start_pos), Handle<SeqTwoByteString>::cast(data), - start_offset, static_cast<size_t>(end_pos)); + return new RelocatingCharacterStream( + isolate, static_cast<size_t>(start_pos), + Handle<SeqTwoByteString>::cast(data), start_offset, + static_cast<size_t>(end_pos)); } else { UNREACHABLE(); } @@ -601,7 +734,7 @@ std::unique_ptr<Utf16CharacterStream> ScannerStream::ForTesting( std::unique_ptr<Utf16CharacterStream> ScannerStream::ForTesting( const char* data, size_t length) { return std::unique_ptr<Utf16CharacterStream>( - new BufferedCharacterStream<uint8_t, ExternalStringStream>( + new BufferedCharacterStream<ExternalStringStream>( static_cast<size_t>(0), reinterpret_cast<const uint8_t*>(data), static_cast<size_t>(length))); } @@ -615,8 +748,8 @@ Utf16CharacterStream* ScannerStream::For( return new UnbufferedCharacterStream<ChunkedStream>( static_cast<size_t>(0), source_stream, stats); case v8::ScriptCompiler::StreamedSource::ONE_BYTE: - return new BufferedCharacterStream<uint8_t, ChunkedStream>( - static_cast<size_t>(0), source_stream, stats); + return new BufferedCharacterStream<ChunkedStream>(static_cast<size_t>(0), + source_stream, stats); case v8::ScriptCompiler::StreamedSource::UTF8: return new Utf8ExternalStreamingStream(source_stream, stats); } diff --git a/deps/v8/src/parsing/scanner-character-streams.h b/deps/v8/src/parsing/scanner-character-streams.h index 12c5847f2f..091ef5b8ea 100644 --- a/deps/v8/src/parsing/scanner-character-streams.h +++ b/deps/v8/src/parsing/scanner-character-streams.h @@ -27,7 +27,6 @@ class V8_EXPORT_PRIVATE ScannerStream { ScriptCompiler::StreamedSource::Encoding encoding, RuntimeCallStats* stats); - // For testing: static std::unique_ptr<Utf16CharacterStream> ForTesting(const char* data); static std::unique_ptr<Utf16CharacterStream> ForTesting(const char* data, size_t length); diff --git a/deps/v8/src/parsing/scanner-inl.h b/deps/v8/src/parsing/scanner-inl.h new file mode 100644 index 0000000000..809ef655a7 --- /dev/null +++ b/deps/v8/src/parsing/scanner-inl.h @@ -0,0 +1,43 @@ +// Copyright 2018 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_SCANNER_INL_H_ +#define V8_PARSING_SCANNER_INL_H_ + +#include "src/parsing/scanner.h" +#include "src/unicode-cache-inl.h" + +namespace v8 { +namespace internal { + +V8_INLINE Token::Value Scanner::SkipWhiteSpace() { + int start_position = source_pos(); + + while (true) { + // We won't skip behind the end of input. + DCHECK(!unicode_cache_->IsWhiteSpace(kEndOfInput)); + + // Advance as long as character is a WhiteSpace or LineTerminator. + // Remember if the latter is the case. + if (unibrow::IsLineTerminator(c0_)) { + next().after_line_terminator = true; + } else if (!unicode_cache_->IsWhiteSpace(c0_)) { + break; + } + Advance(); + } + + // Return whether or not we skipped any characters. + if (source_pos() == start_position) { + DCHECK_NE('0', c0_); + return Token::ILLEGAL; + } + + return Token::WHITESPACE; +} + +} // namespace internal +} // namespace v8 + +#endif // V8_PARSING_SCANNER_INL_H_ diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc index 852b5e400b..781832c2e6 100644 --- a/deps/v8/src/parsing/scanner.cc +++ b/deps/v8/src/parsing/scanner.cc @@ -15,7 +15,7 @@ #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" +#include "src/parsing/scanner-inl.h" namespace v8 { namespace internal { @@ -60,6 +60,7 @@ class Scanner::ErrorState { // Scanner::LiteralBuffer Handle<String> Scanner::LiteralBuffer::Internalize(Isolate* isolate) const { + DCHECK(is_used_); if (is_one_byte()) { return isolate->factory()->InternalizeOneByteString(one_byte_literal()); } @@ -103,16 +104,9 @@ void Scanner::LiteralBuffer::ConvertToTwoByte() { is_one_byte_ = false; } -void Scanner::LiteralBuffer::AddCharSlow(uc32 code_unit) { +void Scanner::LiteralBuffer::AddTwoByteChar(uc32 code_unit) { + DCHECK(!is_one_byte_); if (position_ >= backing_store_.length()) ExpandBuffer(); - if (is_one_byte_) { - if (code_unit <= static_cast<uc32>(unibrow::Latin1::kMaxChar)) { - backing_store_[position_] = static_cast<byte>(code_unit); - position_ += kOneByteSize; - return; - } - ConvertToTwoByte(); - } if (code_unit <= static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) { *reinterpret_cast<uint16_t*>(&backing_store_[position_]) = code_unit; @@ -140,16 +134,16 @@ const size_t Scanner::BookmarkScope::kBookmarkWasApplied = void Scanner::BookmarkScope::Set() { DCHECK_EQ(bookmark_, kNoBookmark); - DCHECK_EQ(scanner_->next_next_.token, Token::UNINITIALIZED); + DCHECK_EQ(scanner_->next_next().token, Token::UNINITIALIZED); // The first token is a bit special, since current_ will still be // uninitialized. In this case, store kBookmarkAtFirstPos and special-case it // when // applying the bookmark. - DCHECK_IMPLIES( - scanner_->current_.token == Token::UNINITIALIZED, - scanner_->current_.location.beg_pos == scanner_->next_.location.beg_pos); - bookmark_ = (scanner_->current_.token == Token::UNINITIALIZED) + DCHECK_IMPLIES(scanner_->current().token == Token::UNINITIALIZED, + scanner_->current().location.beg_pos == + scanner_->next().location.beg_pos); + bookmark_ = (scanner_->current().token == Token::UNINITIALIZED) ? kBookmarkAtFirstPos : scanner_->location().beg_pos; } @@ -177,22 +171,24 @@ bool Scanner::BookmarkScope::HasBeenApplied() { // ---------------------------------------------------------------------------- // Scanner -Scanner::Scanner(UnicodeCache* unicode_cache) +Scanner::Scanner(UnicodeCache* unicode_cache, Utf16CharacterStream* source, + bool is_module) : unicode_cache_(unicode_cache), + source_(source), octal_pos_(Location::invalid()), octal_message_(MessageTemplate::kNone), found_html_comment_(false), allow_harmony_bigint_(false), - allow_harmony_numeric_separator_(false) {} - -void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) { + allow_harmony_numeric_separator_(false), + is_module_(is_module) { DCHECK_NOT_NULL(source); - source_ = source; - is_module_ = is_module; +} + +void Scanner::Initialize() { // Need to capture identifiers in order to recognize "get" and "set" // in object literals. Init(); - has_line_terminator_before_next_ = true; + next().after_line_terminator = true; Scan(); } @@ -377,96 +373,43 @@ static const byte one_char_tokens[] = { // clang-format on Token::Value Scanner::Next() { - if (next_.token == Token::EOS) { - next_.location.beg_pos = current_.location.beg_pos; - next_.location.end_pos = current_.location.end_pos; - } + if (next().token == Token::EOS) next().location = current().location; + // Rotate through tokens. + TokenDesc* previous = current_; current_ = next_; - if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) { + // Either we already have the next token lined up, in which case next_next_ + // simply becomes next_. In that case we use current_ as new next_next_ and + // clear its token to indicate that it wasn't scanned yet. Otherwise we use + // current_ as next_ and scan into it, leaving next_next_ uninitialized. + if (V8_LIKELY(next_next().token == Token::UNINITIALIZED)) { + next_ = previous; + next().after_line_terminator = false; + Scan(); + } else { next_ = next_next_; - next_next_.token = Token::UNINITIALIZED; - next_next_.contextual_token = Token::UNINITIALIZED; - has_line_terminator_before_next_ = has_line_terminator_after_next_; - return current_.token; + next_next_ = previous; + previous->token = Token::UNINITIALIZED; + previous->contextual_token = Token::UNINITIALIZED; + DCHECK_NE(Token::UNINITIALIZED, current().token); } - has_line_terminator_before_next_ = false; - has_multiline_comment_before_next_ = false; - Scan(); - return current_.token; + return current().token; } Token::Value Scanner::PeekAhead() { - DCHECK(next_.token != Token::DIV); - DCHECK(next_.token != Token::ASSIGN_DIV); - - if (next_next_.token != Token::UNINITIALIZED) { - return next_next_.token; - } - TokenDesc prev = current_; - bool has_line_terminator_before_next = - has_line_terminator_before_next_ || has_multiline_comment_before_next_; - Next(); - has_line_terminator_after_next_ = - has_line_terminator_before_next_ || has_multiline_comment_before_next_; - has_line_terminator_before_next_ = has_line_terminator_before_next; - Token::Value ret = next_.token; - next_next_ = next_; - next_ = current_; - current_ = prev; - return ret; -} - - -Token::Value Scanner::SkipWhiteSpace() { - int start_position = source_pos(); - - while (true) { - while (true) { - // We won't skip behind the end of input. - DCHECK(!unicode_cache_->IsWhiteSpace(kEndOfInput)); - - // Advance as long as character is a WhiteSpace or LineTerminator. - // Remember if the latter is the case. - if (unibrow::IsLineTerminator(c0_)) { - has_line_terminator_before_next_ = true; - } else if (!unicode_cache_->IsWhiteSpace(c0_)) { - break; - } - Advance(); - } + DCHECK(next().token != Token::DIV); + DCHECK(next().token != Token::ASSIGN_DIV); - // If there is an HTML comment end '-->' at the beginning of a - // line (with only whitespace in front of it), we treat the rest - // of the line as a comment. This is in line with the way - // SpiderMonkey handles it. - if (c0_ != '-' || !has_line_terminator_before_next_) break; - - Advance(); - if (c0_ != '-') { - PushBack('-'); // undo Advance() - break; - } - - Advance(); - if (c0_ != '>') { - PushBack2('-', '-'); // undo 2x Advance(); - break; - } - - // Treat the rest of the line as a comment. - Token::Value token = SkipSingleHTMLComment(); - if (token == Token::ILLEGAL) { - return token; - } + if (next_next().token != Token::UNINITIALIZED) { + return next_next().token; } - - // Return whether or not we skipped any characters. - if (source_pos() == start_position) { - return Token::ILLEGAL; - } - - return Token::WHITESPACE; + TokenDesc* temp = next_; + next_ = next_next_; + next().after_line_terminator = false; + Scan(); + next_next_ = next_; + next_ = temp; + return next_next().token; } Token::Value Scanner::SkipSingleHTMLComment() { @@ -478,21 +421,16 @@ Token::Value Scanner::SkipSingleHTMLComment() { } Token::Value Scanner::SkipSingleLineComment() { - Advance(); - // The line terminator at the end of the line is not considered // to be part of the single-line comment; it is recognized // separately by the lexical grammar and becomes part of the // stream of input elements for the syntactic grammar (see // ECMA-262, section 7.4). - while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { - Advance(); - } + AdvanceUntil([](uc32 c0_) { return unibrow::IsLineTerminator(c0_); }); return Token::WHITESPACE; } - Token::Value Scanner::SkipSourceURLComment() { TryToParseSourceURLComment(); while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { @@ -502,7 +440,6 @@ Token::Value Scanner::SkipSourceURLComment() { return Token::WHITESPACE; } - void Scanner::TryToParseSourceURLComment() { // Magic comments are of the form: //[#@]\s<name>=\s*<value>\s*.* and this // function will just return if it cannot parse a magic comment. @@ -510,6 +447,7 @@ void Scanner::TryToParseSourceURLComment() { if (!unicode_cache_->IsWhiteSpace(c0_)) return; Advance(); LiteralBuffer name; + name.Start(); while (c0_ != kEndOfInput && !unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_) && c0_ != '=') { @@ -528,15 +466,16 @@ void Scanner::TryToParseSourceURLComment() { } if (c0_ != '=') return; + value->Drop(); + value->Start(); Advance(); - value->Reset(); while (unicode_cache_->IsWhiteSpace(c0_)) { Advance(); } while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { // Disallowed characters. if (c0_ == '"' || c0_ == '\'') { - value->Reset(); + value->Drop(); return; } if (unicode_cache_->IsWhiteSpace(c0_)) { @@ -548,34 +487,33 @@ void Scanner::TryToParseSourceURLComment() { // Allow whitespace at the end. while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { if (!unicode_cache_->IsWhiteSpace(c0_)) { - value->Reset(); + value->Drop(); break; } Advance(); } } - Token::Value Scanner::SkipMultiLineComment() { DCHECK_EQ(c0_, '*'); Advance(); while (c0_ != kEndOfInput) { - uc32 ch = c0_; - Advance(); DCHECK(!unibrow::IsLineTerminator(kEndOfInput)); - if (unibrow::IsLineTerminator(ch)) { + if (!HasLineTerminatorBeforeNext() && unibrow::IsLineTerminator(c0_)) { // Following ECMA-262, section 7.4, a comment containing // a newline will make the comment count as a line-terminator. - has_multiline_comment_before_next_ = true; + next().after_line_terminator = true; } - // If we have reached the end of the multi-line comment, we - // consume the '/' and insert a whitespace. This way all - // multi-line comments are treated as whitespace. - if (ch == '*' && c0_ == '/') { - c0_ = ' '; - return Token::WHITESPACE; + + while (V8_UNLIKELY(c0_ == '*')) { + Advance(); + if (c0_ == '/') { + Advance(); + return Token::WHITESPACE; + } } + Advance(); } // Unterminated multi-line comment. @@ -586,25 +524,20 @@ Token::Value Scanner::ScanHtmlComment() { // Check for <!-- comments. DCHECK_EQ(c0_, '!'); Advance(); - if (c0_ != '-') { + if (c0_ != '-' || Peek() != '-') { PushBack('!'); // undo Advance() return Token::LT; } - Advance(); - if (c0_ != '-') { - PushBack2('-', '!'); // undo 2x Advance() - return Token::LT; - } found_html_comment_ = true; return SkipSingleHTMLComment(); } void Scanner::Scan() { - next_.literal_chars = nullptr; - next_.raw_literal_chars = nullptr; - next_.invalid_template_escape_message = MessageTemplate::kNone; + next().literal_chars.Drop(); + next().raw_literal_chars.Drop(); + next().invalid_template_escape_message = MessageTemplate::kNone; Token::Value token; do { @@ -612,17 +545,17 @@ void Scanner::Scan() { Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]); if (token != Token::ILLEGAL) { int pos = source_pos(); - next_.token = token; - next_.contextual_token = Token::UNINITIALIZED; - next_.location.beg_pos = pos; - next_.location.end_pos = pos + 1; + next().token = token; + next().contextual_token = Token::UNINITIALIZED; + next().location.beg_pos = pos; + next().location.end_pos = pos + 1; Advance(); return; } } // Remember the position of the next token - next_.location.beg_pos = source_pos(); + next().location.beg_pos = source_pos(); switch (c0_) { case '"': @@ -703,7 +636,7 @@ void Scanner::Scan() { Advance(); if (c0_ == '-') { Advance(); - if (c0_ == '>' && HasAnyLineTerminatorBeforeNext()) { + if (c0_ == '>' && HasLineTerminatorBeforeNext()) { // For compatibility with SpiderMonkey, we skip lines that // start with an HTML comment end '-->'. token = SkipSingleHTMLComment(); @@ -738,12 +671,12 @@ void Scanner::Scan() { // / // /* /= Advance(); if (c0_ == '/') { - Advance(); - if (c0_ == '#' || c0_ == '@') { + uc32 c = Peek(); + if (c == '#' || c == '@') { + Advance(); Advance(); token = SkipSourceURLComment(); } else { - PushBack(c0_); token = SkipSingleLineComment(); } } else if (c0_ == '*') { @@ -792,12 +725,10 @@ void Scanner::Scan() { } else { token = Token::PERIOD; if (c0_ == '.') { - Advance(); - if (c0_ == '.') { + if (Peek() == '.') { + Advance(); Advance(); token = Token::ELLIPSIS; - } else { - PushBack('.'); } } } @@ -831,19 +762,19 @@ void Scanner::Scan() { // whitespace. } while (token == Token::WHITESPACE); - next_.location.end_pos = source_pos(); + next().location.end_pos = source_pos(); if (Token::IsContextualKeyword(token)) { - next_.token = Token::IDENTIFIER; - next_.contextual_token = token; + next().token = Token::IDENTIFIER; + next().contextual_token = token; } else { - next_.token = token; - next_.contextual_token = Token::UNINITIALIZED; + next().token = token; + next().contextual_token = Token::UNINITIALIZED; } #ifdef DEBUG - SanityCheckTokenDesc(current_); - SanityCheckTokenDesc(next_); - SanityCheckTokenDesc(next_next_); + SanityCheckTokenDesc(current()); + SanityCheckTokenDesc(next()); + SanityCheckTokenDesc(next_next()); #endif } @@ -864,8 +795,8 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const { break; case Token::TEMPLATE_SPAN: case Token::TEMPLATE_TAIL: - DCHECK_NOT_NULL(token.raw_literal_chars); - DCHECK_NOT_NULL(token.literal_chars); + DCHECK(token.raw_literal_chars.is_used()); + DCHECK(token.literal_chars.is_used()); break; case Token::ESCAPED_KEYWORD: case Token::ESCAPED_STRICT_RESERVED_WORD: @@ -877,13 +808,13 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const { case Token::SMI: case Token::STRING: case Token::PRIVATE_NAME: - DCHECK_NOT_NULL(token.literal_chars); - DCHECK_NULL(token.raw_literal_chars); + DCHECK(token.literal_chars.is_used()); + DCHECK(!token.raw_literal_chars.is_used()); DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone); break; default: - DCHECK_NULL(token.literal_chars); - DCHECK_NULL(token.raw_literal_chars); + DCHECK(!token.literal_chars.is_used()); + DCHECK(!token.raw_literal_chars.is_used()); DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone); break; } @@ -900,9 +831,9 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const { void Scanner::SeekForward(int pos) { // After this call, we will have the token at the given position as // the "next" token. The "current" token will be invalid. - if (pos == next_.location.beg_pos) return; + if (pos == next().location.beg_pos) return; int current_pos = source_pos(); - DCHECK_EQ(next_.location.end_pos, current_pos); + DCHECK_EQ(next().location.end_pos, current_pos); // Positions inside the lookahead token aren't supported. DCHECK(pos >= current_pos); if (pos != current_pos) { @@ -911,23 +842,21 @@ void Scanner::SeekForward(int pos) { // This function is only called to seek to the location // of the end of a function (at the "}" token). It doesn't matter // whether there was a line terminator in the part we skip. - has_line_terminator_before_next_ = false; - has_multiline_comment_before_next_ = false; + next().after_line_terminator = false; } Scan(); } - -template <bool capture_raw, bool in_template_literal> +template <bool capture_raw> bool Scanner::ScanEscape() { uc32 c = c0_; Advance<capture_raw>(); // Skip escaped newlines. DCHECK(!unibrow::IsLineTerminator(kEndOfInput)); - if (!in_template_literal && unibrow::IsLineTerminator(c)) { + if (!capture_raw && unibrow::IsLineTerminator(c)) { // Allow escaped CR+LF newlines in multiline string literals. - if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance<capture_raw>(); + if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance(); return true; } @@ -961,7 +890,7 @@ bool Scanner::ScanEscape() { case '5': // fall through case '6': // fall through case '7': - c = ScanOctalEscape<capture_raw>(c, 2, in_template_literal); + c = ScanOctalEscape<capture_raw>(c, 2); break; } @@ -971,7 +900,7 @@ bool Scanner::ScanEscape() { } template <bool capture_raw> -uc32 Scanner::ScanOctalEscape(uc32 c, int length, bool in_template_literal) { +uc32 Scanner::ScanOctalEscape(uc32 c, int length) { uc32 x = c - '0'; int i = 0; for (; i < length; i++) { @@ -989,14 +918,12 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length, bool in_template_literal) { // occur before the "use strict" directive. if (c != '0' || i > 0 || c0_ == '8' || c0_ == '9') { octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1); - octal_message_ = in_template_literal - ? MessageTemplate::kTemplateOctalLiteral - : MessageTemplate::kStrictOctalEscape; + octal_message_ = capture_raw ? MessageTemplate::kTemplateOctalLiteral + : MessageTemplate::kStrictOctalEscape; } return x; } - Token::Value Scanner::ScanString() { uc32 quote = c0_; Advance(); // consume quote @@ -1014,7 +941,7 @@ Token::Value Scanner::ScanString() { if (c0_ == '\\') { Advance(); // TODO(verwaest): Check whether we can remove the additional check. - if (c0_ == kEndOfInput || !ScanEscape<false, false>()) { + if (c0_ == kEndOfInput || !ScanEscape<false>()) { return Token::ILLEGAL; } continue; @@ -1032,15 +959,14 @@ Token::Value Scanner::ScanPrivateName() { LiteralScope literal(this); DCHECK_EQ(c0_, '#'); - AddLiteralCharAdvance(); DCHECK(!unicode_cache_->IsIdentifierStart(kEndOfInput)); - if (!unicode_cache_->IsIdentifierStart(c0_)) { - PushBack(c0_); + if (!unicode_cache_->IsIdentifierStart(Peek())) { ReportScannerError(source_pos(), MessageTemplate::kInvalidOrUnexpectedToken); return Token::ILLEGAL; } + AddLiteralCharAdvance(); Token::Value token = ScanIdentifierOrKeywordInner(&literal); return token == Token::ILLEGAL ? Token::ILLEGAL : Token::PRIVATE_NAME; } @@ -1069,89 +995,87 @@ Token::Value Scanner::ScanTemplateSpan() { LiteralScope literal(this); StartRawLiteral(); const bool capture_raw = true; - const bool in_template_literal = true; while (true) { uc32 c = c0_; - Advance<capture_raw>(); if (c == '`') { + Advance(); // Consume '`' result = Token::TEMPLATE_TAIL; - ReduceRawLiteralLength(1); break; - } else if (c == '$' && c0_ == '{') { - Advance<capture_raw>(); // Consume '{' - ReduceRawLiteralLength(2); + } else if (c == '$' && Peek() == '{') { + Advance(); // Consume '$' + Advance(); // Consume '{' break; } else if (c == '\\') { + Advance(); // Consume '\\' DCHECK(!unibrow::IsLineTerminator(kEndOfInput)); + if (capture_raw) AddRawLiteralChar('\\'); if (unibrow::IsLineTerminator(c0_)) { // The TV of LineContinuation :: \ LineTerminatorSequence is the empty // code unit sequence. uc32 lastChar = c0_; - Advance<capture_raw>(); + Advance(); if (lastChar == '\r') { - ReduceRawLiteralLength(1); // Remove \r - if (c0_ == '\n') { - Advance<capture_raw>(); // Adds \n - } else { - AddRawLiteralChar('\n'); - } + // Also skip \n. + if (c0_ == '\n') Advance(); + lastChar = '\n'; } + if (capture_raw) AddRawLiteralChar(lastChar); } else { - bool success = ScanEscape<capture_raw, in_template_literal>(); + bool success = ScanEscape<capture_raw>(); USE(success); DCHECK_EQ(!success, has_error()); // For templates, invalid escape sequence checking is handled in the // parser. - scanner_error_state.MoveErrorTo(&next_); - octal_error_state.MoveErrorTo(&next_); + scanner_error_state.MoveErrorTo(next_); + octal_error_state.MoveErrorTo(next_); } } else if (c < 0) { // Unterminated template literal - PushBack(c); break; } else { + Advance(); // Consume c. // The TRV of LineTerminatorSequence :: <CR> is the CV 0x000A. // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence // consisting of the CV 0x000A. if (c == '\r') { - ReduceRawLiteralLength(1); // Remove \r - if (c0_ == '\n') { - Advance<capture_raw>(); // Adds \n - } else { - AddRawLiteralChar('\n'); - } + if (c0_ == '\n') Advance(); // Consume '\n' c = '\n'; } + if (capture_raw) AddRawLiteralChar(c); AddLiteralChar(c); } } literal.Complete(); - next_.location.end_pos = source_pos(); - next_.token = result; - next_.contextual_token = Token::UNINITIALIZED; + next().location.end_pos = source_pos(); + next().token = result; + next().contextual_token = Token::UNINITIALIZED; return result; } - Token::Value Scanner::ScanTemplateStart() { - DCHECK_EQ(next_next_.token, Token::UNINITIALIZED); + DCHECK_EQ(next_next().token, Token::UNINITIALIZED); DCHECK_EQ(c0_, '`'); - next_.location.beg_pos = source_pos(); + next().location.beg_pos = source_pos(); Advance(); // Consume ` return ScanTemplateSpan(); } Handle<String> Scanner::SourceUrl(Isolate* isolate) const { Handle<String> tmp; - if (source_url_.length() > 0) tmp = source_url_.Internalize(isolate); + if (source_url_.length() > 0) { + DCHECK(source_url_.is_used()); + tmp = source_url_.Internalize(isolate); + } return tmp; } Handle<String> Scanner::SourceMappingUrl(Isolate* isolate) const { Handle<String> tmp; - if (source_mapping_url_.length() > 0) + if (source_mapping_url_.length() > 0) { + DCHECK(source_mapping_url_.is_used()); tmp = source_mapping_url_.Internalize(isolate); + } return tmp; } @@ -1375,10 +1299,10 @@ Token::Value Scanner::ScanNumber(bool seen_period) { return Token::ILLEGAL; } - if (next_.literal_chars->one_byte_literal().length() <= 10 && + if (next().literal_chars.one_byte_literal().length() <= 10 && value <= Smi::kMaxValue && c0_ != '.' && !unicode_cache_->IsIdentifierStart(c0_)) { - next_.smi_value_ = static_cast<uint32_t>(value); + next().smi_value_ = static_cast<uint32_t>(value); literal.Complete(); if (kind == DECIMAL_WITH_LEADING_ZERO) { @@ -1448,7 +1372,6 @@ Token::Value Scanner::ScanNumber(bool seen_period) { return is_bigint ? Token::BIGINT : Token::NUMBER; } - uc32 Scanner::ScanIdentifierUnicodeEscape() { Advance(); if (c0_ != 'u') return -1; @@ -1456,7 +1379,6 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() { return ScanUnicodeEscape<false>(); } - template <bool capture_raw> uc32 Scanner::ScanUnicodeEscape() { // Accept both \uxxxx and \u{xxxxxx}. In the latter case, the number of @@ -1622,13 +1544,15 @@ Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) { bool escaped = false; if (IsInRange(c0_, 'a', 'z') || c0_ == '_') { do { - AddLiteralCharAdvance(); + AddLiteralChar(static_cast<char>(c0_)); + Advance(); } while (IsInRange(c0_, 'a', 'z') || c0_ == '_'); if (IsDecimalDigit(c0_) || IsInRange(c0_, 'A', 'Z') || c0_ == '$') { // Identifier starting with lowercase or _. do { - AddLiteralCharAdvance(); + AddLiteralChar(static_cast<char>(c0_)); + Advance(); } while (IsAsciiIdentifier(c0_)); if (c0_ <= kMaxAscii && c0_ != '\\') { @@ -1637,7 +1561,7 @@ Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) { } } else if (c0_ <= kMaxAscii && c0_ != '\\') { // Only a-z+ or _: could be a keyword or identifier. - Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); + Vector<const uint8_t> chars = next().literal_chars.one_byte_literal(); Token::Value token = KeywordOrIdentifierToken(chars.start(), chars.length()); if (token == Token::IDENTIFIER || @@ -1648,7 +1572,8 @@ Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) { } } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '$') { do { - AddLiteralCharAdvance(); + AddLiteralChar(static_cast<char>(c0_)); + Advance(); } while (IsAsciiIdentifier(c0_)); if (c0_ <= kMaxAscii && c0_ != '\\') { @@ -1686,8 +1611,8 @@ Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) { } } - if (next_.literal_chars->is_one_byte()) { - Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); + if (next().literal_chars.is_one_byte()) { + Vector<const uint8_t> chars = next().literal_chars.one_byte_literal(); Token::Value token = KeywordOrIdentifierToken(chars.start(), chars.length()); /* TODO(adamk): YIELD should be handled specially. */ @@ -1715,17 +1640,17 @@ Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) { } bool Scanner::ScanRegExpPattern() { - DCHECK(next_next_.token == Token::UNINITIALIZED); - DCHECK(next_.token == Token::DIV || next_.token == Token::ASSIGN_DIV); + DCHECK_EQ(Token::UNINITIALIZED, next_next().token); + DCHECK(next().token == Token::DIV || next().token == Token::ASSIGN_DIV); // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags bool in_character_class = false; - bool seen_equal = (next_.token == Token::ASSIGN_DIV); + bool seen_equal = (next().token == Token::ASSIGN_DIV); // Previous token is either '/' or '/=', in the second case, the // pattern starts at =. - next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1); - next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0); + next().location.beg_pos = source_pos() - (seen_equal ? 2 : 1); + next().location.end_pos = source_pos() - (seen_equal ? 1 : 0); // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5, // the scanner should pass uninterpreted bodies to the RegExp @@ -1764,14 +1689,14 @@ bool Scanner::ScanRegExpPattern() { Advance(); // consume '/' literal.Complete(); - next_.token = Token::REGEXP_LITERAL; - next_.contextual_token = Token::UNINITIALIZED; + next().token = Token::REGEXP_LITERAL; + next().contextual_token = Token::UNINITIALIZED; return true; } Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() { - DCHECK(next_.token == Token::REGEXP_LITERAL); + DCHECK_EQ(Token::REGEXP_LITERAL, next().token); // Scan regular expression flags. int flags = 0; @@ -1806,7 +1731,7 @@ Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() { flags |= flag; } - next_.location.end_pos = source_pos(); + next().location.end_pos = source_pos(); return Just(RegExp::Flags(flags)); } @@ -1869,24 +1794,17 @@ void Scanner::SeekNext(size_t position) { // 1, Reset the current_, next_ and next_next_ tokens // (next_ + next_next_ will be overwrittem by Next(), // current_ will remain unchanged, so overwrite it fully.) - current_ = {{0, 0}, - nullptr, - nullptr, - 0, - Token::UNINITIALIZED, - MessageTemplate::kNone, - {0, 0}, - Token::UNINITIALIZED}; - next_.token = Token::UNINITIALIZED; - next_.contextual_token = Token::UNINITIALIZED; - next_next_.token = Token::UNINITIALIZED; - next_next_.contextual_token = Token::UNINITIALIZED; + for (TokenDesc& token : token_storage_) { + token.token = Token::UNINITIALIZED; + token.contextual_token = Token::UNINITIALIZED; + } // 2, reset the source to the desired position, source_->Seek(position); // 3, re-scan, by scanning the look-ahead char + 1 token (next_). c0_ = source_->Advance(); - Next(); - DCHECK_EQ(next_.location.beg_pos, static_cast<int>(position)); + next().after_line_terminator = false; + Scan(); + DCHECK_EQ(next().location.beg_pos, static_cast<int>(position)); } } // namespace internal diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h index 34da5fafbf..e592debd8e 100644 --- a/deps/v8/src/parsing/scanner.h +++ b/deps/v8/src/parsing/scanner.h @@ -7,6 +7,8 @@ #ifndef V8_PARSING_SCANNER_H_ #define V8_PARSING_SCANNER_H_ +#include <algorithm> + #include "src/allocation.h" #include "src/base/logging.h" #include "src/char-predicates.h" @@ -36,25 +38,51 @@ class Utf16CharacterStream { public: static const uc32 kEndOfInput = -1; - virtual ~Utf16CharacterStream() { } + virtual ~Utf16CharacterStream() {} - // Returns and advances past the next UTF-16 code unit in the input - // stream. If there are no more code units it returns kEndOfInput. - inline uc32 Advance() { + inline uc32 Peek() { if (V8_LIKELY(buffer_cursor_ < buffer_end_)) { - return static_cast<uc32>(*(buffer_cursor_++)); + return static_cast<uc32>(*buffer_cursor_); } else if (ReadBlockChecked()) { - return static_cast<uc32>(*(buffer_cursor_++)); + return static_cast<uc32>(*buffer_cursor_); } else { - // Note: currently the following increment is necessary to avoid a - // parser problem! The scanner treats the final kEndOfInput as - // a code unit with a position, and does math relative to that - // position. - buffer_cursor_++; return kEndOfInput; } } + // Returns and advances past the next UTF-16 code unit in the input + // stream. If there are no more code units it returns kEndOfInput. + inline uc32 Advance() { + uc32 result = Peek(); + buffer_cursor_++; + return result; + } + + // Returns and advances past the next UTF-16 code unit in the input stream + // that meets the checks requirement. If there are no more code units it + // returns kEndOfInput. + template <typename FunctionType> + V8_INLINE uc32 AdvanceUntil(FunctionType check) { + while (true) { + auto next_cursor_pos = + std::find_if(buffer_cursor_, buffer_end_, [&check](uint16_t raw_c0_) { + uc32 c0_ = static_cast<uc32>(raw_c0_); + return check(c0_); + }); + + if (next_cursor_pos == buffer_end_) { + buffer_cursor_ = buffer_end_; + if (!ReadBlockChecked()) { + buffer_cursor_++; + return kEndOfInput; + } + } else { + buffer_cursor_ = next_cursor_pos + 1; + return static_cast<uc32>(*next_cursor_pos); + } + } + } + // Go back one by one character in the input stream. // This undoes the most recent Advance(). inline void Back() { @@ -68,17 +96,6 @@ class Utf16CharacterStream { } } - // Go back one by two characters in the input stream. (This is the same as - // calling Back() twice. But Back() may - in some instances - do substantial - // work. Back2() guarantees this work will be done only once.) - inline void Back2() { - if (V8_LIKELY(buffer_cursor_ - 2 >= buffer_start_)) { - buffer_cursor_ -= 2; - } else { - ReadBlockAt(pos() - 2); - } - } - inline size_t pos() const { return buffer_pos_ + (buffer_cursor_ - buffer_start_); } @@ -157,7 +174,6 @@ class Utf16CharacterStream { size_t buffer_pos_; }; - // ---------------------------------------------------------------------------- // JavaScript Scanner. @@ -207,23 +223,24 @@ class Scanner { static const int kNoOctalLocation = -1; static const uc32 kEndOfInput = Utf16CharacterStream::kEndOfInput; - explicit Scanner(UnicodeCache* scanner_contants); + explicit Scanner(UnicodeCache* scanner_contants, Utf16CharacterStream* source, + bool is_module); - void Initialize(Utf16CharacterStream* source, bool is_module); + void Initialize(); // Returns the next token and advances input. Token::Value Next(); // Returns the token following peek() Token::Value PeekAhead(); // Returns the current token again. - Token::Value current_token() { return current_.token; } + Token::Value current_token() { return current().token; } - Token::Value current_contextual_token() { return current_.contextual_token; } - Token::Value next_contextual_token() { return next_.contextual_token; } + Token::Value current_contextual_token() { return current().contextual_token; } + Token::Value next_contextual_token() { return next().contextual_token; } // Returns the location information for the current token // (the token last returned by Next()). - Location location() const { return current_.location; } + Location location() const { return current().location; } // This error is specifically an invalid hex or unicode escape sequence. bool has_error() const { return scanner_error_ != MessageTemplate::kNone; } @@ -231,26 +248,26 @@ class Scanner { Location error_location() const { return scanner_error_location_; } bool has_invalid_template_escape() const { - return current_.invalid_template_escape_message != MessageTemplate::kNone; + return current().invalid_template_escape_message != MessageTemplate::kNone; } MessageTemplate::Template invalid_template_escape_message() const { DCHECK(has_invalid_template_escape()); - return current_.invalid_template_escape_message; + return current().invalid_template_escape_message; } Location invalid_template_escape_location() const { DCHECK(has_invalid_template_escape()); - return current_.invalid_template_escape_location; + return current().invalid_template_escape_location; } // Similar functions for the upcoming token. // One token look-ahead (past the token returned by Next()). - Token::Value peek() const { return next_.token; } + Token::Value peek() const { return next().token; } - Location peek_location() const { return next_.location; } + Location peek_location() const { return next().location; } bool literal_contains_escapes() const { - return LiteralContainsEscapes(current_); + return LiteralContainsEscapes(current()); } const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory) const; @@ -264,12 +281,12 @@ class Scanner { inline bool CurrentMatches(Token::Value token) const { DCHECK(Token::IsKeyword(token)); - return current_.token == token; + return current().token == token; } inline bool CurrentMatchesContextual(Token::Value token) const { DCHECK(Token::IsContextualKeyword(token)); - return current_.contextual_token == token; + return current().contextual_token == token; } // Match the token against the contextual keyword or literal buffer. @@ -278,17 +295,17 @@ class Scanner { // Escaped keywords are not matched as tokens. So if we require escape // and/or string processing we need to look at the literal content // (which was escape-processed already). - // Conveniently, current_.literal_chars == nullptr for all proper keywords, - // so this second condition should exit early in common cases. - return (current_.contextual_token == token) || - (current_.literal_chars && - current_.literal_chars->Equals(Vector<const char>( + // Conveniently, !current().literal_chars.is_used() for all proper + // keywords, so this second condition should exit early in common cases. + return (current().contextual_token == token) || + (current().literal_chars.is_used() && + current().literal_chars.Equals(Vector<const char>( Token::String(token), Token::StringLength(token)))); } bool IsUseStrict() const { - return current_.token == Token::STRING && - current_.literal_chars->Equals( + return current().token == Token::STRING && + current().literal_chars.Equals( Vector<const char>("use strict", strlen("use strict"))); } bool IsGetOrSet(bool* is_get, bool* is_set) const { @@ -318,7 +335,7 @@ class Scanner { MessageTemplate::Template octal_message() const { return octal_message_; } // Returns the value of the last smi that was scanned. - uint32_t smi_value() const { return current_.smi_value_; } + uint32_t smi_value() const { return current().smi_value_; } // Seek forward to the given position. This operation does not // work in general, for instance when there are pushed back @@ -328,15 +345,14 @@ class Scanner { // Returns true if there was a line terminator before the peek'ed token, // possibly inside a multi-line comment. - bool HasAnyLineTerminatorBeforeNext() const { - return has_line_terminator_before_next_ || - has_multiline_comment_before_next_; + bool HasLineTerminatorBeforeNext() const { + return next().after_line_terminator; } - bool HasAnyLineTerminatorAfterNext() { + bool HasLineTerminatorAfterNext() { Token::Value ensure_next_next = PeekAhead(); USE(ensure_next_next); - return has_line_terminator_after_next_; + return next_next().after_line_terminator; } // Scans the input as a regular expression pattern, next token must be /(=). @@ -348,8 +364,8 @@ class Scanner { // Scans the input as a template literal Token::Value ScanTemplateStart(); Token::Value ScanTemplateContinuation() { - DCHECK_EQ(next_.token, Token::RBRACE); - next_.location.beg_pos = source_pos() - 1; // We already consumed } + DCHECK_EQ(next().token, Token::RBRACE); + next().location.beg_pos = source_pos() - 1; // We already consumed } return ScanTemplateSpan(); } @@ -399,33 +415,40 @@ class Scanner { // LiteralBuffer - Collector of chars of literals. class LiteralBuffer { public: - LiteralBuffer() : is_one_byte_(true), position_(0), backing_store_() {} + LiteralBuffer() + : position_(0), is_one_byte_(true), is_used_(false), backing_store_() {} ~LiteralBuffer() { backing_store_.Dispose(); } V8_INLINE void AddChar(char code_unit) { + DCHECK(is_used_); DCHECK(IsValidAscii(code_unit)); AddOneByteChar(static_cast<byte>(code_unit)); } V8_INLINE void AddChar(uc32 code_unit) { - if (is_one_byte_ && - code_unit <= static_cast<uc32>(unibrow::Latin1::kMaxChar)) { - AddOneByteChar(static_cast<byte>(code_unit)); - } else { - AddCharSlow(code_unit); + DCHECK(is_used_); + if (is_one_byte_) { + if (code_unit <= static_cast<uc32>(unibrow::Latin1::kMaxChar)) { + AddOneByteChar(static_cast<byte>(code_unit)); + return; + } + ConvertToTwoByte(); } + AddTwoByteChar(code_unit); } bool is_one_byte() const { return is_one_byte_; } bool Equals(Vector<const char> keyword) const { + DCHECK(is_used_); return is_one_byte() && keyword.length() == position_ && (memcmp(keyword.start(), backing_store_.start(), position_) == 0); } Vector<const uint16_t> two_byte_literal() const { DCHECK(!is_one_byte_); + DCHECK(is_used_); DCHECK_EQ(position_ & 0x1, 0); return Vector<const uint16_t>( reinterpret_cast<const uint16_t*>(backing_store_.start()), @@ -434,17 +457,23 @@ class Scanner { Vector<const uint8_t> one_byte_literal() const { DCHECK(is_one_byte_); + DCHECK(is_used_); return Vector<const uint8_t>( reinterpret_cast<const uint8_t*>(backing_store_.start()), position_); } int length() const { return is_one_byte_ ? position_ : (position_ >> 1); } - void ReduceLength(int delta) { - position_ -= delta * (is_one_byte_ ? kOneByteSize : kUC16Size); + void Start() { + DCHECK(!is_used_); + DCHECK_EQ(0, position_); + is_used_ = true; } - void Reset() { + bool is_used() const { return is_used_; } + + void Drop() { + is_used_ = false; position_ = 0; is_one_byte_ = true; } @@ -472,13 +501,14 @@ class Scanner { position_ += kOneByteSize; } - void AddCharSlow(uc32 code_unit); + void AddTwoByteChar(uc32 code_unit); int NewCapacity(int min_capacity); void ExpandBuffer(); void ConvertToTwoByte(); - bool is_one_byte_; int position_; + bool is_one_byte_; + bool is_used_; Vector<byte> backing_store_; DISALLOW_COPY_AND_ASSIGN(LiteralBuffer); @@ -486,14 +516,16 @@ class Scanner { // The current and look-ahead token. struct TokenDesc { - Location location; - LiteralBuffer* literal_chars; - LiteralBuffer* raw_literal_chars; - uint32_t smi_value_; - Token::Value token; - MessageTemplate::Template invalid_template_escape_message; + Location location = {0, 0}; + LiteralBuffer literal_chars; + LiteralBuffer raw_literal_chars; + Token::Value token = Token::UNINITIALIZED; + MessageTemplate::Template invalid_template_escape_message = + MessageTemplate::kNone; Location invalid_template_escape_location; - Token::Value contextual_token; + Token::Value contextual_token = Token::UNINITIALIZED; + uint32_t smi_value_ = 0; + bool after_line_terminator = false; }; enum NumberKind { @@ -510,29 +542,18 @@ class Scanner { // Scans octal escape sequence. Also accepts "\0" decimal escape sequence. template <bool capture_raw> - uc32 ScanOctalEscape(uc32 c, int length, bool in_template_literal); + uc32 ScanOctalEscape(uc32 c, int length); // Call this after setting source_ to the input. void Init() { // Set c0_ (one character ahead) STATIC_ASSERT(kCharacterLookaheadBufferSize == 1); Advance(); - // Initialize current_ to not refer to a literal. - current_.token = Token::UNINITIALIZED; - current_.contextual_token = Token::UNINITIALIZED; - 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 = 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 = nullptr; - next_next_.raw_literal_chars = nullptr; - next_next_.invalid_template_escape_message = MessageTemplate::kNone; + + current_ = &token_storage_[0]; + next_ = &token_storage_[1]; + next_next_ = &token_storage_[2]; + found_html_comment_ = false; scanner_error_ = MessageTemplate::kNone; } @@ -554,52 +575,23 @@ class Scanner { void SeekNext(size_t position); // Literal buffer support - inline void StartLiteral() { - LiteralBuffer* free_buffer = - (current_.literal_chars == &literal_buffer0_) - ? &literal_buffer1_ - : (current_.literal_chars == &literal_buffer1_) ? &literal_buffer2_ - : &literal_buffer0_; - free_buffer->Reset(); - next_.literal_chars = free_buffer; - } + inline void StartLiteral() { next().literal_chars.Start(); } - inline void StartRawLiteral() { - LiteralBuffer* free_buffer = - (current_.raw_literal_chars == &raw_literal_buffer0_) - ? &raw_literal_buffer1_ - : (current_.raw_literal_chars == &raw_literal_buffer1_) - ? &raw_literal_buffer2_ - : &raw_literal_buffer0_; - free_buffer->Reset(); - next_.raw_literal_chars = free_buffer; - } + inline void StartRawLiteral() { next().raw_literal_chars.Start(); } - V8_INLINE void AddLiteralChar(uc32 c) { - DCHECK_NOT_NULL(next_.literal_chars); - next_.literal_chars->AddChar(c); - } + V8_INLINE void AddLiteralChar(uc32 c) { next().literal_chars.AddChar(c); } - V8_INLINE void AddLiteralChar(char c) { - DCHECK_NOT_NULL(next_.literal_chars); - next_.literal_chars->AddChar(c); - } + V8_INLINE void AddLiteralChar(char c) { next().literal_chars.AddChar(c); } V8_INLINE void AddRawLiteralChar(uc32 c) { - DCHECK_NOT_NULL(next_.raw_literal_chars); - next_.raw_literal_chars->AddChar(c); - } - - V8_INLINE void ReduceRawLiteralLength(int delta) { - DCHECK_NOT_NULL(next_.raw_literal_chars); - next_.raw_literal_chars->ReduceLength(delta); + next().raw_literal_chars.AddChar(c); } // Stops scanning of a literal and drop the collected characters, // e.g., due to an encountered error. inline void DropLiteral() { - next_.literal_chars = nullptr; - next_.raw_literal_chars = nullptr; + next().literal_chars.Drop(); + next().raw_literal_chars.Drop(); } inline void AddLiteralCharAdvance() { @@ -616,6 +608,11 @@ class Scanner { c0_ = source_->Advance(); } + template <typename FunctionType> + V8_INLINE void AdvanceUntil(FunctionType check) { + c0_ = source_->AdvanceUntil(check); + } + bool CombineSurrogatePair() { DCHECK(!unibrow::Utf16::IsLeadSurrogate(kEndOfInput)); if (unibrow::Utf16::IsLeadSurrogate(c0_)) { @@ -631,22 +628,12 @@ class Scanner { } void PushBack(uc32 ch) { - if (c0_ > static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) { - source_->Back2(); - } else { - source_->Back(); - } + DCHECK_LE(c0_, static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)); + source_->Back(); c0_ = ch; } - // Same as PushBack(ch1); PushBack(ch2). - // - Potentially more efficient as it uses Back2() on the stream. - // - Uses char as parameters, since we're only calling it with ASCII chars in - // practice. This way, we can avoid a few edge cases. - void PushBack2(char ch1, char ch2) { - source_->Back2(); - c0_ = ch2; - } + uc32 Peek() const { return source_->Peek(); } inline Token::Value Select(Token::Value tok) { Advance(); @@ -676,45 +663,46 @@ class Scanner { // token as a one-byte literal. E.g. Token::FUNCTION pretends to have a // literal "function". Vector<const uint8_t> literal_one_byte_string() const { - if (current_.literal_chars) - return current_.literal_chars->one_byte_literal(); - const char* str = Token::String(current_.token); + if (current().literal_chars.is_used()) + return current().literal_chars.one_byte_literal(); + const char* str = Token::String(current().token); const uint8_t* str_as_uint8 = reinterpret_cast<const uint8_t*>(str); return Vector<const uint8_t>(str_as_uint8, - Token::StringLength(current_.token)); + Token::StringLength(current().token)); } Vector<const uint16_t> literal_two_byte_string() const { - DCHECK_NOT_NULL(current_.literal_chars); - return current_.literal_chars->two_byte_literal(); + DCHECK(current().literal_chars.is_used()); + return current().literal_chars.two_byte_literal(); } bool is_literal_one_byte() const { - return !current_.literal_chars || current_.literal_chars->is_one_byte(); + return !current().literal_chars.is_used() || + current().literal_chars.is_one_byte(); } // 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 { - DCHECK_NOT_NULL(next_.literal_chars); - return next_.literal_chars->one_byte_literal(); + DCHECK(next().literal_chars.is_used()); + return next().literal_chars.one_byte_literal(); } Vector<const uint16_t> next_literal_two_byte_string() const { - DCHECK_NOT_NULL(next_.literal_chars); - return next_.literal_chars->two_byte_literal(); + DCHECK(next().literal_chars.is_used()); + return next().literal_chars.two_byte_literal(); } bool is_next_literal_one_byte() const { - DCHECK_NOT_NULL(next_.literal_chars); - return next_.literal_chars->is_one_byte(); + DCHECK(next().literal_chars.is_used()); + return next().literal_chars.is_one_byte(); } Vector<const uint8_t> raw_literal_one_byte_string() const { - DCHECK_NOT_NULL(current_.raw_literal_chars); - return current_.raw_literal_chars->one_byte_literal(); + DCHECK(current().raw_literal_chars.is_used()); + return current().raw_literal_chars.one_byte_literal(); } Vector<const uint16_t> raw_literal_two_byte_string() const { - DCHECK_NOT_NULL(current_.raw_literal_chars); - return current_.raw_literal_chars->two_byte_literal(); + DCHECK(current().raw_literal_chars.is_used()); + return current().raw_literal_chars.two_byte_literal(); } bool is_raw_literal_one_byte() const { - DCHECK_NOT_NULL(current_.raw_literal_chars); - return current_.raw_literal_chars->is_one_byte(); + DCHECK(current().raw_literal_chars.is_used()); + return current().raw_literal_chars.is_one_byte(); } template <bool capture_raw, bool unicode = false> @@ -728,7 +716,7 @@ class Scanner { // Scans a single JavaScript token. void Scan(); - Token::Value SkipWhiteSpace(); + V8_INLINE Token::Value SkipWhiteSpace(); Token::Value SkipSingleHTMLComment(); Token::Value SkipSingleLineComment(); Token::Value SkipSourceURLComment(); @@ -759,7 +747,7 @@ class Scanner { // Scans an escape-sequence which is part of a string and adds the // decoded character to the current literal. Returns true if a pattern // is scanned. - template <bool capture_raw, bool in_template_literal> + template <bool capture_raw> bool ScanEscape(); // Decodes a Unicode escape-sequence which is part of an identifier. @@ -769,8 +757,6 @@ class Scanner { template <bool capture_raw> uc32 ScanUnicodeEscape(); - bool is_module_; - Token::Value ScanTemplateSpan(); // Return the current source position. @@ -785,8 +771,8 @@ class Scanner { // Subtract delimiters. source_length -= 2; } - return token.literal_chars && - (token.literal_chars->length() != source_length); + return token.literal_chars.is_used() && + (token.literal_chars.length() != source_length); } #ifdef DEBUG @@ -795,26 +781,24 @@ class Scanner { UnicodeCache* unicode_cache_; - // Buffers collecting literal strings, numbers, etc. - LiteralBuffer literal_buffer0_; - LiteralBuffer literal_buffer1_; - LiteralBuffer literal_buffer2_; - // Values parsed from magic comments. LiteralBuffer source_url_; LiteralBuffer source_mapping_url_; - // Buffer to store raw string values - LiteralBuffer raw_literal_buffer0_; - LiteralBuffer raw_literal_buffer1_; - LiteralBuffer raw_literal_buffer2_; + TokenDesc token_storage_[3]; + + TokenDesc& next() { return *next_; } + + const TokenDesc& current() const { return *current_; } + const TokenDesc& next() const { return *next_; } + const TokenDesc& next_next() const { return *next_next_; } - TokenDesc current_; // desc for current token (as returned by Next()) - TokenDesc next_; // desc for next token (one token look-ahead) - TokenDesc next_next_; // desc for the token after next (after PeakAhead()) + TokenDesc* current_; // desc for current token (as returned by Next()) + TokenDesc* next_; // desc for next token (one token look-ahead) + TokenDesc* next_next_; // desc for the token after next (after PeakAhead()) // Input stream. Must be initialized to an Utf16CharacterStream. - Utf16CharacterStream* source_; + Utf16CharacterStream* const source_; // Last-seen positions of potentially problematic tokens. Location octal_pos_; @@ -823,15 +807,6 @@ class Scanner { // One Unicode character look-ahead; c0_ < 0 at the end of the input. uc32 c0_; - // Whether there is a line terminator whitespace character after - // the current token, and before the next. Does not count newlines - // inside multiline comments. - bool has_line_terminator_before_next_; - // Whether there is a multi-line comment that contains a - // line-terminator after the current token, and before the next. - bool has_multiline_comment_before_next_; - bool has_line_terminator_after_next_; - // Whether this scanner encountered an HTML comment. bool found_html_comment_; @@ -840,6 +815,8 @@ class Scanner { bool allow_harmony_private_fields_; bool allow_harmony_numeric_separator_; + const bool is_module_; + MessageTemplate::Template scanner_error_; Location scanner_error_location_; }; |