From 3ab070d4e13cce67987d45d84592a6ff8e32f01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Tue, 21 Feb 2017 22:40:12 +0100 Subject: [PATCH] deps: backport dfb8d33 from V8 upstream Original commit message: Reduce the memory footprint of expression classifiers This patch attempts to reduce the (stack) memory footprint of expression classifiers. Instead of keeping space in each classifier for all possible error messages that will (potentially) be reported, if an expression turns out to be a pattern or a non-pattern, such error messages are placed in a list shared by the FunctionState and each classifier keeps a couple of indices in this list. This requires that classifiers are used strictly in a stack-based fashion, which is also in line with my previous patch for revisiting non-pattern rewriting. R=adamk@chromium.org BUG=chromium:528697 Review-Url: https://codereview.chromium.org/1708193003 Cr-Commit-Position: refs/heads/master@{#36897} Fixes: https://github.com/nodejs/node/issues/11480 PR-URL: https://github.com/nodejs/node/pull/11483 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Myles Borins --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/messages.h | 2 + deps/v8/src/parsing/expression-classifier.h | 353 +++++++++++++------- deps/v8/src/parsing/parser-base.h | 47 ++- deps/v8/src/parsing/parser.cc | 19 +- deps/v8/src/parsing/parser.h | 4 +- deps/v8/src/parsing/preparser.h | 18 +- 7 files changed, 288 insertions(+), 157 deletions(-) diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 4adb8f0234a7f0..4dcb3e573482a3 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 5 #define V8_MINOR_VERSION 1 #define V8_BUILD_NUMBER 281 -#define V8_PATCH_LEVEL 94 +#define V8_PATCH_LEVEL 95 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/messages.h b/deps/v8/src/messages.h index 4aa0b73e7179c1..5ea0bc2686e84e 100644 --- a/deps/v8/src/messages.h +++ b/deps/v8/src/messages.h @@ -449,6 +449,8 @@ class CallSite { "Too many arguments in function call (only 65535 allowed)") \ T(TooManyParameters, \ "Too many parameters in function definition (only 65535 allowed)") \ + T(TooManySpreads, \ + "Literal containing too many nested spreads (up to 65534 allowed)") \ T(TooManyVariables, "Too many variables declared (only 4194303 allowed)") \ T(TypedArrayTooShort, \ "Derived TypedArray constructor created an array which was too small") \ diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h index 71fa3d3e89b160..e3b0b8c487be5a 100644 --- a/deps/v8/src/parsing/expression-classifier.h +++ b/deps/v8/src/parsing/expression-classifier.h @@ -13,32 +13,52 @@ namespace v8 { namespace internal { +#define ERROR_CODES(T) \ + T(ExpressionProduction, 0) \ + T(FormalParameterInitializerProduction, 1) \ + T(BindingPatternProduction, 2) \ + T(AssignmentPatternProduction, 3) \ + T(DistinctFormalParametersProduction, 4) \ + T(StrictModeFormalParametersProduction, 5) \ + T(ArrowFormalParametersProduction, 6) \ + T(LetPatternProduction, 7) \ + T(CoverInitializedNameProduction, 8) + + template class ExpressionClassifier { public: + enum ErrorKind : unsigned { +#define DEFINE_ERROR_KIND(NAME, CODE) k##NAME = CODE, + ERROR_CODES(DEFINE_ERROR_KIND) +#undef DEFINE_ERROR_KIND + kUnusedError = 15 // Larger than error codes; should fit in 4 bits + }; + struct Error { - Error() + V8_INLINE Error() : 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) {} Scanner::Location location; - MessageTemplate::Template message : 30; + MessageTemplate::Template message : 26; + unsigned kind : 4; ParseErrorType type : 2; const char* arg; }; - enum TargetProduction { - ExpressionProduction = 1 << 0, - FormalParameterInitializerProduction = 1 << 1, - BindingPatternProduction = 1 << 2, - AssignmentPatternProduction = 1 << 3, - DistinctFormalParametersProduction = 1 << 4, - StrictModeFormalParametersProduction = 1 << 5, - ArrowFormalParametersProduction = 1 << 6, - LetPatternProduction = 1 << 7, - CoverInitializedNameProduction = 1 << 8, + enum TargetProduction : unsigned { +#define DEFINE_PRODUCTION(NAME, CODE) NAME = 1 << CODE, + ERROR_CODES(DEFINE_PRODUCTION) +#undef DEFINE_PRODUCTION ExpressionProductions = (ExpressionProduction | FormalParameterInitializerProduction), @@ -52,102 +72,121 @@ class ExpressionClassifier { ArrowFormalParametersProduction | CoverInitializedNameProduction) }; - enum FunctionProperties { NonSimpleParameter = 1 << 0 }; + enum FunctionProperties : unsigned { + NonSimpleParameter = 1 << 0 + }; explicit ExpressionClassifier(const Traits* t) : zone_(t->zone()), non_patterns_to_rewrite_(t->GetNonPatternList()), + reported_errors_(t->GetReportedErrorList()), + duplicate_finder_(nullptr), invalid_productions_(0), - function_properties_(0), - duplicate_finder_(nullptr) { + function_properties_(0) { + reported_errors_begin_ = reported_errors_end_ = reported_errors_->length(); non_pattern_begin_ = non_patterns_to_rewrite_->length(); } ExpressionClassifier(const Traits* t, DuplicateFinder* duplicate_finder) : zone_(t->zone()), non_patterns_to_rewrite_(t->GetNonPatternList()), + reported_errors_(t->GetReportedErrorList()), + duplicate_finder_(duplicate_finder), invalid_productions_(0), - function_properties_(0), - duplicate_finder_(duplicate_finder) { + function_properties_(0) { + reported_errors_begin_ = reported_errors_end_ = reported_errors_->length(); non_pattern_begin_ = non_patterns_to_rewrite_->length(); } ~ExpressionClassifier() { Discard(); } - bool is_valid(unsigned productions) const { + V8_INLINE bool is_valid(unsigned productions) const { return (invalid_productions_ & productions) == 0; } - DuplicateFinder* duplicate_finder() const { return duplicate_finder_; } + V8_INLINE DuplicateFinder* duplicate_finder() const { + return duplicate_finder_; + } - bool is_valid_expression() const { return is_valid(ExpressionProduction); } + V8_INLINE bool is_valid_expression() const { + return is_valid(ExpressionProduction); + } - bool is_valid_formal_parameter_initializer() const { + V8_INLINE bool is_valid_formal_parameter_initializer() const { return is_valid(FormalParameterInitializerProduction); } - bool is_valid_binding_pattern() const { + V8_INLINE bool is_valid_binding_pattern() const { return is_valid(BindingPatternProduction); } - bool is_valid_assignment_pattern() const { + V8_INLINE bool is_valid_assignment_pattern() const { return is_valid(AssignmentPatternProduction); } - bool is_valid_arrow_formal_parameters() const { + V8_INLINE bool is_valid_arrow_formal_parameters() const { return is_valid(ArrowFormalParametersProduction); } - bool is_valid_formal_parameter_list_without_duplicates() const { + V8_INLINE bool is_valid_formal_parameter_list_without_duplicates() const { return is_valid(DistinctFormalParametersProduction); } // Note: callers should also check // is_valid_formal_parameter_list_without_duplicates(). - bool is_valid_strict_mode_formal_parameters() const { + V8_INLINE bool is_valid_strict_mode_formal_parameters() const { return is_valid(StrictModeFormalParametersProduction); } - bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); } + V8_INLINE bool is_valid_let_pattern() const { + return is_valid(LetPatternProduction); + } - const Error& expression_error() const { return expression_error_; } + V8_INLINE const Error& expression_error() const { + return reported_error(kExpressionProduction); + } - const Error& formal_parameter_initializer_error() const { - return formal_parameter_initializer_error_; + V8_INLINE const Error& formal_parameter_initializer_error() const { + return reported_error(kFormalParameterInitializerProduction); } - const Error& binding_pattern_error() const { return binding_pattern_error_; } + V8_INLINE const Error& binding_pattern_error() const { + return reported_error(kBindingPatternProduction); + } - const Error& assignment_pattern_error() const { - return assignment_pattern_error_; + V8_INLINE const Error& assignment_pattern_error() const { + return reported_error(kAssignmentPatternProduction); } - const Error& arrow_formal_parameters_error() const { - return arrow_formal_parameters_error_; + V8_INLINE const Error& arrow_formal_parameters_error() const { + return reported_error(kArrowFormalParametersProduction); } - const Error& duplicate_formal_parameter_error() const { - return duplicate_formal_parameter_error_; + V8_INLINE const Error& duplicate_formal_parameter_error() const { + return reported_error(kDistinctFormalParametersProduction); } - const Error& strict_mode_formal_parameter_error() const { - return strict_mode_formal_parameter_error_; + V8_INLINE const Error& strict_mode_formal_parameter_error() const { + return reported_error(kStrictModeFormalParametersProduction); } - const Error& let_pattern_error() const { return let_pattern_error_; } + V8_INLINE const Error& let_pattern_error() const { + return reported_error(kLetPatternProduction); + } - bool has_cover_initialized_name() const { + V8_INLINE bool has_cover_initialized_name() const { return !is_valid(CoverInitializedNameProduction); } - const Error& cover_initialized_name_error() const { - return cover_initialized_name_error_; + + V8_INLINE const Error& cover_initialized_name_error() const { + return reported_error(kCoverInitializedNameProduction); } - bool is_simple_parameter_list() const { + V8_INLINE bool is_simple_parameter_list() const { return !(function_properties_ & NonSimpleParameter); } - void RecordNonSimpleParameter() { + V8_INLINE void RecordNonSimpleParameter() { function_properties_ |= NonSimpleParameter; } @@ -156,9 +195,7 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_expression()) return; invalid_productions_ |= ExpressionProduction; - expression_error_.location = loc; - expression_error_.message = message; - expression_error_.arg = arg; + Add(Error(loc, message, kExpressionProduction, arg)); } void RecordExpressionError(const Scanner::Location& loc, @@ -166,10 +203,7 @@ class ExpressionClassifier { ParseErrorType type, const char* arg = nullptr) { if (!is_valid_expression()) return; invalid_productions_ |= ExpressionProduction; - expression_error_.location = loc; - expression_error_.message = message; - expression_error_.arg = arg; - expression_error_.type = type; + Add(Error(loc, message, kExpressionProduction, arg, type)); } void RecordFormalParameterInitializerError(const Scanner::Location& loc, @@ -177,9 +211,7 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_formal_parameter_initializer()) return; invalid_productions_ |= FormalParameterInitializerProduction; - formal_parameter_initializer_error_.location = loc; - formal_parameter_initializer_error_.message = message; - formal_parameter_initializer_error_.arg = arg; + Add(Error(loc, message, kFormalParameterInitializerProduction, arg)); } void RecordBindingPatternError(const Scanner::Location& loc, @@ -187,9 +219,7 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_binding_pattern()) return; invalid_productions_ |= BindingPatternProduction; - binding_pattern_error_.location = loc; - binding_pattern_error_.message = message; - binding_pattern_error_.arg = arg; + Add(Error(loc, message, kBindingPatternProduction, arg)); } void RecordAssignmentPatternError(const Scanner::Location& loc, @@ -197,9 +227,7 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_assignment_pattern()) return; invalid_productions_ |= AssignmentPatternProduction; - assignment_pattern_error_.location = loc; - assignment_pattern_error_.message = message; - assignment_pattern_error_.arg = arg; + Add(Error(loc, message, kAssignmentPatternProduction, arg)); } void RecordPatternError(const Scanner::Location& loc, @@ -214,17 +242,14 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_arrow_formal_parameters()) return; invalid_productions_ |= ArrowFormalParametersProduction; - arrow_formal_parameters_error_.location = loc; - arrow_formal_parameters_error_.message = message; - arrow_formal_parameters_error_.arg = arg; + Add(Error(loc, message, kArrowFormalParametersProduction, arg)); } void RecordDuplicateFormalParameterError(const Scanner::Location& loc) { if (!is_valid_formal_parameter_list_without_duplicates()) return; invalid_productions_ |= DistinctFormalParametersProduction; - duplicate_formal_parameter_error_.location = loc; - duplicate_formal_parameter_error_.message = MessageTemplate::kParamDupe; - duplicate_formal_parameter_error_.arg = nullptr; + Add(Error(loc, MessageTemplate::kParamDupe, + kDistinctFormalParametersProduction)); } // Record a binding that would be invalid in strict mode. Confusingly this @@ -235,9 +260,7 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_strict_mode_formal_parameters()) return; invalid_productions_ |= StrictModeFormalParametersProduction; - strict_mode_formal_parameter_error_.location = loc; - strict_mode_formal_parameter_error_.message = message; - strict_mode_formal_parameter_error_.arg = arg; + Add(Error(loc, message, kStrictModeFormalParametersProduction, arg)); } void RecordLetPatternError(const Scanner::Location& loc, @@ -245,9 +268,7 @@ class ExpressionClassifier { const char* arg = nullptr) { if (!is_valid_let_pattern()) return; invalid_productions_ |= LetPatternProduction; - let_pattern_error_.location = loc; - let_pattern_error_.message = message; - let_pattern_error_.arg = arg; + Add(Error(loc, message, kLetPatternProduction, arg)); } void RecordCoverInitializedNameError(const Scanner::Location& loc, @@ -255,76 +276,102 @@ class ExpressionClassifier { const char* arg = nullptr) { if (has_cover_initialized_name()) return; invalid_productions_ |= CoverInitializedNameProduction; - cover_initialized_name_error_.location = loc; - cover_initialized_name_error_.message = message; - cover_initialized_name_error_.arg = arg; + Add(Error(loc, message, kCoverInitializedNameProduction, arg)); } void ForgiveCoverInitializedNameError() { + if (!(invalid_productions_ & CoverInitializedNameProduction)) return; + Error& e = reported_error(kCoverInitializedNameProduction); + e.kind = kUnusedError; invalid_productions_ &= ~CoverInitializedNameProduction; - cover_initialized_name_error_ = Error(); } void ForgiveAssignmentPatternError() { + if (!(invalid_productions_ & AssignmentPatternProduction)) return; + Error& e = reported_error(kAssignmentPatternProduction); + e.kind = kUnusedError; invalid_productions_ &= ~AssignmentPatternProduction; - assignment_pattern_error_ = Error(); } void Accumulate(ExpressionClassifier* inner, unsigned productions = StandardProductions, bool merge_non_patterns = true) { + 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()); if (merge_non_patterns) MergeNonPatterns(inner); // Propagate errors from inner, but don't overwrite already recorded // errors. unsigned non_arrow_inner_invalid_productions = inner->invalid_productions_ & ~ArrowFormalParametersProduction; - if (non_arrow_inner_invalid_productions == 0) return; - unsigned non_arrow_productions = - productions & ~ArrowFormalParametersProduction; - unsigned errors = - non_arrow_productions & non_arrow_inner_invalid_productions; - errors &= ~invalid_productions_; - if (errors != 0) { - invalid_productions_ |= errors; - if (errors & ExpressionProduction) - expression_error_ = inner->expression_error_; - if (errors & FormalParameterInitializerProduction) - formal_parameter_initializer_error_ = - inner->formal_parameter_initializer_error_; - if (errors & BindingPatternProduction) - binding_pattern_error_ = inner->binding_pattern_error_; - if (errors & AssignmentPatternProduction) - assignment_pattern_error_ = inner->assignment_pattern_error_; - if (errors & DistinctFormalParametersProduction) - duplicate_formal_parameter_error_ = - inner->duplicate_formal_parameter_error_; - if (errors & StrictModeFormalParametersProduction) - strict_mode_formal_parameter_error_ = - inner->strict_mode_formal_parameter_error_; - if (errors & LetPatternProduction) - let_pattern_error_ = inner->let_pattern_error_; - if (errors & CoverInitializedNameProduction) - cover_initialized_name_error_ = inner->cover_initialized_name_error_; - } - - // As an exception to the above, the result continues to be a valid arrow - // formal parameters if the inner expression is a valid binding pattern. - if (productions & ArrowFormalParametersProduction && - is_valid_arrow_formal_parameters()) { - // Also copy function properties if expecting an arrow function - // parameter. - function_properties_ |= inner->function_properties_; - - if (!inner->is_valid_binding_pattern()) { - invalid_productions_ |= ArrowFormalParametersProduction; - arrow_formal_parameters_error_ = inner->binding_pattern_error_; + if (non_arrow_inner_invalid_productions) { + unsigned errors = non_arrow_inner_invalid_productions & productions & + ~invalid_productions_; + // The result will continue to be a valid arrow formal parameters if the + // inner expression is a valid binding pattern. + 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_; + if (!inner->is_valid_binding_pattern()) { + copy_BP_to_AFP = true; + invalid_productions_ |= ArrowFormalParametersProduction; + } + } + // Traverse the list of errors reported by the inner classifier + // to copy what's necessary. + if (errors != 0 || copy_BP_to_AFP) { + invalid_productions_ |= errors; + int binding_pattern_index = inner->reported_errors_end_; + for (int i = inner->reported_errors_begin_; + i < inner->reported_errors_end_; i++) { + int k = reported_errors_->at(i).kind; + if (errors & (1 << k)) Copy(i); + // Check if it's a BP error that has to be copied to an AFP error. + if (k == kBindingPatternProduction && copy_BP_to_AFP) { + if (reported_errors_end_ <= i) { + // If the BP error itself has not already been copied, + // copy it now and change it to an AFP error. + Copy(i); + reported_errors_->at(reported_errors_end_-1).kind = + kArrowFormalParametersProduction; + } else { + // Otherwise, if the BP error was already copied, keep its + // position and wait until the end of the traversal. + DCHECK_EQ(reported_errors_end_, i+1); + binding_pattern_index = i; + } + } + } + // Do we still have to copy the BP error to an AFP error? + if (binding_pattern_index < inner->reported_errors_end_) { + // If there's still unused space in the list of the inner + // classifier, copy it there, otherwise add it to the end + // of the list. + if (reported_errors_end_ < inner->reported_errors_end_) + Copy(binding_pattern_index); + else + Add(reported_errors_->at(binding_pattern_index)); + reported_errors_->at(reported_errors_end_-1).kind = + kArrowFormalParametersProduction; + } } } + reported_errors_->Rewind(reported_errors_end_); + inner->reported_errors_begin_ = inner->reported_errors_end_ = + reported_errors_end_; } V8_INLINE int GetNonPatternBegin() const { return non_pattern_begin_; } V8_INLINE void Discard() { + if (reported_errors_end_ == reported_errors_->length()) { + reported_errors_->Rewind(reported_errors_begin_); + reported_errors_end_ = reported_errors_begin_; + } + DCHECK_EQ(reported_errors_begin_, reported_errors_end_); DCHECK_LE(non_pattern_begin_, non_patterns_to_rewrite_->length()); non_patterns_to_rewrite_->Rewind(non_pattern_begin_); } @@ -335,24 +382,70 @@ class ExpressionClassifier { } private: + V8_INLINE Error& reported_error(ErrorKind kind) const { + if (invalid_productions_ & (1 << kind)) { + for (int i = reported_errors_begin_; i < reported_errors_end_; i++) { + if (reported_errors_->at(i).kind == kind) + return reported_errors_->at(i); + } + UNREACHABLE(); + } + // We should only be looking for an error when we know that one has + // been reported. But we're not... So this is to make sure we have + // the same behaviour. + static Error none; + return none; + } + + // 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_); + reported_errors_end_++; + } + + // Copies the error at position i of the list of reported errors, so that + // it becomes the last error reported for this classifier. Position i + // could be either after the existing errors of this classifier (i.e., + // in an inner classifier) or it could be an existing error (in case a + // copy is needed). + V8_INLINE void Copy(int i) { + DCHECK_LE(reported_errors_end_, i); + DCHECK_LT(i, reported_errors_->length()); + if (reported_errors_end_ != i) + reported_errors_->at(reported_errors_end_) = reported_errors_->at(i); + reported_errors_end_++; + } + Zone* zone_; ZoneList* non_patterns_to_rewrite_; - int non_pattern_begin_; - unsigned invalid_productions_; - unsigned function_properties_; - Error expression_error_; - Error formal_parameter_initializer_error_; - Error binding_pattern_error_; - Error assignment_pattern_error_; - Error arrow_formal_parameters_error_; - Error duplicate_formal_parameter_error_; - Error strict_mode_formal_parameter_error_; - Error let_pattern_error_; - Error cover_initialized_name_error_; + ZoneList* reported_errors_; DuplicateFinder* duplicate_finder_; + // The uint16_t for non_pattern_begin_ will not be enough in the case, + // e.g., of an array literal containing more than 64K inner array + // literals with spreads, as in: + // var N=65536; eval("var x=[];" + "[" + "[...x],".repeat(N) + "].length"); + // An implementation limit error in ParserBase::AddNonPatternForRewriting + // will be triggered in this case. + uint16_t non_pattern_begin_; + unsigned invalid_productions_ : 14; + unsigned function_properties_ : 2; + // 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: + // literals with spreads, as in: + // var N=65536; eval("var x;" + "x=".repeat(N) + "42"); + // This should not be a problem, as such things currently fail with a + // stack overflow while parsing. + uint16_t reported_errors_begin_; + uint16_t reported_errors_end_; }; +#undef ERROR_CODES + + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index dde6b1dd863627..0eb19ceb83b13a 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -247,8 +247,8 @@ class ParserBase : public Traits { typename Traits::Type::Factory* factory() { return factory_; } - const List& destructuring_assignments_to_rewrite() - const { + const ZoneList& + destructuring_assignments_to_rewrite() const { return destructuring_assignments_to_rewrite_; } @@ -268,19 +268,26 @@ class ParserBase : public Traits { collect_expressions_in_tail_position_ = collect; } + ZoneList* GetReportedErrorList() { + return &reported_errors_; + } + ZoneList* non_patterns_to_rewrite() { return &non_patterns_to_rewrite_; } private: void AddDestructuringAssignment(DestructuringAssignment pair) { - destructuring_assignments_to_rewrite_.Add(pair); + destructuring_assignments_to_rewrite_.Add(pair, (*scope_stack_)->zone()); } V8_INLINE Scope* scope() { return *scope_stack_; } - void AddNonPatternForRewriting(ExpressionT expr) { + void AddNonPatternForRewriting(ExpressionT expr, bool* ok) { non_patterns_to_rewrite_.Add(expr, (*scope_stack_)->zone()); + if (non_patterns_to_rewrite_.length() >= + std::numeric_limits::max()) + *ok = false; } // Used to assign an index to each literal that needs materialization in @@ -311,11 +318,13 @@ class ParserBase : public Traits { Scope** scope_stack_; Scope* outer_scope_; - List destructuring_assignments_to_rewrite_; + ZoneList destructuring_assignments_to_rewrite_; List expressions_in_tail_position_; bool collect_expressions_in_tail_position_; ZoneList non_patterns_to_rewrite_; + ZoneList reported_errors_; + typename Traits::Type::Factory* factory_; friend class ParserTraits; @@ -945,8 +954,10 @@ ParserBase::FunctionState::FunctionState( outer_function_state_(*function_state_stack), scope_stack_(scope_stack), outer_scope_(*scope_stack), + destructuring_assignments_to_rewrite_(16, scope->zone()), collect_expressions_in_tail_position_(true), non_patterns_to_rewrite_(0, scope->zone()), + reported_errors_(16, scope->zone()), factory_(factory) { *scope_stack_ = scope; *function_state_stack = this; @@ -1274,12 +1285,11 @@ ParserBase::ParsePrimaryExpression(ExpressionClassifier* classifier, // Parentheses are not valid on the LHS of a BindingPattern, so we use the // is_valid_binding_pattern() check to detect multiple levels of // parenthesization. - if (!classifier->is_valid_binding_pattern()) { - ArrowFormalParametersUnexpectedToken(classifier); - } + bool pattern_error = !classifier->is_valid_binding_pattern(); classifier->RecordPatternError(scanner()->peek_location(), MessageTemplate::kUnexpectedToken, Token::String(Token::LPAREN)); + if (pattern_error) ArrowFormalParametersUnexpectedToken(classifier); Consume(Token::LPAREN); if (Check(Token::RPAREN)) { // ()=>x. The continuation that looks for the => is in @@ -1416,6 +1426,7 @@ typename ParserBase::ExpressionT ParserBase::ParseExpression( seen_rest = is_rest = true; } int pos = position(), expr_pos = peek_position(); + ExpressionClassifier binding_classifier(this); ExpressionT right = this->ParseAssignmentExpression( accept_IN, &binding_classifier, CHECK_OK); classifier->Accumulate(&binding_classifier, @@ -1501,7 +1512,15 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral( literal_index, pos); if (first_spread_index >= 0) { result = factory()->NewRewritableExpression(result); - Traits::QueueNonPatternForRewriting(result); + Traits::QueueNonPatternForRewriting(result, ok); + if (!*ok) { + // If the non-pattern rewriting mechanism is used in the future for + // rewriting other things than spreads, this error message will have + // to change. Also, this error message will never appear while pre- + // parsing (this is OK, as it is an implementation limitation). + ReportMessage(MessageTemplate::kTooManySpreads); + return this->EmptyExpression(); + } } return result; } @@ -1907,9 +1926,7 @@ ParserBase::ParseAssignmentExpression(bool accept_IN, ExpressionT expression = this->ParseConditionalExpression( accept_IN, &arrow_formals_classifier, CHECK_OK); if (peek() == Token::ARROW) { - classifier->RecordPatternError(scanner()->peek_location(), - MessageTemplate::kUnexpectedToken, - Token::String(Token::ARROW)); + Scanner::Location arrow_loc = scanner()->peek_location(); ValidateArrowFormalParameters(&arrow_formals_classifier, expression, parenthesized_formals, CHECK_OK); // This reads strangely, but is correct: it checks whether any @@ -1944,6 +1961,10 @@ ParserBase::ParseAssignmentExpression(bool accept_IN, } expression = this->ParseArrowFunctionLiteral( accept_IN, parameters, arrow_formals_classifier, CHECK_OK); + arrow_formals_classifier.Discard(); + classifier->RecordPatternError(arrow_loc, + MessageTemplate::kUnexpectedToken, + Token::String(Token::ARROW)); if (fni_ != nullptr) fni_->Infer(); @@ -2113,8 +2134,8 @@ ParserBase::ParseConditionalExpression(bool accept_IN, this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK); if (peek() != Token::CONDITIONAL) return expression; Traits::RewriteNonPattern(classifier, CHECK_OK); - ArrowFormalParametersUnexpectedToken(classifier); BindingPatternUnexpectedToken(classifier); + ArrowFormalParametersUnexpectedToken(classifier); Consume(Token::CONDITIONAL); // In parsing the first assignment expression in conditional // expressions we always accept the 'in' keyword; see ECMA-262, diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 48837f0ad62e27..bbb75de3ea3dab 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -2439,7 +2439,6 @@ Statement* Parser::ParseExpressionOrLabelledStatement( ReportUnexpectedToken(Next()); *ok = false; return nullptr; - default: break; } @@ -5405,13 +5404,19 @@ void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, } -Zone* ParserTraits::zone() const { - return parser_->function_state_->scope()->zone(); +ZoneList* ParserTraits::GetNonPatternList() const { + return parser_->function_state_->non_patterns_to_rewrite(); } -ZoneList* ParserTraits::GetNonPatternList() const { - return parser_->function_state_->non_patterns_to_rewrite(); +ZoneList* +ParserTraits::GetReportedErrorList() const { + return parser_->function_state_->GetReportedErrorList(); +} + + +Zone* ParserTraits::zone() const { + return parser_->function_state_->scope()->zone(); } @@ -5628,9 +5633,9 @@ void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) { } -void ParserTraits::QueueNonPatternForRewriting(Expression* expr) { +void ParserTraits::QueueNonPatternForRewriting(Expression* expr, bool* ok) { DCHECK(expr->IsRewritableExpression()); - parser_->function_state_->AddNonPatternForRewriting(expr); + parser_->function_state_->AddNonPatternForRewriting(expr, ok); } diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h index 5df11e77a01337..a62ffbe72b3032 100644 --- a/deps/v8/src/parsing/parser.h +++ b/deps/v8/src/parsing/parser.h @@ -646,7 +646,7 @@ class ParserTraits { V8_INLINE void QueueDestructuringAssignmentForRewriting( Expression* assignment); - V8_INLINE void QueueNonPatternForRewriting(Expression* expr); + V8_INLINE void QueueNonPatternForRewriting(Expression* expr, bool* ok); void SetFunctionNameFromPropertyName(ObjectLiteralProperty* property, const AstRawString* name); @@ -658,6 +658,8 @@ class ParserTraits { V8_INLINE void RewriteNonPattern(Type::ExpressionClassifier* classifier, bool* ok); + V8_INLINE ZoneList* + GetReportedErrorList() const; V8_INLINE Zone* zone() const; V8_INLINE ZoneList* GetNonPatternList() const; diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h index f2f69517b25b42..1c6c7e6d6fed45 100644 --- a/deps/v8/src/parsing/preparser.h +++ b/deps/v8/src/parsing/preparser.h @@ -916,7 +916,7 @@ class PreParserTraits { } inline void QueueDestructuringAssignmentForRewriting(PreParserExpression) {} - inline void QueueNonPatternForRewriting(PreParserExpression) {} + inline void QueueNonPatternForRewriting(PreParserExpression, bool* ok) {} void SetFunctionNameFromPropertyName(PreParserExpression, PreParserIdentifier) {} @@ -926,6 +926,8 @@ class PreParserTraits { inline void RewriteNonPattern(Type::ExpressionClassifier* classifier, bool* ok); + V8_INLINE ZoneList* + GetReportedErrorList() const; V8_INLINE Zone* zone() const; V8_INLINE ZoneList* GetNonPatternList() const; @@ -1126,13 +1128,19 @@ void PreParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier, } -Zone* PreParserTraits::zone() const { - return pre_parser_->function_state_->scope()->zone(); +ZoneList* PreParserTraits::GetNonPatternList() const { + return pre_parser_->function_state_->non_patterns_to_rewrite(); } -ZoneList* PreParserTraits::GetNonPatternList() const { - return pre_parser_->function_state_->non_patterns_to_rewrite(); +ZoneList* +PreParserTraits::GetReportedErrorList() const { + return pre_parser_->function_state_->GetReportedErrorList(); +} + + +Zone* PreParserTraits::zone() const { + return pre_parser_->function_state_->scope()->zone(); }