summaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/parsing')
-rw-r--r--deps/v8/src/parsing/OWNERS1
-rw-r--r--deps/v8/src/parsing/duplicate-finder.h2
-rw-r--r--deps/v8/src/parsing/expression-classifier.h528
-rw-r--r--deps/v8/src/parsing/func-name-inferrer.h8
-rw-r--r--deps/v8/src/parsing/parse-info.cc96
-rw-r--r--deps/v8/src/parsing/parse-info.h30
-rw-r--r--deps/v8/src/parsing/parser-base.h1324
-rw-r--r--deps/v8/src/parsing/parser.cc343
-rw-r--r--deps/v8/src/parsing/parser.h109
-rw-r--r--deps/v8/src/parsing/pattern-rewriter.cc242
-rw-r--r--deps/v8/src/parsing/preparsed-scope-data-impl.h259
-rw-r--r--deps/v8/src/parsing/preparsed-scope-data.cc433
-rw-r--r--deps/v8/src/parsing/preparsed-scope-data.h163
-rw-r--r--deps/v8/src/parsing/preparser.cc92
-rw-r--r--deps/v8/src/parsing/preparser.h232
-rw-r--r--deps/v8/src/parsing/scanner-character-streams.cc276
-rw-r--r--deps/v8/src/parsing/scanner-character-streams.h3
-rw-r--r--deps/v8/src/parsing/scanner-inl.h530
-rw-r--r--deps/v8/src/parsing/scanner.cc620
-rw-r--r--deps/v8/src/parsing/scanner.h151
-rw-r--r--deps/v8/src/parsing/token.cc1
-rw-r--r--deps/v8/src/parsing/token.h205
22 files changed, 2983 insertions, 2665 deletions
diff --git a/deps/v8/src/parsing/OWNERS b/deps/v8/src/parsing/OWNERS
index 24218df199..177f214415 100644
--- a/deps/v8/src/parsing/OWNERS
+++ b/deps/v8/src/parsing/OWNERS
@@ -2,6 +2,7 @@ set noparent
adamk@chromium.org
gsathya@chromium.org
+leszeks@chromium.org
littledan@chromium.org
marja@chromium.org
neis@chromium.org
diff --git a/deps/v8/src/parsing/duplicate-finder.h b/deps/v8/src/parsing/duplicate-finder.h
index a4981c1872..65bcc4e00d 100644
--- a/deps/v8/src/parsing/duplicate-finder.h
+++ b/deps/v8/src/parsing/duplicate-finder.h
@@ -22,7 +22,7 @@ class Scanner;
// Scanner::IsDuplicateSymbol.
class DuplicateFinder {
public:
- DuplicateFinder() {}
+ DuplicateFinder() = default;
private:
friend class Scanner;
diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h
index 7833dbc8d3..2eed75b939 100644
--- a/deps/v8/src/parsing/expression-classifier.h
+++ b/deps/v8/src/parsing/expression-classifier.h
@@ -5,9 +5,10 @@
#ifndef V8_PARSING_EXPRESSION_CLASSIFIER_H_
#define V8_PARSING_EXPRESSION_CLASSIFIER_H_
+#include <type_traits>
+
#include "src/messages.h"
#include "src/parsing/scanner.h"
-#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
@@ -47,14 +48,38 @@ class DuplicateFinder;
// by calling the method Discard. Both actions result in removing the
// classifier from the parser's stack.
+// Expression classifier is split into four parts. The base implementing the
+// general expression classifier logic. Two parts that implement the error
+// tracking interface, where one is the actual implementation and the other is
+// an empty class providing only the interface without logic. The expression
+// classifier class then combines the other parts and provides the full
+// expression classifier interface by inheriting conditionally, controlled by
+// Types::ExpressionClassifierReportErrors, either from the ErrorTracker or the
+// EmptyErrorTracker.
+//
+// Base
+// / \
+// / \
+// / \
+// / \
+// ErrorTracker EmptyErrorTracker
+// \ /
+// \ /
+// \ /
+// \ /
+// ExpressionClassifier
+
template <typename Types>
-class ExpressionClassifier {
+class ExpressionClassifier;
+
+template <typename Types, typename ErrorTracker>
+class ExpressionClassifierBase {
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
+ kUnusedError = 15 // Larger than error codes; should fit in 4 bits
};
struct Error {
@@ -86,23 +111,14 @@ class ExpressionClassifier {
};
// clang-format on
- explicit ExpressionClassifier(typename Types::Base* base,
- DuplicateFinder* duplicate_finder = nullptr)
+ explicit ExpressionClassifierBase(typename Types::Base* base,
+ DuplicateFinder* duplicate_finder = nullptr)
: base_(base),
- previous_(base->classifier_),
- zone_(base->impl()->zone()),
- reported_errors_(base->impl()->GetReportedErrorList()),
duplicate_finder_(duplicate_finder),
invalid_productions_(0),
- is_non_simple_parameter_list_(0) {
- base->classifier_ = this;
- reported_errors_begin_ = reported_errors_end_ = reported_errors_->size();
- }
+ is_non_simple_parameter_list_(0) {}
- V8_INLINE ~ExpressionClassifier() {
- Discard();
- if (base_->classifier_ == this) base_->classifier_ = previous_;
- }
+ virtual ~ExpressionClassifierBase() = default;
V8_INLINE bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
@@ -150,80 +166,338 @@ class ExpressionClassifier {
return is_valid(AsyncArrowFormalParametersProduction);
}
+ V8_INLINE bool is_simple_parameter_list() const {
+ return !is_non_simple_parameter_list_;
+ }
+
+ V8_INLINE void RecordNonSimpleParameter() {
+ is_non_simple_parameter_list_ = 1;
+ }
+
+ V8_INLINE void Accumulate(ExpressionClassifier<Types>* const inner,
+ unsigned productions) {
+#ifdef DEBUG
+ static_cast<ErrorTracker*>(this)->CheckErrorPositions(inner);
+#endif
+ // 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) {
+ unsigned errors = non_arrow_inner_invalid_productions & productions &
+ ~this->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 &&
+ this->is_valid_arrow_formal_parameters()) {
+ // Also whether we've seen any non-simple parameters
+ // if expecting an arrow function parameter.
+ this->is_non_simple_parameter_list_ |=
+ inner->is_non_simple_parameter_list_;
+ if (!inner->is_valid_binding_pattern()) {
+ copy_BP_to_AFP = true;
+ this->invalid_productions_ |= ArrowFormalParametersProduction;
+ }
+ }
+ if (errors != 0 || copy_BP_to_AFP) {
+ this->invalid_productions_ |= errors;
+ static_cast<ErrorTracker*>(this)->AccumulateErrorImpl(
+ inner, productions, errors, copy_BP_to_AFP);
+ }
+ }
+ static_cast<ErrorTracker*>(this)->RewindErrors(inner);
+ }
+
+ protected:
+ typename Types::Base* base_;
+ DuplicateFinder* duplicate_finder_;
+ unsigned invalid_productions_ : kUnusedError;
+ STATIC_ASSERT(kUnusedError <= 15);
+ unsigned is_non_simple_parameter_list_ : 1;
+};
+
+template <typename Types>
+class ExpressionClassifierErrorTracker
+ : public ExpressionClassifierBase<Types,
+ ExpressionClassifierErrorTracker<Types>> {
+ public:
+ using BaseClassType =
+ ExpressionClassifierBase<Types, ExpressionClassifierErrorTracker<Types>>;
+ using typename BaseClassType::Error;
+ using typename BaseClassType::ErrorKind;
+ using TP = typename BaseClassType::TargetProduction;
+
+ ExpressionClassifierErrorTracker(typename Types::Base* base,
+ DuplicateFinder* duplicate_finder)
+ : BaseClassType(base, duplicate_finder),
+ reported_errors_(base->impl()->GetReportedErrorList()) {
+ reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
+ }
+
+ ~ExpressionClassifierErrorTracker() override { Discard(); }
+
+ 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_);
+ }
+
+ protected:
+ V8_INLINE const Error& reported_error(ErrorKind kind) const {
+ if (this->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.
+ UNREACHABLE();
+
+ // Make MSVC happy by returning an error from this inaccessible path.
+ 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, this->base_->impl()->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_LT(i, reported_errors_->length());
+ if (reported_errors_end_ != i)
+ reported_errors_->at(reported_errors_end_) = reported_errors_->at(i);
+ reported_errors_end_++;
+ }
+
+ private:
+#ifdef DEBUG
+ V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) {
+ DCHECK_EQ(inner->reported_errors_, this->reported_errors_);
+ DCHECK_EQ(inner->reported_errors_begin_, this->reported_errors_end_);
+ DCHECK_EQ(inner->reported_errors_end_, this->reported_errors_->length());
+ }
+#endif
+
+ V8_INLINE void RewindErrors(ExpressionClassifier<Types>* const inner) {
+ this->reported_errors_->Rewind(this->reported_errors_end_);
+ inner->reported_errors_begin_ = inner->reported_errors_end_ =
+ this->reported_errors_end_;
+ }
+
+ void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner,
+ unsigned productions, unsigned errors,
+ bool copy_BP_to_AFP) {
+ // Traverse the list of errors reported by the inner classifier
+ // to copy what's necessary.
+ int binding_pattern_index = inner->reported_errors_end_;
+ for (int i = inner->reported_errors_begin_; i < inner->reported_errors_end_;
+ i++) {
+ int k = this->reported_errors_->at(i).kind;
+ if (errors & (1 << k)) this->Copy(i);
+ // Check if it's a BP error that has to be copied to an AFP error.
+ if (k == ErrorKind::kBindingPatternProduction && copy_BP_to_AFP) {
+ if (this->reported_errors_end_ <= i) {
+ // If the BP error itself has not already been copied,
+ // copy it now and change it to an AFP error.
+ this->Copy(i);
+ this->reported_errors_->at(this->reported_errors_end_ - 1).kind =
+ ErrorKind::kArrowFormalParametersProduction;
+ } else {
+ // Otherwise, if the BP error was already copied, keep its
+ // position and wait until the end of the traversal.
+ DCHECK_EQ(this->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 (this->reported_errors_end_ < inner->reported_errors_end_)
+ this->Copy(binding_pattern_index);
+ else
+ Add(this->reported_errors_->at(binding_pattern_index));
+ this->reported_errors_->at(this->reported_errors_end_ - 1).kind =
+ ErrorKind::kArrowFormalParametersProduction;
+ }
+ }
+
+ private:
+ ZoneList<Error>* reported_errors_;
+ // 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_;
+
+ friend BaseClassType;
+};
+
+template <typename Types>
+class ExpressionClassifierEmptyErrorTracker
+ : public ExpressionClassifierBase<
+ Types, ExpressionClassifierEmptyErrorTracker<Types>> {
+ public:
+ using BaseClassType =
+ ExpressionClassifierBase<Types,
+ ExpressionClassifierEmptyErrorTracker<Types>>;
+ using typename BaseClassType::Error;
+ using typename BaseClassType::ErrorKind;
+ using TP = typename BaseClassType::TargetProduction;
+
+ ExpressionClassifierEmptyErrorTracker(typename Types::Base* base,
+ DuplicateFinder* duplicate_finder)
+ : BaseClassType(base, duplicate_finder) {}
+
+ V8_INLINE void Discard() {}
+
+ protected:
+ V8_INLINE const Error& reported_error(ErrorKind kind) const {
+ static Error none;
+ return none;
+ }
+
+ V8_INLINE void Add(const Error& e) {}
+
+ private:
+#ifdef DEBUG
+ V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) {
+ }
+#endif
+ V8_INLINE void RewindErrors(ExpressionClassifier<Types>* const inner) {}
+ V8_INLINE void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner,
+ unsigned productions, unsigned errors,
+ bool copy_BP_to_AFP) {}
+
+ friend BaseClassType;
+};
+
+template <typename Types>
+class ExpressionClassifier
+ : public std::conditional<
+ Types::ExpressionClassifierReportErrors,
+ ExpressionClassifierErrorTracker<Types>,
+ ExpressionClassifierEmptyErrorTracker<Types>>::type {
+ static constexpr bool ReportErrors = Types::ExpressionClassifierReportErrors;
+
+ public:
+ using BaseClassType = typename std::conditional<
+ Types::ExpressionClassifierReportErrors,
+ typename ExpressionClassifierErrorTracker<Types>::BaseClassType,
+ typename ExpressionClassifierEmptyErrorTracker<Types>::BaseClassType>::
+ type;
+ using typename BaseClassType::Error;
+ using typename BaseClassType::ErrorKind;
+ using TP = typename BaseClassType::TargetProduction;
+
+ explicit ExpressionClassifier(typename Types::Base* base,
+ DuplicateFinder* duplicate_finder = nullptr)
+ : std::conditional<Types::ExpressionClassifierReportErrors,
+ ExpressionClassifierErrorTracker<Types>,
+ ExpressionClassifierEmptyErrorTracker<Types>>::
+ type(base, duplicate_finder),
+ previous_(base->classifier_) {
+ base->classifier_ = this;
+ }
+
+ V8_INLINE ~ExpressionClassifier() override {
+ if (this->base_->classifier_ == this) this->base_->classifier_ = previous_;
+ }
+
V8_INLINE const Error& expression_error() const {
- return reported_error(kExpressionProduction);
+ return this->reported_error(ErrorKind::kExpressionProduction);
}
V8_INLINE const Error& formal_parameter_initializer_error() const {
- return reported_error(kFormalParameterInitializerProduction);
+ return this->reported_error(
+ ErrorKind::kFormalParameterInitializerProduction);
}
V8_INLINE const Error& binding_pattern_error() const {
- return reported_error(kBindingPatternProduction);
+ return this->reported_error(ErrorKind::kBindingPatternProduction);
}
V8_INLINE const Error& assignment_pattern_error() const {
- return reported_error(kAssignmentPatternProduction);
+ return this->reported_error(ErrorKind::kAssignmentPatternProduction);
}
V8_INLINE const Error& arrow_formal_parameters_error() const {
- return reported_error(kArrowFormalParametersProduction);
+ return this->reported_error(ErrorKind::kArrowFormalParametersProduction);
}
V8_INLINE const Error& duplicate_formal_parameter_error() const {
- return reported_error(kDistinctFormalParametersProduction);
+ return this->reported_error(ErrorKind::kDistinctFormalParametersProduction);
}
V8_INLINE const Error& strict_mode_formal_parameter_error() const {
- return reported_error(kStrictModeFormalParametersProduction);
+ return this->reported_error(
+ ErrorKind::kStrictModeFormalParametersProduction);
}
V8_INLINE const Error& let_pattern_error() const {
- return reported_error(kLetPatternProduction);
+ return this->reported_error(ErrorKind::kLetPatternProduction);
}
V8_INLINE const Error& async_arrow_formal_parameters_error() const {
- return reported_error(kAsyncArrowFormalParametersProduction);
- }
-
- V8_INLINE bool is_simple_parameter_list() const {
- return !is_non_simple_parameter_list_;
+ return this->reported_error(
+ ErrorKind::kAsyncArrowFormalParametersProduction);
}
- V8_INLINE void RecordNonSimpleParameter() {
- is_non_simple_parameter_list_ = 1;
- }
+ V8_INLINE bool does_error_reporting() { return ReportErrors; }
void RecordExpressionError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_expression()) return;
- invalid_productions_ |= ExpressionProduction;
- Add(Error(loc, message, kExpressionProduction, arg));
+ if (!this->is_valid_expression()) return;
+ this->invalid_productions_ |= TP::ExpressionProduction;
+ this->Add(Error(loc, message, ErrorKind::kExpressionProduction, arg));
}
void RecordFormalParameterInitializerError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_formal_parameter_initializer()) return;
- invalid_productions_ |= FormalParameterInitializerProduction;
- Add(Error(loc, message, kFormalParameterInitializerProduction, arg));
+ if (!this->is_valid_formal_parameter_initializer()) return;
+ this->invalid_productions_ |= TP::FormalParameterInitializerProduction;
+ this->Add(Error(loc, message,
+ ErrorKind::kFormalParameterInitializerProduction, arg));
}
void RecordBindingPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_binding_pattern()) return;
- invalid_productions_ |= BindingPatternProduction;
- Add(Error(loc, message, kBindingPatternProduction, arg));
+ if (!this->is_valid_binding_pattern()) return;
+ this->invalid_productions_ |= TP::BindingPatternProduction;
+ this->Add(Error(loc, message, ErrorKind::kBindingPatternProduction, arg));
}
void RecordAssignmentPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_assignment_pattern()) return;
- invalid_productions_ |= AssignmentPatternProduction;
- Add(Error(loc, message, kAssignmentPatternProduction, arg));
+ if (!this->is_valid_assignment_pattern()) return;
+ this->invalid_productions_ |= TP::AssignmentPatternProduction;
+ this->Add(
+ Error(loc, message, ErrorKind::kAssignmentPatternProduction, arg));
}
void RecordPatternError(const Scanner::Location& loc,
@@ -236,24 +510,26 @@ class ExpressionClassifier {
void RecordArrowFormalParametersError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_arrow_formal_parameters()) return;
- invalid_productions_ |= ArrowFormalParametersProduction;
- Add(Error(loc, message, kArrowFormalParametersProduction, arg));
+ if (!this->is_valid_arrow_formal_parameters()) return;
+ this->invalid_productions_ |= TP::ArrowFormalParametersProduction;
+ this->Add(
+ Error(loc, message, ErrorKind::kArrowFormalParametersProduction, arg));
}
void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_async_arrow_formal_parameters()) return;
- invalid_productions_ |= AsyncArrowFormalParametersProduction;
- Add(Error(loc, message, kAsyncArrowFormalParametersProduction, arg));
+ if (!this->is_valid_async_arrow_formal_parameters()) return;
+ this->invalid_productions_ |= TP::AsyncArrowFormalParametersProduction;
+ this->Add(Error(loc, message,
+ ErrorKind::kAsyncArrowFormalParametersProduction, arg));
}
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
- if (!is_valid_formal_parameter_list_without_duplicates()) return;
- invalid_productions_ |= DistinctFormalParametersProduction;
- Add(Error(loc, MessageTemplate::kParamDupe,
- kDistinctFormalParametersProduction));
+ if (!this->is_valid_formal_parameter_list_without_duplicates()) return;
+ this->invalid_productions_ |= TP::DistinctFormalParametersProduction;
+ this->Add(Error(loc, MessageTemplate::kParamDupe,
+ ErrorKind::kDistinctFormalParametersProduction));
}
// Record a binding that would be invalid in strict mode. Confusingly this
@@ -262,160 +538,30 @@ class ExpressionClassifier {
void RecordStrictModeFormalParameterError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_strict_mode_formal_parameters()) return;
- invalid_productions_ |= StrictModeFormalParametersProduction;
- Add(Error(loc, message, kStrictModeFormalParametersProduction, arg));
+ if (!this->is_valid_strict_mode_formal_parameters()) return;
+ this->invalid_productions_ |= TP::StrictModeFormalParametersProduction;
+ this->Add(Error(loc, message,
+ ErrorKind::kStrictModeFormalParametersProduction, arg));
}
void RecordLetPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
- if (!is_valid_let_pattern()) return;
- invalid_productions_ |= LetPatternProduction;
- Add(Error(loc, message, kLetPatternProduction, arg));
- }
-
- 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_->size());
- // 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) {
- 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 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;
- }
- }
- // 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_->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_->size()) {
- reported_errors_->resize(reported_errors_begin_);
- reported_errors_end_ = reported_errors_begin_;
- }
- DCHECK_EQ(reported_errors_begin_, reported_errors_end_);
+ if (!this->is_valid_let_pattern()) return;
+ this->invalid_productions_ |= TP::LetPatternProduction;
+ this->Add(Error(loc, message, ErrorKind::kLetPatternProduction, arg));
}
ExpressionClassifier* previous() const { return previous_; }
private:
- V8_INLINE const 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.
- UNREACHABLE();
-
- // Make MSVC happy by returning an error from this inaccessible path.
- 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_->size());
- reported_errors_->push_back(e);
- 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_LT(i, reported_errors_->size());
- if (reported_errors_end_ != i)
- reported_errors_->at(reported_errors_end_) = reported_errors_->at(i);
- reported_errors_end_++;
- }
-
- typename Types::Base* base_;
ExpressionClassifier* previous_;
- Zone* zone_;
- ZoneVector<Error>* reported_errors_;
- DuplicateFinder* duplicate_finder_;
- 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:
- // 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_;
DISALLOW_COPY_AND_ASSIGN(ExpressionClassifier);
};
-
#undef ERROR_CODES
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/func-name-inferrer.h b/deps/v8/src/parsing/func-name-inferrer.h
index 8f0f428a05..d46d7f2c2b 100644
--- a/deps/v8/src/parsing/func-name-inferrer.h
+++ b/deps/v8/src/parsing/func-name-inferrer.h
@@ -36,12 +36,8 @@ class FuncNameInferrer : public ZoneObject {
// on the stack.
class State {
public:
- explicit State(FuncNameInferrer* fni) : fni_(fni) {
- if (fni_ != nullptr) fni_->Enter();
- }
- ~State() {
- if (fni_ != nullptr) fni_->Leave();
- }
+ explicit State(FuncNameInferrer* fni) : fni_(fni) { fni_->Enter(); }
+ ~State() { fni_->Leave(); }
private:
FuncNameInferrer* fni_;
diff --git a/deps/v8/src/parsing/parse-info.cc b/deps/v8/src/parsing/parse-info.cc
index 0a58c4f0bd..129b00a2c2 100644
--- a/deps/v8/src/parsing/parse-info.cc
+++ b/deps/v8/src/parsing/parse-info.cc
@@ -16,7 +16,7 @@
namespace v8 {
namespace internal {
-ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator)
+ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
: zone_(base::make_unique<Zone>(zone_allocator, ZONE_NAME)),
flags_(0),
extension_(nullptr),
@@ -37,7 +37,10 @@ ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator)
function_name_(nullptr),
runtime_call_stats_(nullptr),
source_range_map_(nullptr),
- literal_(nullptr) {
+ literal_(nullptr) {}
+
+ParseInfo::ParseInfo(Isolate* isolate, AccountingAllocator* zone_allocator)
+ : ParseInfo(zone_allocator) {
set_hash_seed(isolate->heap()->HashSeed());
set_stack_limit(isolate->stack_guard()->real_climit());
set_unicode_cache(isolate->unicode_cache());
@@ -54,6 +57,18 @@ ParseInfo::ParseInfo(Isolate* isolate)
LOG(isolate, ScriptEvent(Logger::ScriptEventType::kReserveId, script_id_));
}
+template <typename T>
+void ParseInfo::SetFunctionInfo(T function) {
+ set_is_named_expression(function->is_named_expression());
+ set_language_mode(function->language_mode());
+ set_function_kind(function->kind());
+ set_declaration(function->is_declaration());
+ set_requires_instance_fields_initializer(
+ function->requires_instance_fields_initializer());
+ set_toplevel(function->is_toplevel());
+ set_wrapped_as_function(function->is_wrapped());
+}
+
ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared)
: ParseInfo(isolate, isolate->allocator()) {
// Do not support re-parsing top-level function of a wrapped script.
@@ -61,19 +76,13 @@ ParseInfo::ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared)
// wrapped script at all.
DCHECK_IMPLIES(is_toplevel(), !Script::cast(shared->script())->is_wrapped());
- set_toplevel(shared->is_toplevel());
- set_wrapped_as_function(shared->is_wrapped());
set_allow_lazy_parsing(FLAG_lazy_inner_functions);
- set_is_named_expression(shared->is_named_expression());
+ set_asm_wasm_broken(shared->is_asm_wasm_broken());
+
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());
+ SetFunctionInfo(shared);
Handle<Script> script(Script::cast(shared->script()), isolate);
set_script(script);
@@ -99,37 +108,44 @@ ParseInfo::ParseInfo(Isolate* isolate, Handle<Script> script)
script->IsUserJavaScript());
}
-ParseInfo::~ParseInfo() {}
-
-DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
-
-void ParseInfo::EmitBackgroundParseStatisticsOnBackgroundThread() {
- // If runtime call stats was enabled by tracing, emit a trace event at the
- // end of background parsing on the background thread.
- if (runtime_call_stats_ &&
- (FLAG_runtime_stats &
- v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
- auto value = v8::tracing::TracedValue::Create();
- runtime_call_stats_->Dump(value.get());
- TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats"),
- "V8.RuntimeStats", TRACE_EVENT_SCOPE_THREAD,
- "runtime-call-stats", std::move(value));
- }
+// static
+std::unique_ptr<ParseInfo> ParseInfo::FromParent(
+ const ParseInfo* outer_parse_info, AccountingAllocator* zone_allocator,
+ const FunctionLiteral* literal, const AstRawString* function_name) {
+ std::unique_ptr<ParseInfo> result =
+ base::make_unique<ParseInfo>(zone_allocator);
+
+ // Replicate shared state of the outer_parse_info.
+ result->flags_ = outer_parse_info->flags_;
+ result->script_id_ = outer_parse_info->script_id_;
+ result->set_logger(outer_parse_info->logger());
+ result->set_ast_string_constants(outer_parse_info->ast_string_constants());
+ result->set_hash_seed(outer_parse_info->hash_seed());
+
+ DCHECK_EQ(outer_parse_info->parameters_end_pos(), kNoSourcePosition);
+ DCHECK_NULL(outer_parse_info->extension());
+ DCHECK(outer_parse_info->maybe_outer_scope_info().is_null());
+
+ // Clone the function_name AstRawString into the ParseInfo's own
+ // AstValueFactory.
+ const AstRawString* cloned_function_name =
+ result->GetOrCreateAstValueFactory()->CloneFromOtherFactory(
+ function_name);
+
+ // Setup function specific details.
+ DCHECK(!literal->is_toplevel());
+ result->set_function_name(cloned_function_name);
+ result->set_start_position(literal->start_position());
+ result->set_end_position(literal->end_position());
+ result->set_function_literal_id(literal->function_literal_id());
+ result->SetFunctionInfo(literal);
+
+ return result;
}
-void ParseInfo::UpdateBackgroundParseStatisticsOnMainThread(Isolate* isolate) {
- // Copy over the counters from the background thread to the main counters on
- // the isolate.
- RuntimeCallStats* main_call_stats = isolate->counters()->runtime_call_stats();
- if (FLAG_runtime_stats ==
- v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE) {
- DCHECK_NE(main_call_stats, runtime_call_stats());
- DCHECK_NOT_NULL(main_call_stats);
- DCHECK_NOT_NULL(runtime_call_stats());
- main_call_stats->Add(runtime_call_stats());
- }
- set_runtime_call_stats(main_call_stats);
-}
+ParseInfo::~ParseInfo() = default;
+
+DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
Handle<Script> ParseInfo::CreateScript(Isolate* isolate, Handle<String> source,
ScriptOriginOptions origin_options,
diff --git a/deps/v8/src/parsing/parse-info.h b/deps/v8/src/parsing/parse-info.h
index 64a50806f5..ba3e3d2898 100644
--- a/deps/v8/src/parsing/parse-info.h
+++ b/deps/v8/src/parsing/parse-info.h
@@ -12,6 +12,7 @@
#include "include/v8.h"
#include "src/globals.h"
#include "src/handles.h"
+#include "src/objects/script.h"
#include "src/parsing/preparsed-scope-data.h"
#include "src/pending-compilation-error-handler.h"
@@ -37,11 +38,18 @@ class Zone;
// A container for the inputs, configuration options, and outputs of parsing.
class V8_EXPORT_PRIVATE ParseInfo {
public:
- ParseInfo(Isolate*);
+ explicit ParseInfo(AccountingAllocator* zone_allocator);
+ explicit ParseInfo(Isolate*);
ParseInfo(Isolate*, AccountingAllocator* zone_allocator);
ParseInfo(Isolate* isolate, Handle<Script> script);
ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared);
+ // Creates a new parse info based on parent top-level |outer_parse_info| for
+ // function |literal|.
+ static std::unique_ptr<ParseInfo> FromParent(
+ const ParseInfo* outer_parse_info, AccountingAllocator* zone_allocator,
+ const FunctionLiteral* literal, const AstRawString* function_name);
+
~ParseInfo();
Handle<Script> CreateScript(Isolate* isolate, Handle<String> source,
@@ -105,9 +113,12 @@ class V8_EXPORT_PRIVATE ParseInfo {
v8::Extension* extension() const { return extension_; }
void set_extension(v8::Extension* extension) { extension_ = extension; }
-
+ void set_consumed_preparsed_scope_data(
+ std::unique_ptr<ConsumedPreParsedScopeData> data) {
+ consumed_preparsed_scope_data_.swap(data);
+ }
ConsumedPreParsedScopeData* consumed_preparsed_scope_data() {
- return &consumed_preparsed_scope_data_;
+ return consumed_preparsed_scope_data_.get();
}
DeclarationScope* script_scope() const { return script_scope_; }
@@ -198,6 +209,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
// TODO(titzer): these should not be part of ParseInfo.
//--------------------------------------------------------------------------
Handle<Script> script() const { return script_; }
+ void set_script(Handle<Script> script);
+
MaybeHandle<ScopeInfo> maybe_outer_scope_info() const {
return maybe_outer_scope_info_;
}
@@ -216,12 +229,13 @@ class V8_EXPORT_PRIVATE ParseInfo {
set_strict_mode(is_strict(language_mode));
}
- void EmitBackgroundParseStatisticsOnBackgroundThread();
- void UpdateBackgroundParseStatisticsOnMainThread(Isolate* isolate);
-
private:
void SetScriptForToplevelCompile(Isolate* isolate, Handle<Script> script);
- void set_script(Handle<Script> script);
+
+ // Set function info flags based on those in either FunctionLiteral or
+ // SharedFunctionInfo |function|
+ template <typename T>
+ void SetFunctionInfo(T function);
// Various configuration flags for parsing.
enum Flag {
@@ -268,7 +282,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::unique_ptr<ConsumedPreParsedScopeData> consumed_preparsed_scope_data_;
std::unique_ptr<AstValueFactory> ast_value_factory_;
const class AstStringConstants* ast_string_constants_;
const AstRawString* function_name_;
diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h
index 9d13724f06..d1ad0e9d13 100644
--- a/deps/v8/src/parsing/parser-base.h
+++ b/deps/v8/src/parsing/parser-base.h
@@ -5,12 +5,14 @@
#ifndef V8_PARSING_PARSER_BASE_H_
#define V8_PARSING_PARSER_BASE_H_
+#include <stdint.h>
#include <vector>
#include "src/ast/ast-source-ranges.h"
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/bailout-reason.h"
+#include "src/base/flags.h"
#include "src/base/hashmap.h"
#include "src/base/v8-fallthrough.h"
#include "src/counters.h"
@@ -37,31 +39,13 @@ enum AllowLabelledFunctionStatement {
kDisallowLabelledFunctionStatement,
};
-enum class ParseFunctionFlags {
+enum class ParseFunctionFlag : uint8_t {
kIsNormal = 0,
- kIsGenerator = 1,
- kIsAsync = 2,
- kIsDefault = 4
+ kIsGenerator = 1 << 0,
+ kIsAsync = 1 << 1
};
-static inline ParseFunctionFlags operator|(ParseFunctionFlags lhs,
- ParseFunctionFlags rhs) {
- typedef unsigned char T;
- return static_cast<ParseFunctionFlags>(static_cast<T>(lhs) |
- static_cast<T>(rhs));
-}
-
-static inline ParseFunctionFlags& operator|=(ParseFunctionFlags& lhs,
- const ParseFunctionFlags& rhs) {
- lhs = lhs | rhs;
- return lhs;
-}
-
-static inline bool operator&(ParseFunctionFlags bitfield,
- ParseFunctionFlags mask) {
- typedef unsigned char T;
- return static_cast<T>(bitfield) & static_cast<T>(mask);
-}
+typedef base::Flags<ParseFunctionFlag> ParseFunctionFlags;
struct FormalParametersBase {
explicit FormalParametersBase(DeclarationScope* scope) : scope(scope) {}
@@ -228,6 +212,17 @@ class SourceRangeScope final {
template <typename Impl>
struct ParserTypes;
+enum class ParsePropertyKind : uint8_t {
+ kAccessorGetter,
+ kAccessorSetter,
+ kValue,
+ kShorthand,
+ kMethod,
+ kClassField,
+ kSpread,
+ kNotSet
+};
+
template <typename Impl>
class ParserBase {
public:
@@ -248,6 +243,10 @@ class ParserBase {
typedef typename Types::ForStatement ForStatementT;
typedef typename v8::internal::ExpressionClassifier<Types>
ExpressionClassifier;
+ typedef typename Types::FuncNameInferrer FuncNameInferrer;
+ typedef typename Types::FuncNameInferrer::State FuncNameInferrerState;
+ typedef typename Types::SourceRange SourceRange;
+ typedef typename Types::SourceRangeScope SourceRangeScope;
// All implementation-specific methods must be called through this.
Impl* impl() { return static_cast<Impl*>(this); }
@@ -262,7 +261,7 @@ class ParserBase {
original_scope_(nullptr),
function_state_(nullptr),
extension_(extension),
- fni_(nullptr),
+ fni_(ast_value_factory, zone),
ast_value_factory_(ast_value_factory),
ast_node_factory_(ast_value_factory, zone),
runtime_call_stats_(runtime_call_stats),
@@ -300,12 +299,6 @@ class ParserBase {
#undef ALLOW_ACCESSORS
- bool allow_harmony_bigint() const {
- return scanner()->allow_harmony_bigint();
- }
- void set_allow_harmony_bigint(bool allow) {
- scanner()->set_allow_harmony_bigint(allow);
- }
bool allow_harmony_numeric_separator() const {
return scanner()->allow_harmony_numeric_separator();
}
@@ -370,7 +363,7 @@ class ParserBase {
// The parser's current scope is in scope_. BlockState and FunctionState
// constructors push on the scope stack and the destructors pop. They are also
// used to hold the parser's per-funcion state.
- class BlockState BASE_EMBEDDED {
+ class BlockState {
public:
BlockState(Scope** scope_stack, Scope* scope)
: scope_stack_(scope_stack), outer_scope_(*scope_stack) {
@@ -433,7 +426,7 @@ class ParserBase {
return destructuring_assignments_to_rewrite_;
}
- ZoneVector<typename ExpressionClassifier::Error>* GetReportedErrorList() {
+ ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() {
return &reported_errors_;
}
@@ -490,8 +483,7 @@ class ParserBase {
ZoneChunkList<RewritableExpressionT> destructuring_assignments_to_rewrite_;
- // We use a ZoneVector here because we need to do a lot of random access.
- ZoneVector<typename ExpressionClassifier::Error> reported_errors_;
+ ZoneList<typename ExpressionClassifier::Error> reported_errors_;
// A reason, if any, why this function should not be optimized.
BailoutReason dont_optimize_reason_;
@@ -652,11 +644,11 @@ class ParserBase {
// scope itself is either allocated in zone() or in target_zone if one is
// passed in.
DeclarationScope* NewFunctionScope(FunctionKind kind,
- Zone* target_zone = nullptr) const {
+ Zone* parse_zone = nullptr) const {
DCHECK(ast_value_factory());
- if (target_zone == nullptr) target_zone = zone();
- DeclarationScope* result = new (target_zone)
- DeclarationScope(zone(), scope(), FUNCTION_SCOPE, kind);
+ if (parse_zone == nullptr) parse_zone = zone();
+ DeclarationScope* result = new (zone())
+ DeclarationScope(parse_zone, scope(), FUNCTION_SCOPE, kind);
// Record presence of an inner function scope
function_state_->RecordFunctionOrEvalCall();
@@ -679,6 +671,8 @@ class ParserBase {
AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
int position() const { return scanner_->location().beg_pos; }
int peek_position() const { return scanner_->peek_location().beg_pos; }
+ int end_position() const { return scanner_->location().end_pos; }
+ int peek_end_position() const { return scanner_->peek_location().end_pos; }
bool stack_overflow() const {
return pending_error_handler()->stack_overflow();
}
@@ -694,8 +688,7 @@ class ParserBase {
// Returns the position past the following semicolon (if it exists), and the
// position past the end of the current token otherwise.
int PositionAfterSemicolon() {
- return (peek() == Token::SEMICOLON) ? scanner_->peek_location().end_pos
- : scanner_->location().end_pos;
+ return (peek() == Token::SEMICOLON) ? peek_end_position() : end_position();
}
V8_INLINE Token::Value PeekAhead() {
@@ -720,7 +713,7 @@ class ParserBase {
Token::Value next = Next();
USE(next);
USE(token);
- DCHECK(next == token);
+ DCHECK_EQ(next, token);
}
bool Check(Token::Value token) {
@@ -753,22 +746,14 @@ class ParserBase {
return;
}
- Token::Value current = scanner()->current_token();
- Scanner::Location current_location = scanner()->location();
- Token::Value next = Next();
-
- if (next == Token::SEMICOLON) {
- return;
- }
-
*ok = false;
- if (current == Token::AWAIT && !is_async_function()) {
- ReportMessageAt(current_location,
+ if (scanner()->current_token() == Token::AWAIT && !is_async_function()) {
+ ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitNotInAsyncFunction, kSyntaxError);
return;
}
- ReportUnexpectedToken(next);
+ ReportUnexpectedToken(Next());
}
// Dummy functions, just useful as arguments to CHECK_OK_CUSTOM.
@@ -778,14 +763,7 @@ class ParserBase {
return result;
}
- bool is_any_identifier(Token::Value token) {
- return token == Token::IDENTIFIER || token == Token::ENUM ||
- token == Token::AWAIT || token == Token::ASYNC ||
- token == Token::ESCAPED_STRICT_RESERVED_WORD ||
- token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::LET ||
- token == Token::STATIC || token == Token::YIELD;
- }
- bool peek_any_identifier() { return is_any_identifier(peek()); }
+ bool peek_any_identifier() { return Token::IsAnyIdentifier(peek()); }
bool CheckContextualKeyword(Token::Value token) {
if (PeekContextualKeyword(token)) {
@@ -961,7 +939,11 @@ class ParserBase {
void ReportClassifierError(
const typename ExpressionClassifier::Error& error) {
- impl()->ReportMessageAt(error.location, error.message, error.arg);
+ if (classifier()->does_error_reporting()) {
+ impl()->ReportMessageAt(error.location, error.message, error.arg);
+ } else {
+ impl()->ReportUnidentifiableError();
+ }
}
void ValidateExpression(bool* ok) {
@@ -1006,7 +988,7 @@ class ParserBase {
}
bool IsValidArrowFormalParametersStart(Token::Value token) {
- return is_any_identifier(token) || token == Token::LPAREN;
+ return Token::IsAnyIdentifier(token) || token == Token::LPAREN;
}
void ValidateArrowFormalParameters(ExpressionT expr,
@@ -1096,15 +1078,12 @@ class ParserBase {
ExpressionT ParseRegExpLiteral(bool* ok);
+ ExpressionT ParseBindingPattern(bool* ok);
ExpressionT ParsePrimaryExpression(bool* is_async, bool* ok);
- ExpressionT ParsePrimaryExpression(bool* ok) {
- bool is_async;
- return ParsePrimaryExpression(&is_async, ok);
- }
// Use when parsing an expression that is known to not be a pattern or part
// of a pattern.
- V8_INLINE ExpressionT ParseExpression(bool accept_IN, bool* ok);
+ V8_INLINE ExpressionT ParseExpression(bool* ok);
// This method does not wrap the parsing of the expression inside a
// new expression classifier; it uses the top-level classifier instead.
@@ -1117,28 +1096,21 @@ class ParserBase {
ExpressionT ParseArrayLiteral(bool* ok);
- enum class PropertyKind {
- kAccessorProperty,
- kValueProperty,
- kShorthandProperty,
- kMethodProperty,
- kClassField,
- kSpreadProperty,
- kNotSet
- };
+ inline static bool IsAccessor(ParsePropertyKind kind) {
+ return IsInRange(kind, ParsePropertyKind::kAccessorGetter,
+ ParsePropertyKind::kAccessorSetter);
+ }
- bool SetPropertyKindFromToken(Token::Value token, PropertyKind* kind);
- ExpressionT ParsePropertyName(IdentifierT* name, PropertyKind* kind,
- bool* is_generator, bool* is_get, bool* is_set,
- bool* is_async, bool* is_computed_name,
- bool* ok);
+ ExpressionT ParsePropertyName(IdentifierT* name, ParsePropertyKind* kind,
+ ParseFunctionFlags* flags,
+ bool* is_computed_name, bool* ok);
ExpressionT ParseObjectLiteral(bool* ok);
ClassLiteralPropertyT ParseClassPropertyDefinition(
ClassLiteralChecker* checker, ClassInfo* class_info,
IdentifierT* property_name, bool has_extends, bool* is_computed_name,
ClassLiteralProperty::Kind* property_kind, bool* is_static, bool* ok);
- ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, bool is_static,
- bool* ok);
+ ExpressionT ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
+ bool is_static, bool* ok);
ObjectLiteralPropertyT ParseObjectPropertyDefinition(
ObjectLiteralChecker* checker, bool* is_computed_name,
bool* is_rest_property, bool* ok);
@@ -1147,17 +1119,26 @@ class ParserBase {
bool* is_simple_parameter_list, bool* ok);
ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
bool* ok) {
- return ParseArguments(first_spread_pos, false, nullptr, ok);
+ bool is_simple = true;
+ return ParseArguments(first_spread_pos, false, &is_simple, ok);
}
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
ExpressionT ParseYieldExpression(bool accept_IN, bool* ok);
V8_INLINE ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok);
+ ExpressionT ParseConditionalContinuation(ExpressionT expression,
+ bool accept_IN, int pos, bool* ok);
ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
- ExpressionT ParseUnaryExpression(bool* ok);
+ ExpressionT ParseUnaryOpExpression(bool* ok);
+ ExpressionT ParseAwaitExpression(bool* ok);
+ ExpressionT ParsePrefixExpression(bool* ok);
+ V8_INLINE ExpressionT ParseUnaryExpression(bool* ok);
V8_INLINE ExpressionT ParsePostfixExpression(bool* ok);
V8_INLINE ExpressionT ParseLeftHandSideExpression(bool* ok);
- ExpressionT ParseMemberWithNewPrefixesExpression(bool* is_async, bool* ok);
+ ExpressionT ParseMemberWithPresentNewPrefixesExpression(bool* is_async,
+ bool* ok);
+ V8_INLINE ExpressionT ParseMemberWithNewPrefixesExpression(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);
@@ -1169,8 +1150,6 @@ class ParserBase {
ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
const FormalParametersT& parameters,
int rewritable_length, bool* ok);
- void ParseSingleExpressionFunctionBody(StatementListT body, bool is_async,
- bool accept_IN, bool* ok);
void ParseAsyncFunctionBody(Scope* scope, StatementListT body, bool* ok);
ExpressionT ParseAsyncFunctionLiteral(bool* ok);
ExpressionT ParseClassLiteral(IdentifierT name,
@@ -1205,11 +1184,14 @@ class ParserBase {
bool default_export, bool* ok);
StatementT ParseNativeDeclaration(bool* ok);
+ // Whether we're parsing a single-expression arrow function or something else.
+ enum class FunctionBodyType { kExpression, kBlock };
// Consumes the ending }.
void ParseFunctionBody(StatementListT result, IdentifierT function_name,
int pos, const FormalParametersT& parameters,
FunctionKind kind,
- FunctionLiteral::FunctionType function_type, bool* ok);
+ FunctionLiteral::FunctionType function_type,
+ FunctionBodyType body_type, bool accept_IN, bool* ok);
// Under some circumstances, we allow preparsing to abort if the preparsed
// function is "long and trivial", and fully parse instead. Our current
@@ -1363,8 +1345,7 @@ class ParserBase {
Scope* scope, Variable* var,
typename DeclarationDescriptor::Kind declaration_kind);
- FunctionKind FunctionKindForImpl(bool is_method, bool is_generator,
- bool is_async) {
+ FunctionKind FunctionKindForImpl(bool is_method, ParseFunctionFlags flags) {
static const FunctionKind kFunctionKinds[][2][2] = {
{
// is_method=false
@@ -1382,17 +1363,19 @@ class ParserBase {
FunctionKind::kConciseGeneratorMethod,
FunctionKind::kAsyncConciseGeneratorMethod},
}};
- return kFunctionKinds[is_method][is_generator][is_async];
+ return kFunctionKinds[is_method]
+ [(flags & ParseFunctionFlag::kIsGenerator) != 0]
+ [(flags & ParseFunctionFlag::kIsAsync) != 0];
}
- inline FunctionKind FunctionKindFor(bool is_generator, bool is_async) {
+ inline FunctionKind FunctionKindFor(ParseFunctionFlags flags) {
const bool kIsMethod = false;
- return FunctionKindForImpl(kIsMethod, is_generator, is_async);
+ return FunctionKindForImpl(kIsMethod, flags);
}
- inline FunctionKind MethodKindFor(bool is_generator, bool is_async) {
+ inline FunctionKind MethodKindFor(ParseFunctionFlags flags) {
const bool kIsMethod = true;
- return FunctionKindForImpl(kIsMethod, is_generator, is_async);
+ return FunctionKindForImpl(kIsMethod, flags);
}
// Keep track of eval() calls since they disable all local variable
@@ -1466,8 +1449,8 @@ class ParserBase {
explicit ClassLiteralChecker(ParserBase* parser)
: parser_(parser), has_seen_constructor_(false) {}
- void CheckClassMethodName(Token::Value property, PropertyKind type,
- bool is_generator, bool is_async, bool is_static,
+ void CheckClassMethodName(Token::Value property, ParsePropertyKind type,
+ ParseFunctionFlags flags, bool is_static,
bool* ok);
void CheckClassFieldName(bool is_static, bool* ok);
@@ -1546,7 +1529,7 @@ class ParserBase {
Scope* original_scope_; // The top scope for the current parsing item.
FunctionState* function_state_; // Function state stack.
v8::Extension* extension_;
- FuncNameInferrer* fni_;
+ FuncNameInferrer fni_;
AstValueFactory* ast_value_factory_; // Not owned.
typename Types::Factory ast_node_factory_;
RuntimeCallStats* runtime_call_stats_;
@@ -1577,8 +1560,6 @@ class ParserBase {
bool allow_harmony_import_meta_;
bool allow_harmony_private_fields_;
bool allow_eval_cache_;
-
- friend class DiscardableZoneScope;
};
template <typename Impl>
@@ -1592,13 +1573,12 @@ ParserBase<Impl>::FunctionState::FunctionState(
outer_function_state_(*function_state_stack),
scope_(scope),
destructuring_assignments_to_rewrite_(scope->zone()),
- reported_errors_(scope_->zone()),
+ reported_errors_(16, scope->zone()),
dont_optimize_reason_(BailoutReason::kNoReason),
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_;
@@ -1704,16 +1684,10 @@ template <typename Impl>
typename ParserBase<Impl>::IdentifierT
ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
Token::Value next = Next();
- if (next == Token::IDENTIFIER || next == Token::ASYNC ||
- (next == Token::AWAIT && !parsing_module_ && !is_async_function())) {
+ STATIC_ASSERT(Token::IDENTIFIER + 1 == Token::ASYNC);
+ if (IsInRange(next, Token::IDENTIFIER, Token::ASYNC)) {
IdentifierT name = impl()->GetSymbol();
- if (impl()->IsArguments(name) && scope()->ShouldBanArguments()) {
- ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer);
- *ok = false;
- return impl()->NullIdentifier();
- }
-
// When this function is used to read a formal parameter, we don't always
// know whether the function is going to be strict or sloppy. Indeed for
// arrow functions we don't always know that the identifier we are reading
@@ -1721,15 +1695,18 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
// must detect because we know we're in strict mode, we also record any
// error that we might make in the future once we know the language mode.
if (impl()->IsEvalOrArguments(name)) {
+ if (impl()->IsArguments(name) && scope()->ShouldBanArguments()) {
+ ReportMessage(MessageTemplate::kArgumentsDisallowedInInitializer);
+ *ok = false;
+ return impl()->NullIdentifier();
+ }
+
classifier()->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
if (is_strict(language_mode())) {
classifier()->RecordBindingPatternError(
scanner()->location(), MessageTemplate::kStrictEvalArguments);
}
- } else if (next == Token::AWAIT) {
- classifier()->RecordAsyncArrowFormalParametersError(
- scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
}
if (classifier()->duplicate_finder() != nullptr &&
@@ -1737,20 +1714,17 @@ ParserBase<Impl>::ParseAndClassifyIdentifier(bool* ok) {
ast_value_factory())) {
classifier()->RecordDuplicateFormalParameterError(scanner()->location());
}
+
return name;
+ } else if (next == Token::AWAIT && !parsing_module_ && !is_async_function()) {
+ classifier()->RecordAsyncArrowFormalParametersError(
+ scanner()->location(), MessageTemplate::kAwaitBindingIdentifier);
+ return impl()->GetSymbol();
} else if (is_sloppy(language_mode()) &&
- (next == Token::FUTURE_STRICT_RESERVED_WORD ||
- next == Token::ESCAPED_STRICT_RESERVED_WORD ||
- next == Token::LET || next == Token::STATIC ||
+ (Token::IsStrictReservedWord(next) ||
(next == Token::YIELD && !is_generator()))) {
classifier()->RecordStrictModeFormalParameterError(
scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
- if (next == Token::ESCAPED_STRICT_RESERVED_WORD &&
- is_strict(language_mode())) {
- ReportUnexpectedToken(next);
- *ok = false;
- return impl()->NullIdentifier();
- }
if (scanner()->IsLet()) {
classifier()->RecordLetPatternError(
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
@@ -1774,9 +1748,7 @@ ParserBase<Impl>::ParseIdentifierOrStrictReservedWord(
next == Token::ASYNC) {
*is_strict_reserved = false;
*is_await = next == Token::AWAIT;
- } else if (next == Token::ESCAPED_STRICT_RESERVED_WORD ||
- next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
- next == Token::STATIC ||
+ } else if (Token::IsStrictReservedWord(next) ||
(next == Token::YIELD && !IsGeneratorFunction(function_kind))) {
*is_strict_reserved = true;
} else {
@@ -1792,12 +1764,8 @@ template <typename Impl>
typename ParserBase<Impl>::IdentifierT ParserBase<Impl>::ParseIdentifierName(
bool* ok) {
Token::Value next = Next();
- if (next != Token::IDENTIFIER && next != Token::ASYNC &&
- next != Token::ENUM && next != Token::AWAIT && next != Token::LET &&
- next != Token::STATIC && next != Token::YIELD &&
- next != Token::FUTURE_STRICT_RESERVED_WORD &&
- next != Token::ESCAPED_KEYWORD &&
- next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
+ if (!Token::IsAnyIdentifier(next) && next != Token::ESCAPED_KEYWORD &&
+ !Token::IsKeyword(next)) {
ReportUnexpectedToken(next);
*ok = false;
return impl()->NullIdentifier();
@@ -1852,6 +1820,39 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseRegExpLiteral(
}
template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern(
+ bool* ok) {
+ // Pattern ::
+ // Identifier
+ // ArrayLiteral
+ // ObjectLiteral
+
+ int beg_pos = peek_position();
+ Token::Value token = peek();
+ ExpressionT result;
+
+ if (Token::IsAnyIdentifier(token)) {
+ IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
+ result = impl()->ExpressionFromIdentifier(name, beg_pos);
+ } else {
+ classifier()->RecordNonSimpleParameter();
+
+ if (token == Token::LBRACK) {
+ result = ParseArrayLiteral(CHECK_OK);
+ } else if (token == Token::LBRACE) {
+ result = ParseObjectLiteral(CHECK_OK);
+ } else {
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return impl()->NullExpression();
+ }
+ }
+
+ ValidateBindingPattern(CHECK_OK);
+ return result;
+}
+
+template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
bool* is_async, bool* ok) {
// PrimaryExpression ::
@@ -1872,7 +1873,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
// AsyncFunctionLiteral
int beg_pos = peek_position();
- switch (peek()) {
+ Token::Value token = peek();
+ switch (token) {
case Token::THIS: {
BindingPatternUnexpectedToken();
Consume(Token::THIS);
@@ -1884,16 +1886,25 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::FALSE_LITERAL:
case Token::SMI:
case Token::NUMBER:
- case Token::BIGINT:
+ case Token::BIGINT: {
+ // Ensure continuous enum range.
+ DCHECK(Token::IsLiteral(token));
BindingPatternUnexpectedToken();
return impl()->ExpressionFromLiteral(Next(), beg_pos);
+ }
+ case Token::STRING: {
+ DCHECK(Token::IsLiteral(token));
+ BindingPatternUnexpectedToken();
+ Consume(Token::STRING);
+ return impl()->ExpressionFromString(beg_pos);
+ }
case Token::ASYNC:
if (!scanner()->HasLineTerminatorAfterNext() &&
PeekAhead() == Token::FUNCTION) {
BindingPatternUnexpectedToken();
Consume(Token::ASYNC);
- return ParseAsyncFunctionLiteral(CHECK_OK);
+ return ParseAsyncFunctionLiteral(ok);
}
// CoverCallExpressionAndAsyncArrowHead
*is_async = true;
@@ -1903,19 +1914,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::STATIC:
case Token::YIELD:
case Token::AWAIT:
- case Token::ESCAPED_STRICT_RESERVED_WORD:
- case Token::FUTURE_STRICT_RESERVED_WORD: {
+ case Token::FUTURE_STRICT_RESERVED_WORD:
+ case Token::ESCAPED_STRICT_RESERVED_WORD: {
+ // Ensure continuous enum range.
+ DCHECK(IsInRange(token, Token::IDENTIFIER,
+ Token::ESCAPED_STRICT_RESERVED_WORD));
// Using eval or arguments in this context is OK even in strict mode.
IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
return impl()->ExpressionFromIdentifier(name, beg_pos);
}
- case Token::STRING: {
- BindingPatternUnexpectedToken();
- Consume(Token::STRING);
- return impl()->ExpressionFromString(beg_pos);
- }
-
case Token::ASSIGN_DIV:
case Token::DIV:
classifier()->RecordBindingPatternError(
@@ -1931,8 +1939,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::LPAREN: {
// Arrow function formal parameters are either a single identifier or a
// list of BindingPattern productions enclosed in parentheses.
- // Parentheses are not valid on the LHS of a BindingPattern, so we use the
- // is_valid_binding_pattern() check to detect multiple levels of
+ // 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.
bool pattern_error = !classifier()->is_valid_binding_pattern();
classifier()->RecordPatternError(scanner()->peek_location(),
@@ -1955,7 +1963,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
function_state_->set_next_function_is_likely_called();
}
ExpressionT expr = ParseExpressionCoverGrammar(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(Token::RPAREN, ok);
return expr;
}
@@ -2010,10 +2018,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
- bool accept_IN, bool* ok) {
+ bool* ok) {
ExpressionClassifier classifier(this);
- ExpressionT result = ParseExpressionCoverGrammar(accept_IN, CHECK_OK);
- ValidateExpression(CHECK_OK);
+ ExpressionT result = ParseExpressionCoverGrammar(true, CHECK_OK);
+ ValidateExpression(ok);
return result;
}
@@ -2038,13 +2046,12 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
Token::String(Token::ELLIPSIS));
int ellipsis_pos = position();
int pattern_pos = peek_position();
- ExpressionT pattern = ParsePrimaryExpression(CHECK_OK);
+ ExpressionT pattern = ParseBindingPattern(CHECK_OK);
if (peek() == Token::ASSIGN) {
ReportMessage(MessageTemplate::kRestDefaultInitializer);
*ok = false;
return result;
}
- ValidateBindingPattern(CHECK_OK);
right = factory()->NewSpread(pattern, ellipsis_pos, pattern_pos);
} else {
right = ParseAssignmentExpression(accept_IN, CHECK_OK);
@@ -2097,14 +2104,13 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
int pos = peek_position();
ExpressionListT values = impl()->NewExpressionList(4);
int first_spread_index = -1;
- Expect(Token::LBRACK, CHECK_OK);
- while (peek() != Token::RBRACK) {
+ Consume(Token::LBRACK);
+ while (!Check(Token::RBRACK)) {
ExpressionT elem;
if (peek() == Token::COMMA) {
elem = factory()->NewTheHoleLiteral();
- } else if (peek() == Token::ELLIPSIS) {
- int start_pos = peek_position();
- Consume(Token::ELLIPSIS);
+ } else if (Check(Token::ELLIPSIS)) {
+ int start_pos = position();
int expr_pos = peek_position();
ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK);
elem = factory()->NewSpread(argument, start_pos, expr_pos);
@@ -2115,57 +2121,54 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
if (argument->IsAssignment()) {
classifier()->RecordPatternError(
- Scanner::Location(start_pos, scanner()->location().end_pos),
+ Scanner::Location(start_pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
} else {
- CheckDestructuringElement(argument, start_pos,
- scanner()->location().end_pos);
+ CheckDestructuringElement(argument, start_pos, end_position());
}
if (peek() == Token::COMMA) {
classifier()->RecordPatternError(
- Scanner::Location(start_pos, scanner()->location().end_pos),
+ Scanner::Location(start_pos, end_position()),
MessageTemplate::kElementAfterRest);
}
} else {
int beg_pos = peek_position();
elem = ParseAssignmentExpression(true, CHECK_OK);
- CheckDestructuringElement(elem, beg_pos, scanner()->location().end_pos);
+ CheckDestructuringElement(elem, beg_pos, end_position());
}
values->Add(elem, zone_);
if (peek() != Token::RBRACK) {
Expect(Token::COMMA, CHECK_OK);
}
}
- Expect(Token::RBRACK, CHECK_OK);
return factory()->NewArrayLiteral(values, first_spread_index, pos);
}
-template <class Impl>
-bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token,
- PropertyKind* kind) {
+inline bool ParsePropertyKindFromToken(Token::Value token,
+ ParsePropertyKind* kind) {
// This returns true, setting the property kind, iff the given token is one
// which must occur after a property name, indicating that the previous token
// was in fact a name and not a modifier (like the "get" in "get x").
switch (token) {
case Token::COLON:
- *kind = PropertyKind::kValueProperty;
+ *kind = ParsePropertyKind::kValue;
return true;
case Token::COMMA:
case Token::RBRACE:
case Token::ASSIGN:
- *kind = PropertyKind::kShorthandProperty;
+ *kind = ParsePropertyKind::kShorthand;
return true;
case Token::LPAREN:
- *kind = PropertyKind::kMethodProperty;
+ *kind = ParsePropertyKind::kMethod;
return true;
case Token::MUL:
case Token::SEMICOLON:
- *kind = PropertyKind::kClassField;
+ *kind = ParsePropertyKind::kClassField;
return true;
case Token::PRIVATE_NAME:
- *kind = PropertyKind::kClassField;
+ *kind = ParsePropertyKind::kClassField;
return true;
default:
break;
@@ -2173,57 +2176,55 @@ bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token,
return false;
}
-template <class Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
- IdentifierT* name, PropertyKind* kind, bool* is_generator, bool* is_get,
- bool* is_set, bool* is_async, bool* is_computed_name, bool* ok) {
- DCHECK_EQ(*kind, PropertyKind::kNotSet);
- DCHECK(!*is_generator);
- DCHECK(!*is_get);
- DCHECK(!*is_set);
- DCHECK(!*is_async);
- DCHECK(!*is_computed_name);
+inline bool ParseAsAccessor(Token::Value token, Token::Value contextual_token,
+ ParsePropertyKind* kind) {
+ if (ParsePropertyKindFromToken(token, kind)) return false;
- *is_generator = Check(Token::MUL);
- if (*is_generator) {
- *kind = PropertyKind::kMethodProperty;
+ if (contextual_token == Token::GET) {
+ *kind = ParsePropertyKind::kAccessorGetter;
+ } else if (contextual_token == Token::SET) {
+ *kind = ParsePropertyKind::kAccessorSetter;
+ } else {
+ return false;
}
- Token::Value token = peek();
- int pos = peek_position();
+ return true;
+}
- if (!*is_generator && token == Token::ASYNC &&
- !scanner()->HasLineTerminatorAfterNext()) {
- Consume(Token::ASYNC);
- token = peek();
- if (token == Token::MUL && !scanner()->HasLineTerminatorBeforeNext()) {
- Consume(Token::MUL);
- token = peek();
- *is_generator = true;
- } else if (SetPropertyKindFromToken(token, kind)) {
- *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'async'
- impl()->PushLiteralName(*name);
- return factory()->NewStringLiteral(*name, pos);
- }
- *kind = PropertyKind::kMethodProperty;
- *is_async = true;
- pos = peek_position();
- }
+template <class Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
+ IdentifierT* name, ParsePropertyKind* kind, ParseFunctionFlags* flags,
+ bool* is_computed_name, bool* ok) {
+ DCHECK_EQ(ParsePropertyKind::kNotSet, *kind);
+ DCHECK_EQ(*flags, ParseFunctionFlag::kIsNormal);
+ DCHECK(!*is_computed_name);
- if (token == Token::IDENTIFIER && !*is_generator && !*is_async) {
- // This is checking for 'get' and 'set' in particular.
- Consume(Token::IDENTIFIER);
- token = peek();
- if (SetPropertyKindFromToken(token, kind) ||
- !scanner()->IsGetOrSet(is_get, is_set)) {
+ if (Check(Token::ASYNC)) {
+ Token::Value token = peek();
+ if ((token != Token::MUL && ParsePropertyKindFromToken(token, kind)) ||
+ scanner()->HasLineTerminatorBeforeNext()) {
*name = impl()->GetSymbol();
impl()->PushLiteralName(*name);
- return factory()->NewStringLiteral(*name, pos);
+ return factory()->NewStringLiteral(*name, position());
}
- *kind = PropertyKind::kAccessorProperty;
- pos = peek_position();
+ *flags = ParseFunctionFlag::kIsAsync;
+ *kind = ParsePropertyKind::kMethod;
+ }
+
+ if (Check(Token::MUL)) {
+ *flags |= ParseFunctionFlag::kIsGenerator;
+ *kind = ParsePropertyKind::kMethod;
}
+ if (*kind == ParsePropertyKind::kNotSet && Check(Token::IDENTIFIER) &&
+ !ParseAsAccessor(peek(), scanner()->current_contextual_token(), kind)) {
+ *name = impl()->GetSymbol();
+ impl()->PushLiteralName(*name);
+ return factory()->NewStringLiteral(*name, position());
+ }
+
+ int pos = peek_position();
+
// For non computed property names we normalize the name a bit:
//
// "12" -> 12
@@ -2233,41 +2234,50 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
//
// This is important because we use the property name as a key in a hash
// table when we compute constant properties.
- ExpressionT expression = impl()->NullExpression();
- switch (token) {
+ bool is_array_index;
+ uint32_t index;
+ switch (peek()) {
case Token::STRING:
Consume(Token::STRING);
*name = impl()->GetSymbol();
+ is_array_index = impl()->IsArrayIndex(*name, &index);
break;
case Token::SMI:
Consume(Token::SMI);
- *name = impl()->GetNumberAsSymbol();
+ index = scanner()->smi_value();
+ is_array_index = true;
+ // Token::SMI were scanned from their canonical representation.
+ *name = impl()->GetSymbol();
break;
- case Token::NUMBER:
+ case Token::NUMBER: {
Consume(Token::NUMBER);
*name = impl()->GetNumberAsSymbol();
+ is_array_index = impl()->IsArrayIndex(*name, &index);
break;
-
+ }
case Token::LBRACK: {
*name = impl()->NullIdentifier();
*is_computed_name = true;
Consume(Token::LBRACK);
ExpressionClassifier computed_name_classifier(this);
- expression = ParseAssignmentExpression(true, CHECK_OK);
+ ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK);
ValidateExpression(CHECK_OK);
AccumulateFormalParameterContainmentErrors();
Expect(Token::RBRACK, CHECK_OK);
- break;
+ if (*kind == ParsePropertyKind::kNotSet) {
+ ParsePropertyKindFromToken(peek(), kind);
+ }
+ return expression;
}
case Token::ELLIPSIS:
- if (!*is_generator && !*is_async && !*is_get && !*is_set) {
+ if (*kind == ParsePropertyKind::kNotSet) {
*name = impl()->NullIdentifier();
Consume(Token::ELLIPSIS);
- expression = ParseAssignmentExpression(true, CHECK_OK);
- *kind = PropertyKind::kSpreadProperty;
+ ExpressionT expression = ParseAssignmentExpression(true, CHECK_OK);
+ *kind = ParsePropertyKind::kSpread;
if (!impl()->IsIdentifier(expression)) {
classifier()->RecordBindingPatternError(
@@ -2291,23 +2301,16 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
default:
*name = ParseIdentifierName(CHECK_OK);
+ is_array_index = false;
break;
}
- if (*kind == PropertyKind::kNotSet) {
- SetPropertyKindFromToken(peek(), kind);
+ if (*kind == ParsePropertyKind::kNotSet) {
+ ParsePropertyKindFromToken(peek(), kind);
}
-
- if (*is_computed_name) {
- return expression;
- }
-
impl()->PushLiteralName(*name);
-
- uint32_t index;
- return impl()->IsArrayIndex(*name, &index)
- ? factory()->NewNumberLiteral(index, pos)
- : factory()->NewStringLiteral(*name, pos);
+ return is_array_index ? factory()->NewNumberLiteral(index, pos)
+ : factory()->NewStringLiteral(*name, pos);
}
template <typename Impl>
@@ -2317,26 +2320,24 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
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;
- bool is_async = false;
+ ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal;
*is_static = false;
*property_kind = ClassLiteralProperty::METHOD;
- PropertyKind kind = PropertyKind::kNotSet;
+ ParsePropertyKind kind = ParsePropertyKind::kNotSet;
Token::Value name_token = peek();
DCHECK_IMPLIES(name_token == Token::PRIVATE_NAME,
allow_harmony_private_fields());
- int name_token_position = scanner()->peek_location().beg_pos;
+ int property_beg_pos = scanner()->peek_location().beg_pos;
+ int name_token_position = property_beg_pos;
*name = impl()->NullIdentifier();
ExpressionT name_expression;
if (name_token == Token::STATIC) {
Consume(Token::STATIC);
name_token_position = scanner()->peek_location().beg_pos;
if (peek() == Token::LPAREN) {
- kind = PropertyKind::kMethodProperty;
+ kind = ParsePropertyKind::kMethod;
*name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
name_expression = factory()->NewStringLiteral(*name, position());
} else if (peek() == Token::ASSIGN || peek() == Token::SEMICOLON ||
@@ -2351,18 +2352,18 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
return impl()->NullLiteralProperty();
} else {
*is_static = true;
- name_expression = ParsePropertyName(name, &kind, &is_generator, &is_get,
- &is_set, &is_async, is_computed_name,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ name_expression =
+ ParsePropertyName(name, &kind, &function_flags, is_computed_name,
+ CHECK_OK_CUSTOM(NullLiteralProperty));
}
} else if (name_token == Token::PRIVATE_NAME) {
Consume(Token::PRIVATE_NAME);
*name = impl()->GetSymbol();
name_expression = factory()->NewStringLiteral(*name, position());
} else {
- name_expression = ParsePropertyName(name, &kind, &is_generator, &is_get,
- &is_set, &is_async, is_computed_name,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ name_expression =
+ ParsePropertyName(name, &kind, &function_flags, is_computed_name,
+ CHECK_OK_CUSTOM(NullLiteralProperty));
}
if (!class_info->has_name_static_property && *is_static &&
@@ -2371,16 +2372,17 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
}
switch (kind) {
- case PropertyKind::kClassField:
- case PropertyKind::kNotSet: // This case is a name followed by a name or
- // other property. Here we have to assume
- // that's an uninitialized field followed by a
- // linebreak followed by a property, with ASI
- // adding the semicolon. If not, there will be
- // a syntax error after parsing the first name
- // as an uninitialized field.
- case PropertyKind::kShorthandProperty:
- case PropertyKind::kValueProperty:
+ case ParsePropertyKind::kClassField:
+ case ParsePropertyKind::kNotSet: // This case is a name followed by a name
+ // or other property. Here we have to
+ // assume that's an uninitialized field
+ // followed by a linebreak followed by a
+ // property, with ASI adding the
+ // semicolon. If not, there will be a
+ // syntax error after parsing the first
+ // name as an uninitialized field.
+ case ParsePropertyKind::kShorthand:
+ case ParsePropertyKind::kValue:
if (allow_harmony_public_fields() || allow_harmony_private_fields()) {
*property_kind = name_token == Token::PRIVATE_NAME
? ClassLiteralProperty::PRIVATE_FIELD
@@ -2394,8 +2396,9 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
checker->CheckClassFieldName(*is_static,
CHECK_OK_CUSTOM(NullLiteralProperty));
}
- ExpressionT initializer = ParseClassFieldInitializer(
- class_info, *is_static, CHECK_OK_CUSTOM(NullLiteralProperty));
+ ExpressionT initializer =
+ ParseClassFieldInitializer(class_info, property_beg_pos, *is_static,
+ CHECK_OK_CUSTOM(NullLiteralProperty));
ExpectSemicolon(CHECK_OK_CUSTOM(NullLiteralProperty));
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
name_expression, initializer, *property_kind, *is_static,
@@ -2409,9 +2412,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
return impl()->NullLiteralProperty();
}
- case PropertyKind::kMethodProperty: {
- DCHECK(!is_get && !is_set);
-
+ case ParsePropertyKind::kMethod: {
// MethodDefinition
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
@@ -2421,12 +2422,12 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
// '{' FunctionBody '}'
if (!*is_computed_name) {
- checker->CheckClassMethodName(name_token, PropertyKind::kMethodProperty,
- is_generator, is_async, *is_static,
+ checker->CheckClassMethodName(name_token, ParsePropertyKind::kMethod,
+ function_flags, *is_static,
CHECK_OK_CUSTOM(NullLiteralProperty));
}
- FunctionKind kind = MethodKindFor(is_generator, is_async);
+ FunctionKind kind = MethodKindFor(function_flags);
if (!*is_static && impl()->IsConstructor(*name)) {
class_info->has_seen_constructor = true;
@@ -2436,10 +2437,8 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
ExpressionT value = impl()->ParseFunctionLiteral(
*name, scanner()->location(), kSkipFunctionNameCheck, kind,
- FLAG_harmony_function_tostring ? name_token_position
- : kNoSourcePosition,
- FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ name_token_position, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
*property_kind = ClassLiteralProperty::METHOD;
ClassLiteralPropertyT result = factory()->NewClassLiteralProperty(
@@ -2449,13 +2448,15 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
return result;
}
- case PropertyKind::kAccessorProperty: {
- DCHECK((is_get || is_set) && !is_generator && !is_async);
+ case ParsePropertyKind::kAccessorGetter:
+ case ParsePropertyKind::kAccessorSetter: {
+ DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
+ bool is_get = kind == ParsePropertyKind::kAccessorGetter;
if (!*is_computed_name) {
- checker->CheckClassMethodName(
- name_token, PropertyKind::kAccessorProperty, false, false,
- *is_static, CHECK_OK_CUSTOM(NullLiteralProperty));
+ checker->CheckClassMethodName(name_token, kind,
+ ParseFunctionFlag::kIsNormal, *is_static,
+ CHECK_OK_CUSTOM(NullLiteralProperty));
// Make sure the name expression is a string since we need a Name for
// Runtime_DefineAccessorPropertyUnchecked and since we can determine
// this statically we can skip the extra runtime check.
@@ -2468,10 +2469,8 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
FunctionLiteralT value = impl()->ParseFunctionLiteral(
*name, scanner()->location(), kSkipFunctionNameCheck, kind,
- FLAG_harmony_function_tostring ? name_token_position
- : kNoSourcePosition,
- FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ name_token_position, FunctionLiteral::kAccessorOrMethod,
+ language_mode(), nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
*property_kind =
is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER;
@@ -2484,7 +2483,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
impl()->SetFunctionNameFromPropertyName(result, *name, prefix);
return result;
}
- case PropertyKind::kSpreadProperty:
+ case ParsePropertyKind::kSpread:
ReportUnexpectedTokenAt(
Scanner::Location(name_token_position, name_expression->position()),
name_token);
@@ -2496,7 +2495,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info,
+ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info, int beg_pos,
bool is_static, bool* ok) {
DeclarationScope* initializer_scope = is_static
? class_info->static_fields_scope
@@ -2506,7 +2505,7 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info,
initializer_scope =
NewFunctionScope(FunctionKind::kClassFieldsInitializerFunction);
// TODO(gsathya): Make scopes be non contiguous.
- initializer_scope->set_start_position(scanner()->location().end_pos);
+ initializer_scope->set_start_position(beg_pos);
initializer_scope->SetLanguageMode(LanguageMode::kStrict);
}
@@ -2523,7 +2522,7 @@ ParserBase<Impl>::ParseClassFieldInitializer(ClassInfo* class_info,
initializer = factory()->NewUndefinedLiteral(kNoSourcePosition);
}
- initializer_scope->set_end_position(scanner()->location().end_pos);
+ initializer_scope->set_end_position(end_position());
if (is_static) {
class_info->static_fields_scope = initializer_scope;
class_info->has_static_class_fields = true;
@@ -2541,26 +2540,23 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
bool* is_computed_name,
bool* is_rest_property,
bool* ok) {
- bool is_get = false;
- bool is_set = false;
- bool is_generator = false;
- bool is_async = false;
- PropertyKind kind = PropertyKind::kNotSet;
+ ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal;
+ ParsePropertyKind kind = ParsePropertyKind::kNotSet;
IdentifierT name = impl()->NullIdentifier();
Token::Value name_token = peek();
- int next_beg_pos = scanner()->peek_location().beg_pos;
- int next_end_pos = scanner()->peek_location().end_pos;
+ int next_beg_pos = peek_position();
+ int next_end_pos = peek_end_position();
- ExpressionT name_expression = ParsePropertyName(
- &name, &kind, &is_generator, &is_get, &is_set, &is_async,
- is_computed_name, CHECK_OK_CUSTOM(NullLiteralProperty));
+ ExpressionT name_expression =
+ ParsePropertyName(&name, &kind, &function_flags, is_computed_name,
+ CHECK_OK_CUSTOM(NullLiteralProperty));
switch (kind) {
- case PropertyKind::kSpreadProperty:
- DCHECK(!is_get && !is_set && !is_generator && !is_async &&
- !*is_computed_name);
- DCHECK(name_token == Token::ELLIPSIS);
+ case ParsePropertyKind::kSpread:
+ DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
+ DCHECK(!*is_computed_name);
+ DCHECK_EQ(Token::ELLIPSIS, name_token);
*is_computed_name = true;
*is_rest_property = true;
@@ -2569,8 +2565,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
factory()->NewTheHoleLiteral(), name_expression,
ObjectLiteralProperty::SPREAD, true);
- case PropertyKind::kValueProperty: {
- DCHECK(!is_get && !is_set && !is_generator && !is_async);
+ case ParsePropertyKind::kValue: {
+ DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
if (!*is_computed_name) {
checker->CheckDuplicateProto(name_token);
@@ -2579,7 +2575,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
int beg_pos = peek_position();
ExpressionT value =
ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullLiteralProperty));
- CheckDestructuringElement(value, beg_pos, scanner()->location().end_pos);
+ CheckDestructuringElement(value, beg_pos, end_position());
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value, *is_computed_name);
@@ -2587,14 +2583,14 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
return result;
}
- case PropertyKind::kShorthandProperty: {
+ case ParsePropertyKind::kShorthand: {
// PropertyDefinition
// IdentifierReference
// CoverInitializedName
//
// CoverInitializedName
// IdentifierReference Initializer?
- DCHECK(!is_get && !is_set && !is_generator && !is_async);
+ DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
if (!Token::IsIdentifier(name_token, language_mode(),
this->is_generator(),
@@ -2642,7 +2638,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
kNoSourcePosition);
classifier()->RecordExpressionError(
- Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+ Scanner::Location(next_beg_pos, end_position()),
MessageTemplate::kInvalidCoverInitializedName);
impl()->SetFunctionNameFromIdentifierRef(rhs, lhs);
@@ -2656,24 +2652,21 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
return result;
}
- case PropertyKind::kMethodProperty: {
- DCHECK(!is_get && !is_set);
-
+ case ParsePropertyKind::kMethod: {
// MethodDefinition
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
classifier()->RecordPatternError(
- Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+ Scanner::Location(next_beg_pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
- FunctionKind kind = MethodKindFor(is_generator, is_async);
+ FunctionKind kind = MethodKindFor(function_flags);
ExpressionT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
- FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ next_beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
+ nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value, ObjectLiteralProperty::COMPUTED,
@@ -2682,12 +2675,13 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
return result;
}
- case PropertyKind::kAccessorProperty: {
- DCHECK((is_get || is_set) && !(is_set && is_get) && !is_generator &&
- !is_async);
+ case ParsePropertyKind::kAccessorGetter:
+ case ParsePropertyKind::kAccessorSetter: {
+ DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
+ bool is_get = kind == ParsePropertyKind::kAccessorGetter;
classifier()->RecordPatternError(
- Scanner::Location(next_beg_pos, scanner()->location().end_pos),
+ Scanner::Location(next_beg_pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
if (!*is_computed_name) {
@@ -2703,9 +2697,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
FunctionLiteralT value = impl()->ParseFunctionLiteral(
name, scanner()->location(), kSkipFunctionNameCheck, kind,
- FLAG_harmony_function_tostring ? next_beg_pos : kNoSourcePosition,
- FunctionLiteral::kAccessorOrMethod, language_mode(), nullptr,
- CHECK_OK_CUSTOM(NullLiteralProperty));
+ next_beg_pos, FunctionLiteral::kAccessorOrMethod, language_mode(),
+ nullptr, CHECK_OK_CUSTOM(NullLiteralProperty));
ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty(
name_expression, value,
@@ -2719,8 +2712,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
return result;
}
- case PropertyKind::kClassField:
- case PropertyKind::kNotSet:
+ case ParsePropertyKind::kClassField:
+ case ParsePropertyKind::kNotSet:
ReportUnexpectedToken(Next());
*ok = false;
return impl()->NullLiteralProperty();
@@ -2743,10 +2736,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
bool has_rest_property = false;
ObjectLiteralChecker checker(this);
- Expect(Token::LBRACE, CHECK_OK);
+ Consume(Token::LBRACE);
- while (peek() != Token::RBRACE) {
- FuncNameInferrer::State fni_state(fni_);
+ while (!Check(Token::RBRACE)) {
+ FuncNameInferrerState fni_state(&fni_);
bool is_computed_name = false;
bool is_rest_property = false;
@@ -2774,9 +2767,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
Expect(Token::COMMA, CHECK_OK);
}
- if (fni_ != nullptr) fni_->Infer();
+ fni_.Infer();
}
- Expect(Token::RBRACE, CHECK_OK);
// In pattern rewriter, we rewrite rest property to call out to a
// runtime function passing all the other properties as arguments to
@@ -2802,25 +2794,20 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
Scanner::Location spread_arg = Scanner::Location::invalid();
ExpressionListT result = impl()->NewExpressionList(4);
Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
- bool done = (peek() == Token::RPAREN);
- while (!done) {
+ while (peek() != Token::RPAREN) {
int start_pos = peek_position();
bool is_spread = Check(Token::ELLIPSIS);
int expr_pos = peek_position();
ExpressionT argument =
ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList));
- if (!impl()->IsIdentifier(argument) &&
- is_simple_parameter_list != nullptr) {
- *is_simple_parameter_list = false;
- }
+ if (!impl()->IsIdentifier(argument)) *is_simple_parameter_list = false;
+
if (!maybe_arrow) {
ValidateExpression(CHECK_OK_CUSTOM(NullExpressionList));
}
if (is_spread) {
- if (is_simple_parameter_list != nullptr) {
- *is_simple_parameter_list = false;
- }
+ *is_simple_parameter_list = false;
if (!spread_arg.IsValid()) {
spread_arg.beg_pos = start_pos;
spread_arg.end_pos = peek_position();
@@ -2833,24 +2820,22 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
}
result->Add(argument, zone_);
- if (result->length() > Code::kMaxArguments) {
- ReportMessage(MessageTemplate::kTooManyArguments);
- *ok = false;
- return impl()->NullExpressionList();
- }
- done = (peek() != Token::COMMA);
- if (!done) {
- Next();
- if (argument->IsSpread()) {
- classifier()->RecordAsyncArrowFormalParametersError(
- scanner()->location(), MessageTemplate::kParamAfterRest);
- }
- if (peek() == Token::RPAREN) {
- // allow trailing comma
- done = true;
- }
+ if (peek() != Token::COMMA) break;
+
+ Next();
+
+ if (argument->IsSpread()) {
+ classifier()->RecordAsyncArrowFormalParametersError(
+ scanner()->location(), MessageTemplate::kParamAfterRest);
}
}
+
+ if (result->length() > Code::kMaxArguments) {
+ ReportMessage(MessageTemplate::kTooManyArguments);
+ *ok = false;
+ return impl()->NullExpressionList();
+ }
+
Scanner::Location location = scanner_->location();
if (Token::RPAREN != Next()) {
impl()->ReportMessageAt(location, MessageTemplate::kUnterminatedArgList);
@@ -2883,7 +2868,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
return ParseYieldExpression(accept_IN, ok);
}
- FuncNameInferrer::State fni_state(fni_);
+ FuncNameInferrerState fni_state(&fni_);
ExpressionClassifier arrow_formals_classifier(
this, classifier()->duplicate_finder());
@@ -2915,10 +2900,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
IdentifierT name = ParseAndClassifyIdentifier(CHECK_OK);
expression =
impl()->ExpressionFromIdentifier(name, position(), InferName::kNo);
- if (fni_) {
- // Remove `async` keyword from inferred name stack.
- fni_->RemoveAsyncKeywordFromEnd();
- }
+ // Remove `async` keyword from inferred name stack.
+ fni_.RemoveAsyncKeywordFromEnd();
}
if (peek() == Token::ARROW) {
@@ -2931,9 +2914,9 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// in an arrow parameter list, this is correct.
// TODO(adamk): Rename "FormalParameterInitializerError" to refer to
// "YieldExpression", which is its only use.
- ValidateFormalParameterInitializer(ok);
+ ValidateFormalParameterInitializer(CHECK_OK);
- Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
+ Scanner::Location loc(lhs_beg_pos, end_position());
DeclarationScope* scope =
NewFunctionScope(is_async ? FunctionKind::kAsyncArrowFunction
: FunctionKind::kArrowFunction);
@@ -2962,7 +2945,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
MessageTemplate::kUnexpectedToken,
Token::String(Token::ARROW));
- if (fni_ != nullptr) fni_->Infer();
+ fni_.Infer();
return expression;
}
@@ -2997,7 +2980,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
ValidateAssignmentPattern(CHECK_OK);
} else {
expression = CheckAndRewriteReferenceExpression(
- expression, lhs_beg_pos, scanner()->location().end_pos,
+ expression, lhs_beg_pos, end_position(),
MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
}
@@ -3027,15 +3010,13 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
impl()->CheckAssigningFunctionLiteralToProperty(expression, right);
- if (fni_ != nullptr) {
- // Check if the right hand side is a call to avoid inferring a
- // name if we're dealing with "a = function(){...}();"-like
- // expression.
- if (op == Token::ASSIGN && !right->IsCall() && !right->IsCallNew()) {
- fni_->Infer();
- } else {
- fni_->RemoveLastFunction();
- }
+ // Check if the right hand side is a call to avoid inferring a
+ // name if we're dealing with "a = function(){...}();"-like
+ // expression.
+ if (op == Token::ASSIGN && !right->IsCall() && !right->IsCallNew()) {
+ fni_.Infer();
+ } else {
+ fni_.RemoveLastFunction();
}
if (op == Token::ASSIGN) {
@@ -3124,11 +3105,20 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// LogicalOrExpression
// LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
- SourceRange then_range, else_range;
int pos = peek_position();
// We start using the binary expression parser for prec >= 4 only!
ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
- if (peek() != Token::CONDITIONAL) return expression;
+ return peek() == Token::CONDITIONAL
+ ? ParseConditionalContinuation(expression, accept_IN, pos, ok)
+ : expression;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseConditionalContinuation(ExpressionT expression,
+ bool accept_IN, int pos,
+ bool* ok) {
+ SourceRange then_range, else_range;
ValidateExpression(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
@@ -3184,10 +3174,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
right_range_scope.Finalize();
ValidateExpression(CHECK_OK);
- if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) {
- continue;
- }
-
// For now we distinguish between comparisons and other binary
// operations. (We could combine the two and get rid of this
// code and AST node eventually.)
@@ -3204,9 +3190,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
// The comparison was negated - add a NOT.
x = factory()->NewUnaryOperation(Token::NOT, x, pos);
}
- } else if (impl()->CollapseNaryExpression(&x, y, op, pos, right_range)) {
- continue;
- } else {
+ } else if (!impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op,
+ pos) &&
+ !impl()->CollapseNaryExpression(&x, y, op, pos, right_range)) {
// We have a "normal" binary operation.
x = factory()->NewBinaryOperation(op, x, y, pos);
if (op == Token::OR || op == Token::AND) {
@@ -3219,97 +3205,109 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
}
template <typename Impl>
-typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryOpExpression(
bool* ok) {
- // UnaryExpression ::
- // PostfixExpression
- // 'delete' UnaryExpression
- // 'void' UnaryExpression
- // 'typeof' UnaryExpression
- // '++' UnaryExpression
- // '--' UnaryExpression
- // '+' UnaryExpression
- // '-' UnaryExpression
- // '~' UnaryExpression
- // '!' UnaryExpression
- // [+Await] AwaitExpression[?Yield]
-
- Token::Value op = peek();
- if (Token::IsUnaryOp(op)) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
-
- op = Next();
- int pos = position();
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
- // Assume "! function ..." indicates the function is likely to be called.
- if (op == Token::NOT && peek() == Token::FUNCTION) {
- function_state_->set_next_function_is_likely_called();
- }
+ Token::Value op = Next();
+ int pos = position();
- ExpressionT expression = ParseUnaryExpression(CHECK_OK);
- ValidateExpression(CHECK_OK);
+ // Assume "! function ..." indicates the function is likely to be called.
+ if (op == Token::NOT && peek() == Token::FUNCTION) {
+ function_state_->set_next_function_is_likely_called();
+ }
- if (op == Token::DELETE) {
- if (impl()->IsIdentifier(expression) && is_strict(language_mode())) {
- // "delete identifier" is a syntax error in strict mode.
- ReportMessage(MessageTemplate::kStrictDelete);
- *ok = false;
- return impl()->NullExpression();
- }
+ ExpressionT expression = ParseUnaryExpression(CHECK_OK);
+ ValidateExpression(CHECK_OK);
- if (impl()->IsPropertyWithPrivateFieldKey(expression)) {
- ReportMessage(MessageTemplate::kDeletePrivateField);
- *ok = false;
- return impl()->NullExpression();
- }
+ if (op == Token::DELETE) {
+ if (impl()->IsIdentifier(expression) && is_strict(language_mode())) {
+ // "delete identifier" is a syntax error in strict mode.
+ ReportMessage(MessageTemplate::kStrictDelete);
+ *ok = false;
+ return impl()->NullExpression();
}
- if (peek() == Token::EXP) {
- ReportUnexpectedToken(Next());
+ if (impl()->IsPropertyWithPrivateFieldKey(expression)) {
+ ReportMessage(MessageTemplate::kDeletePrivateField);
*ok = false;
return impl()->NullExpression();
}
+ }
- // Allow the parser's implementation to rewrite the expression.
- return impl()->BuildUnaryExpression(expression, op, pos);
- } else if (Token::IsCountOp(op)) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
- op = Next();
- int beg_pos = peek_position();
- ExpressionT expression = ParseUnaryExpression(CHECK_OK);
- expression = CheckAndRewriteReferenceExpression(
- expression, beg_pos, scanner()->location().end_pos,
- MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
- impl()->MarkExpressionAsAssigned(expression);
- ValidateExpression(CHECK_OK);
+ if (peek() == Token::EXP) {
+ ReportUnexpectedToken(Next());
+ *ok = false;
+ return impl()->NullExpression();
+ }
- return factory()->NewCountOperation(op,
- true /* prefix */,
- expression,
- position());
+ // Allow the parser's implementation to rewrite the expression.
+ return impl()->BuildUnaryExpression(expression, op, pos);
+}
- } else if (is_async_function() && peek() == Token::AWAIT) {
- classifier()->RecordFormalParameterInitializerError(
- scanner()->peek_location(),
- MessageTemplate::kAwaitExpressionFormalParameter);
- int await_pos = peek_position();
- Consume(Token::AWAIT);
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrefixExpression(
+ bool* ok) {
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
+ Token::Value op = Next();
+ int beg_pos = peek_position();
+ ExpressionT expression = ParseUnaryExpression(CHECK_OK);
+ expression = CheckAndRewriteReferenceExpression(
+ expression, beg_pos, end_position(),
+ MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
+ impl()->MarkExpressionAsAssigned(expression);
+ ValidateExpression(CHECK_OK);
- ExpressionT value = ParseUnaryExpression(CHECK_OK);
+ return factory()->NewCountOperation(op, true /* prefix */, expression,
+ position());
+}
- classifier()->RecordBindingPatternError(
- Scanner::Location(await_pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidDestructuringTarget);
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAwaitExpression(
+ bool* ok) {
+ classifier()->RecordFormalParameterInitializerError(
+ scanner()->peek_location(),
+ MessageTemplate::kAwaitExpressionFormalParameter);
+ int await_pos = peek_position();
+ Consume(Token::AWAIT);
- ExpressionT expr = factory()->NewAwait(value, await_pos);
- function_state_->AddSuspend();
- impl()->RecordSuspendSourceRange(expr, PositionAfterSemicolon());
- return expr;
- } else {
- return ParsePostfixExpression(ok);
+ ExpressionT value = ParseUnaryExpression(CHECK_OK);
+
+ classifier()->RecordBindingPatternError(
+ Scanner::Location(await_pos, end_position()),
+ MessageTemplate::kInvalidDestructuringTarget);
+
+ ExpressionT expr = factory()->NewAwait(value, await_pos);
+ function_state_->AddSuspend();
+ impl()->RecordSuspendSourceRange(expr, PositionAfterSemicolon());
+ return expr;
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
+ bool* ok) {
+ // UnaryExpression ::
+ // PostfixExpression
+ // 'delete' UnaryExpression
+ // 'void' UnaryExpression
+ // 'typeof' UnaryExpression
+ // '++' UnaryExpression
+ // '--' UnaryExpression
+ // '+' UnaryExpression
+ // '-' UnaryExpression
+ // '~' UnaryExpression
+ // '!' UnaryExpression
+ // [+Await] AwaitExpression[?Yield]
+
+ Token::Value op = peek();
+ if (Token::IsUnaryOp(op)) return ParseUnaryOpExpression(ok);
+ if (Token::IsCountOp(op)) return ParsePrefixExpression(ok);
+ if (is_async_function() && op == Token::AWAIT) {
+ return ParseAwaitExpression(ok);
}
+ return ParsePostfixExpression(ok);
}
template <typename Impl>
@@ -3325,7 +3323,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
ArrowFormalParametersUnexpectedToken();
expression = CheckAndRewriteReferenceExpression(
- expression, lhs_beg_pos, scanner()->location().end_pos,
+ expression, lhs_beg_pos, end_position(),
MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
impl()->MarkExpressionAsAssigned(expression);
ValidateExpression(CHECK_OK);
@@ -3398,9 +3396,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
args = ParseArguments(&spread_pos, true, &is_simple_parameter_list,
CHECK_OK);
if (peek() == Token::ARROW) {
- if (fni_) {
- fni_->RemoveAsyncKeywordFromEnd();
- }
+ fni_.RemoveAsyncKeywordFromEnd();
ValidateBindingPattern(CHECK_OK);
ValidateFormalParameterInitializer(CHECK_OK);
if (!classifier()->is_valid_async_arrow_formal_parameters()) {
@@ -3443,7 +3439,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
result = factory()->NewCall(result, args, pos, is_possibly_eval);
}
- if (fni_ != nullptr) fni_->RemoveLastFunction();
+ fni_.RemoveLastFunction();
break;
}
@@ -3475,8 +3471,8 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
-ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
- bool* ok) {
+ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression(bool* is_async,
+ bool* ok) {
// NewExpression ::
// ('new')+ MemberExpression
//
@@ -3496,49 +3492,52 @@ ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
// new new foo means new (new foo)
// new new foo() means new (new foo())
// new new foo().bar().baz means (new (new foo()).bar()).baz
+ BindingPatternUnexpectedToken();
+ ArrowFormalParametersUnexpectedToken();
+ Consume(Token::NEW);
+ int new_pos = position();
+ ExpressionT result;
+ if (peek() == Token::SUPER) {
+ const bool is_new = true;
+ result = ParseSuperExpression(is_new, CHECK_OK);
+ } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT &&
+ (!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) {
+ impl()->ReportMessageAt(scanner()->peek_location(),
+ MessageTemplate::kImportCallNotNewExpression);
+ *ok = false;
+ return impl()->NullExpression();
+ } else if (peek() == Token::PERIOD) {
+ *is_async = false;
+ result = ParseNewTargetExpression(CHECK_OK);
+ return ParseMemberExpressionContinuation(result, is_async, ok);
+ } else {
+ result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK);
+ }
+ ValidateExpression(CHECK_OK);
+ if (peek() == Token::LPAREN) {
+ // NewExpression with arguments.
+ Scanner::Location spread_pos;
+ ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK);
- if (peek() == Token::NEW) {
- BindingPatternUnexpectedToken();
- ArrowFormalParametersUnexpectedToken();
- Consume(Token::NEW);
- int new_pos = position();
- ExpressionT result;
- if (peek() == Token::SUPER) {
- const bool is_new = true;
- result = ParseSuperExpression(is_new, CHECK_OK);
- } else if (allow_harmony_dynamic_import() && peek() == Token::IMPORT &&
- (!allow_harmony_import_meta() || PeekAhead() == Token::LPAREN)) {
- impl()->ReportMessageAt(scanner()->peek_location(),
- MessageTemplate::kImportCallNotNewExpression);
- *ok = false;
- return impl()->NullExpression();
- } else if (peek() == Token::PERIOD) {
- *is_async = false;
- result = ParseNewTargetExpression(CHECK_OK);
- return ParseMemberExpressionContinuation(result, is_async, CHECK_OK);
+ if (spread_pos.IsValid()) {
+ result = impl()->SpreadCallNew(result, args, new_pos);
} else {
- result = ParseMemberWithNewPrefixesExpression(is_async, CHECK_OK);
+ result = factory()->NewCallNew(result, args, new_pos);
}
- ValidateExpression(CHECK_OK);
- if (peek() == Token::LPAREN) {
- // NewExpression with arguments.
- Scanner::Location spread_pos;
- ExpressionListT args = ParseArguments(&spread_pos, CHECK_OK);
-
- if (spread_pos.IsValid()) {
- result = impl()->SpreadCallNew(result, args, new_pos);
- } else {
- result = factory()->NewCallNew(result, args, new_pos);
- }
- // The expression can still continue with . or [ after the arguments.
- result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK);
- return result;
- }
- // NewExpression without arguments.
- return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos);
+ // The expression can still continue with . or [ after the arguments.
+ return ParseMemberExpressionContinuation(result, is_async, ok);
}
- // No 'new' or 'super' keyword.
- return ParseMemberExpression(is_async, ok);
+ // NewExpression without arguments.
+ return factory()->NewCallNew(result, impl()->NewExpressionList(0), new_pos);
+}
+
+template <typename Impl>
+typename ParserBase<Impl>::ExpressionT
+ParserBase<Impl>::ParseMemberWithNewPrefixesExpression(bool* is_async,
+ bool* ok) {
+ return peek() == Token::NEW
+ ? ParseMemberWithPresentNewPrefixesExpression(is_async, ok)
+ : ParseMemberExpression(is_async, ok);
}
template <typename Impl>
@@ -3604,8 +3603,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberExpression(
result = ParsePrimaryExpression(is_async, CHECK_OK);
}
- result = ParseMemberExpressionContinuation(result, is_async, CHECK_OK);
- return result;
+ return ParseMemberExpressionContinuation(result, is_async, ok);
}
template <typename Impl>
@@ -3678,9 +3676,9 @@ void ParserBase<Impl>::ExpectMetaProperty(Token::Value property_name,
Consume(Token::PERIOD);
ExpectContextualKeyword(property_name, CHECK_OK_CUSTOM(Void));
if (scanner()->literal_contains_escapes()) {
- impl()->ReportMessageAt(
- Scanner::Location(pos, scanner()->location().end_pos),
- MessageTemplate::kInvalidEscapedMetaProperty, full_name);
+ impl()->ReportMessageAt(Scanner::Location(pos, end_position()),
+ MessageTemplate::kInvalidEscapedMetaProperty,
+ full_name);
*ok = false;
}
}
@@ -3692,7 +3690,7 @@ ParserBase<Impl>::ParseNewTargetExpression(bool* ok) {
ExpectMetaProperty(Token::TARGET, "new.target", pos, CHECK_OK);
classifier()->RecordAssignmentPatternError(
- Scanner::Location(pos, scanner()->location().end_pos),
+ Scanner::Location(pos, end_position()),
MessageTemplate::kInvalidDestructuringTarget);
if (!GetReceiverScope()->is_function_scope()) {
@@ -3780,14 +3778,11 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
// BindingElement[?Yield, ?GeneratorParameter]
bool is_rest = parameters->has_rest;
- FuncNameInferrer::State fni_state(fni_);
- ExpressionT pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(Void));
- ValidateBindingPattern(CHECK_OK_CUSTOM(Void));
-
+ FuncNameInferrerState fni_state(&fni_);
+ ExpressionT pattern = ParseBindingPattern(CHECK_OK_CUSTOM(Void));
if (!impl()->IsIdentifier(pattern)) {
parameters->is_simple = false;
ValidateFormalParameterInitializer(CHECK_OK_CUSTOM(Void));
- classifier()->RecordNonSimpleParameter();
}
ExpressionT initializer = impl()->NullExpression();
@@ -3808,8 +3803,8 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters,
impl()->SetFunctionNameFromIdentifierRef(initializer, pattern);
}
- impl()->AddFormalParameter(parameters, pattern, initializer,
- scanner()->location().end_pos, is_rest);
+ impl()->AddFormalParameter(parameters, pattern, initializer, end_position(),
+ is_rest);
}
template <typename Impl>
@@ -3908,23 +3903,21 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
int bindings_start = peek_position();
do {
// Parse binding pattern.
- FuncNameInferrer::State fni_state(fni_);
+ FuncNameInferrerState fni_state(&fni_);
ExpressionT pattern = impl()->NullExpression();
int decl_pos = peek_position();
{
ExpressionClassifier pattern_classifier(this);
- pattern = ParsePrimaryExpression(CHECK_OK_CUSTOM(NullStatement));
+ pattern = ParseBindingPattern(CHECK_OK_CUSTOM(NullStatement));
- ValidateBindingPattern(CHECK_OK_CUSTOM(NullStatement));
if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
ValidateLetPattern(CHECK_OK_CUSTOM(NullStatement));
}
}
-
Scanner::Location variable_loc = scanner()->location();
- bool single_name = impl()->IsIdentifier(pattern);
+ bool single_name = impl()->IsIdentifier(pattern);
if (single_name) {
impl()->PushVariableName(impl()->AsIdentifier(pattern));
}
@@ -3939,32 +3932,32 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
value = ParseAssignmentExpression(var_context != kForStatement,
CHECK_OK_CUSTOM(NullStatement));
ValidateExpression(CHECK_OK_CUSTOM(NullStatement));
- variable_loc.end_pos = scanner()->location().end_pos;
+ variable_loc.end_pos = end_position();
if (!parsing_result->first_initializer_loc.IsValid()) {
parsing_result->first_initializer_loc = variable_loc;
}
// Don't infer if it is "a = function(){...}();"-like expression.
- if (single_name && fni_ != nullptr) {
+ if (single_name) {
if (!value->IsCall() && !value->IsCallNew()) {
- fni_->Infer();
+ fni_.Infer();
} else {
- fni_->RemoveLastFunction();
+ fni_.RemoveLastFunction();
}
}
impl()->SetFunctionNameFromIdentifierRef(value, pattern);
// End position of the initializer is after the assignment expression.
- initializer_position = scanner()->location().end_pos;
+ initializer_position = end_position();
} else {
if (var_context != kForStatement || !PeekInOrOf()) {
// ES6 'const' and binding patterns require initializers.
if (parsing_result->descriptor.mode == VariableMode::kConst ||
!impl()->IsIdentifier(pattern)) {
impl()->ReportMessageAt(
- Scanner::Location(decl_pos, scanner()->location().end_pos),
+ Scanner::Location(decl_pos, end_position()),
MessageTemplate::kDeclarationMissingInitializer,
!impl()->IsIdentifier(pattern) ? "destructuring" : "const");
*ok = false;
@@ -3998,7 +3991,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
} while (Check(Token::COMMA));
parsing_result->bindings_loc =
- Scanner::Location(bindings_start, scanner()->location().end_pos);
+ Scanner::Location(bindings_start, end_position());
DCHECK(*ok);
return init_block;
@@ -4009,7 +4002,7 @@ typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) {
Consume(Token::FUNCTION);
int pos = position();
- ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal;
if (Check(Token::MUL)) {
impl()->ReportMessageAt(
scanner()->location(),
@@ -4026,9 +4019,9 @@ ParserBase<Impl>::ParseHoistableDeclaration(
ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) {
Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
int pos = position();
- ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
+ ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal;
if (Check(Token::MUL)) {
- flags |= ParseFunctionFlags::kIsGenerator;
+ flags |= ParseFunctionFlag::kIsGenerator;
}
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
@@ -4049,13 +4042,12 @@ ParserBase<Impl>::ParseHoistableDeclaration(
//
// 'function' and '*' (if present) have been consumed by the caller.
- bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
- const bool is_async = flags & ParseFunctionFlags::kIsAsync;
- DCHECK(!is_generator || !is_async);
+ DCHECK_IMPLIES((flags & ParseFunctionFlag::kIsAsync) != 0,
+ (flags & ParseFunctionFlag::kIsGenerator) == 0);
- if (is_async && Check(Token::MUL)) {
+ if ((flags & ParseFunctionFlag::kIsAsync) != 0 && Check(Token::MUL)) {
// Async generator
- is_generator = true;
+ flags |= ParseFunctionFlag::kIsGenerator;
}
IdentifierT name;
@@ -4074,10 +4066,10 @@ ParserBase<Impl>::ParseHoistableDeclaration(
variable_name = name;
}
- FuncNameInferrer::State fni_state(fni_);
+ FuncNameInferrerState fni_state(&fni_);
impl()->PushEnclosingName(name);
- FunctionKind kind = FunctionKindFor(is_generator, is_async);
+ FunctionKind kind = FunctionKindFor(flags);
FunctionLiteralT function = impl()->ParseFunctionLiteral(
name, scanner()->location(), name_validity, kind, pos,
@@ -4097,7 +4089,7 @@ ParserBase<Impl>::ParseHoistableDeclaration(
// a flag and UseCounting violations to assess web compatibility.
bool is_sloppy_block_function = is_sloppy(language_mode()) &&
!scope()->is_declaration_scope() &&
- !is_async && !is_generator;
+ flags == ParseFunctionFlag::kIsNormal;
return impl()->DeclareFunction(variable_name, function, mode, pos,
is_sloppy_block_function, names, ok);
@@ -4187,7 +4179,7 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
return impl()->NullStatement();
}
Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
- ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
+ ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync;
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
@@ -4195,7 +4187,8 @@ template <typename Impl>
void ParserBase<Impl>::ParseFunctionBody(
typename ParserBase<Impl>::StatementListT result, IdentifierT function_name,
int pos, const FormalParametersT& parameters, FunctionKind kind,
- FunctionLiteral::FunctionType function_type, bool* ok) {
+ FunctionLiteral::FunctionType function_type, FunctionBodyType body_type,
+ bool accept_IN, bool* ok) {
DeclarationScope* function_scope = scope()->AsDeclarationScope();
DeclarationScope* inner_scope = function_scope;
BlockT inner_block = impl()->NullStatement();
@@ -4209,35 +4202,56 @@ void ParserBase<Impl>::ParseFunctionBody(
body = inner_block->statements();
}
- // If we are parsing the source as if it is wrapped in a function, the source
- // ends without a closing brace.
- Token::Value closing_token =
- function_type == FunctionLiteral::kWrapped ? Token::EOS : Token::RBRACE;
-
{
BlockState block_state(&scope_, inner_scope);
if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
- if (IsAsyncGeneratorFunction(kind)) {
- impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, body, ok);
- } else if (IsGeneratorFunction(kind)) {
- impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body, ok);
- } else if (IsAsyncFunction(kind)) {
- ParseAsyncFunctionBody(inner_scope, body, CHECK_OK_VOID);
+ if (body_type == FunctionBodyType::kExpression) {
+ ExpressionClassifier classifier(this);
+ ExpressionT expression =
+ ParseAssignmentExpression(accept_IN, CHECK_OK_VOID);
+ ValidateExpression(CHECK_OK_VOID);
+
+ if (IsAsyncFunction(kind)) {
+ BlockT block = factory()->NewBlock(1, true);
+ impl()->RewriteAsyncFunctionBody(body, block, expression,
+ CHECK_OK_VOID);
+ } else {
+ body->Add(BuildReturnStatement(expression, expression->position()),
+ zone());
+ }
} else {
- ParseStatementList(body, closing_token, CHECK_OK_VOID);
- }
+ DCHECK(accept_IN);
+ DCHECK_EQ(FunctionBodyType::kBlock, body_type);
+ // If we are parsing the source as if it is wrapped in a function, the
+ // source ends without a closing brace.
+ Token::Value closing_token = function_type == FunctionLiteral::kWrapped
+ ? Token::EOS
+ : Token::RBRACE;
+
+ if (IsAsyncGeneratorFunction(kind)) {
+ impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, body,
+ CHECK_OK_VOID);
+ } else if (IsGeneratorFunction(kind)) {
+ impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body,
+ CHECK_OK_VOID);
+ } else if (IsAsyncFunction(kind)) {
+ ParseAsyncFunctionBody(inner_scope, body, CHECK_OK_VOID);
+ } else {
+ ParseStatementList(body, closing_token, CHECK_OK_VOID);
+ }
- if (IsDerivedConstructor(kind)) {
- body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
- kNoSourcePosition),
- zone());
+ if (IsDerivedConstructor(kind)) {
+ body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
+ kNoSourcePosition),
+ zone());
+ }
+ Expect(closing_token, CHECK_OK_VOID);
}
}
- Expect(closing_token, CHECK_OK_VOID);
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
if (!parameters.is_simple) {
DCHECK_NOT_NULL(inner_scope);
@@ -4256,7 +4270,7 @@ void ParserBase<Impl>::ParseFunctionBody(
init_block = impl()->BuildRejectPromiseOnException(init_block);
}
- inner_scope->set_end_position(scanner()->location().end_pos);
+ inner_scope->set_end_position(end_position());
if (inner_scope->FinalizeBlockScope() != nullptr) {
impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID);
impl()->InsertShadowingVarBindingInitializers(inner_block);
@@ -4315,7 +4329,7 @@ void ParserBase<Impl>::CheckArityRestrictions(int param_count,
template <typename Impl>
bool ParserBase<Impl>::IsNextLetKeyword() {
- DCHECK(peek() == Token::LET);
+ DCHECK_EQ(Token::LET, peek());
Token::Value next_next = PeekAhead();
switch (next_next) {
case Token::LBRACE:
@@ -4340,17 +4354,13 @@ bool ParserBase<Impl>::IsNextLetKeyword() {
template <typename Impl>
bool ParserBase<Impl>::IsTrivialExpression() {
- Token::Value peek_token = peek();
- if (peek_token == Token::SMI || peek_token == Token::NUMBER ||
- peek_token == Token::BIGINT || peek_token == Token::NULL_LITERAL ||
- peek_token == Token::TRUE_LITERAL || peek_token == Token::FALSE_LITERAL ||
- peek_token == Token::STRING || peek_token == Token::IDENTIFIER ||
- peek_token == Token::THIS) {
- // PeekAhead() is expensive & may not always be called, so we only call it
- // after checking peek().
+ if (Token::IsTrivialExpressionToken(peek())) {
+ // PeekAhead() may not always be called, so we only call it after checking
+ // peek().
Token::Value peek_ahead = PeekAhead();
if (peek_ahead == Token::COMMA || peek_ahead == Token::RPAREN ||
- peek_ahead == Token::SEMICOLON || peek_ahead == Token::RBRACK) {
+ peek_ahead == Token::SEMICOLON || peek_ahead == Token::RBRACK ||
+ Token::IsAssignmentOp(peek_ahead)) {
return true;
}
}
@@ -4421,39 +4431,52 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// parameters.
int dummy_num_parameters = -1;
DCHECK_NE(kind & FunctionKind::kArrowFunction, 0);
- LazyParsingResult result = impl()->SkipFunction(
+ FunctionLiteral::EagerCompileHint hint;
+ bool did_preparse_successfully = impl()->SkipFunction(
nullptr, kind, FunctionLiteral::kAnonymousExpression,
formal_parameters.scope, &dummy_num_parameters,
- &produced_preparsed_scope_data, false, false, CHECK_OK);
- DCHECK_NE(result, kLazyParsingAborted);
+ &produced_preparsed_scope_data, false, false, &hint, CHECK_OK);
+
DCHECK_NULL(produced_preparsed_scope_data);
- USE(result);
- formal_parameters.scope->ResetAfterPreparsing(ast_value_factory_,
- false);
- // Discard any queued destructuring assignments which appeared
- // in this function's parameter list, and which were adopted
- // into this function state, above.
- function_state.RewindDestructuringAssignments(0);
+
+ if (did_preparse_successfully) {
+ // Discard any queued destructuring assignments which appeared
+ // in this function's parameter list, and which were adopted
+ // into this function state, above.
+ function_state.RewindDestructuringAssignments(0);
+ } else {
+ // In case we did not sucessfully preparse the function because of an
+ // unidentified error we do a full reparse to return the error.
+ Consume(Token::LBRACE);
+ body = impl()->NewStatementList(8);
+ ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition,
+ formal_parameters, kind,
+ FunctionLiteral::kAnonymousExpression,
+ FunctionBodyType::kBlock, true, ok);
+ CHECK(!*ok);
+ return impl()->NullExpression();
+ }
} else {
Consume(Token::LBRACE);
body = impl()->NewStatementList(8);
ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition,
formal_parameters, kind,
- FunctionLiteral::kAnonymousExpression, CHECK_OK);
+ FunctionLiteral::kAnonymousExpression,
+ FunctionBodyType::kBlock, true, CHECK_OK);
expected_property_count = function_state.expected_property_count();
}
} else {
// Single-expression body
has_braces = false;
- const bool is_async = IsAsyncFunction(kind);
body = impl()->NewStatementList(1);
- impl()->AddParameterInitializationBlock(formal_parameters, body, is_async,
- CHECK_OK);
- ParseSingleExpressionFunctionBody(body, is_async, accept_IN, CHECK_OK);
+ ParseFunctionBody(body, impl()->NullIdentifier(), kNoSourcePosition,
+ formal_parameters, kind,
+ FunctionLiteral::kAnonymousExpression,
+ FunctionBodyType::kExpression, accept_IN, CHECK_OK);
expected_property_count = function_state.expected_property_count();
}
- formal_parameters.scope->set_end_position(scanner()->location().end_pos);
+ formal_parameters.scope->set_end_position(end_position());
// Arrow function formal parameters are parsed as StrictFormalParameterList,
// which is not the same as "parameters of a strict function"; it only means
@@ -4466,7 +4489,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// Validate strict mode.
if (is_strict(language_mode())) {
CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
- scanner()->location().end_pos, CHECK_OK);
+ end_position(), CHECK_OK);
}
impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
@@ -4532,9 +4555,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
class_info.is_anonymous = is_anonymous;
impl()->DeclareClassVariable(name, &class_info, class_token_pos, CHECK_OK);
- scope()->set_start_position(scanner()->location().end_pos);
+ scope()->set_start_position(end_position());
if (Check(Token::EXTENDS)) {
- FuncNameInferrer::State fni_state(fni_);
+ FuncNameInferrerState fni_state(&fni_);
ExpressionClassifier extends_classifier(this);
class_info.extends = ParseLeftHandSideExpression(CHECK_OK);
ValidateExpression(CHECK_OK);
@@ -4548,7 +4571,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
const bool has_extends = !impl()->IsNull(class_info.extends);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
- FuncNameInferrer::State fni_state(fni_);
+ FuncNameInferrerState fni_state(&fni_);
bool is_computed_name = false; // Classes do not care about computed
// property names here.
bool is_static;
@@ -4580,32 +4603,13 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
}
Expect(Token::RBRACE, CHECK_OK);
- int end_pos = scanner()->location().end_pos;
+ int end_pos = end_position();
block_scope->set_end_position(end_pos);
return impl()->RewriteClassLiteral(block_scope, name, &class_info,
class_token_pos, end_pos, ok);
}
template <typename Impl>
-void ParserBase<Impl>::ParseSingleExpressionFunctionBody(StatementListT body,
- bool is_async,
- bool accept_IN,
- bool* ok) {
- if (is_async) impl()->PrepareGeneratorVariables();
-
- ExpressionClassifier classifier(this);
- ExpressionT expression = ParseAssignmentExpression(accept_IN, CHECK_OK_VOID);
- ValidateExpression(CHECK_OK_VOID);
-
- if (is_async) {
- BlockT block = factory()->NewBlock(1, true);
- impl()->RewriteAsyncFunctionBody(body, block, expression, CHECK_OK_VOID);
- } else {
- body->Add(BuildReturnStatement(expression, expression->position()), zone());
- }
-}
-
-template <typename Impl>
void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body,
bool* ok) {
BlockT block = factory()->NewBlock(8, true);
@@ -4614,7 +4618,7 @@ void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body,
impl()->RewriteAsyncFunctionBody(
body, block, factory()->NewUndefinedLiteral(kNoSourcePosition),
CHECK_OK_VOID);
- scope->set_end_position(scanner()->location().end_pos);
+ scope->set_end_position(end_position());
}
template <typename Impl>
@@ -4633,9 +4637,9 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
IdentifierT name = impl()->NullIdentifier();
FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
- bool is_generator = Check(Token::MUL);
- const bool kIsAsync = true;
- const FunctionKind kind = FunctionKindFor(is_generator, kIsAsync);
+ ParseFunctionFlags flags = ParseFunctionFlag::kIsAsync;
+ if (Check(Token::MUL)) flags |= ParseFunctionFlag::kIsGenerator;
+ const FunctionKind kind = FunctionKindFor(flags);
if (impl()->ParsingDynamicFunctionDeclaration()) {
// We don't want dynamic functions to actually declare their name
@@ -4659,7 +4663,7 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
- kind, pos, type, language_mode(), nullptr, CHECK_OK);
+ kind, pos, type, language_mode(), nullptr, ok);
}
template <typename Impl>
@@ -5112,6 +5116,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullStatement));
{
BlockState block_state(zone(), &scope_);
+ // Scope starts before opening brace.
scope()->set_start_position(scanner()->location().beg_pos);
typename Types::Target target(this, body);
@@ -5123,9 +5128,10 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
}
Expect(Token::RBRACE, CHECK_OK_CUSTOM(NullStatement));
- int end_pos = scanner()->location().end_pos;
- scope()->set_end_position(end_pos);
- impl()->RecordBlockSourceRange(body, end_pos);
+ // Scope ends after closing brace.
+ scope()->set_end_position(scanner()->location().end_pos);
+ // Coverage range uses position before closing brace.
+ impl()->RecordBlockSourceRange(body, scanner()->location().beg_pos);
body->set_scope(scope()->FinalizeBlockScope());
}
return body;
@@ -5144,7 +5150,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseScopedStatement(
BlockT block = factory()->NewBlock(1, false);
StatementT body = ParseFunctionDeclaration(CHECK_OK);
block->statements()->Add(body, zone());
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
block->set_scope(scope()->FinalizeBlockScope());
return block;
}
@@ -5172,7 +5178,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseVariableStatement(
DeclarationParsingResult parsing_result;
StatementT result =
ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
+ ExpectSemicolon(ok);
return result;
}
@@ -5234,7 +5240,7 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
}
bool starts_with_identifier = peek_any_identifier();
- ExpressionT expr = ParseExpression(true, CHECK_OK);
+ ExpressionT expr = ParseExpression(CHECK_OK);
if (peek() == Token::COLON && starts_with_identifier &&
impl()->IsIdentifier(expr)) {
// The whole expression was a single identifier, and not, e.g.,
@@ -5273,7 +5279,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
int pos = peek_position();
Expect(Token::IF, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- ExpressionT condition = ParseExpression(true, CHECK_OK);
+ ExpressionT condition = ParseExpression(CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
SourceRange then_range, else_range;
@@ -5285,9 +5291,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
StatementT else_statement = impl()->NullStatement();
if (Check(Token::ELSE)) {
- else_range = SourceRange::ContinuationOf(then_range);
else_statement = ParseScopedStatement(labels, CHECK_OK);
- else_range.end = scanner_->location().end_pos;
+ else_range = SourceRange::ContinuationOf(then_range, end_position());
} else {
else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
@@ -5330,7 +5335,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
}
ExpectSemicolon(CHECK_OK);
StatementT stmt = factory()->NewContinueStatement(target, pos);
- impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos);
+ impl()->RecordJumpStatementSourceRange(stmt, end_position());
return stmt;
}
@@ -5369,7 +5374,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
}
ExpectSemicolon(CHECK_OK);
StatementT stmt = factory()->NewBreakStatement(target, pos);
- impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos);
+ impl()->RecordJumpStatementSourceRange(stmt, end_position());
return stmt;
}
@@ -5404,14 +5409,14 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
return_value = impl()->ThisExpression(loc.beg_pos);
}
} else {
- return_value = ParseExpression(true, CHECK_OK);
+ return_value = ParseExpression(CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
- int continuation_pos = scanner_->location().end_pos;
+ int continuation_pos = end_position();
StatementT stmt =
BuildReturnStatement(return_value, loc.beg_pos, continuation_pos);
- impl()->RecordJumpStatementSourceRange(stmt, scanner_->location().end_pos);
+ impl()->RecordJumpStatementSourceRange(stmt, end_position());
return stmt;
}
@@ -5431,7 +5436,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
}
Expect(Token::LPAREN, CHECK_OK);
- ExpressionT expr = ParseExpression(true, CHECK_OK);
+ ExpressionT expr = ParseExpression(CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Scope* with_scope = NewScope(WITH_SCOPE);
@@ -5440,7 +5445,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, nullptr, CHECK_OK);
- with_scope->set_end_position(scanner()->location().end_pos);
+ with_scope->set_end_position(end_position());
}
return factory()->NewWithStatement(with_scope, expr, body, pos);
}
@@ -5467,7 +5472,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- ExpressionT cond = ParseExpression(true, CHECK_OK);
+ ExpressionT cond = ParseExpression(CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
// Allow do-statements to be terminated with and without
@@ -5497,7 +5502,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWhileStatement(
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- ExpressionT cond = ParseExpression(true, CHECK_OK);
+ ExpressionT cond = ParseExpression(CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
{
SourceRangeScope range_scope(scanner(), &body_range);
@@ -5523,11 +5528,11 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement(
*ok = false;
return impl()->NullStatement();
}
- ExpressionT exception = ParseExpression(true, CHECK_OK);
+ ExpressionT exception = ParseExpression(CHECK_OK);
ExpectSemicolon(CHECK_OK);
StatementT stmt = impl()->NewThrowStatement(exception, pos);
- impl()->RecordThrowSourceRange(stmt, scanner_->location().end_pos);
+ impl()->RecordThrowSourceRange(stmt, end_position());
return stmt;
}
@@ -5545,7 +5550,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
Expect(Token::SWITCH, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
- ExpressionT tag = ParseExpression(true, CHECK_OK);
+ ExpressionT tag = ParseExpression(CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
auto switch_statement =
@@ -5565,7 +5570,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
SourceRange clause_range;
SourceRangeScope range_scope(scanner(), &clause_range);
if (Check(Token::CASE)) {
- label = ParseExpression(true, CHECK_OK);
+ label = ParseExpression(CHECK_OK);
} else {
Expect(Token::DEFAULT, CHECK_OK);
if (default_seen) {
@@ -5588,9 +5593,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
}
Expect(Token::RBRACE, CHECK_OK);
- int end_position = scanner()->location().end_pos;
- scope()->set_end_position(end_position);
- impl()->RecordSwitchStatementSourceRange(switch_statement, end_position);
+ int end_pos = end_position();
+ scope()->set_end_position(end_pos);
+ impl()->RecordSwitchStatementSourceRange(switch_statement, end_pos);
Scope* switch_scope = scope()->FinalizeBlockScope();
if (switch_scope != nullptr) {
return impl()->RewriteSwitchStatement(switch_statement, switch_scope);
@@ -5659,8 +5664,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
} else {
ExpressionClassifier pattern_classifier(this);
- catch_info.pattern = ParsePrimaryExpression(CHECK_OK);
- ValidateBindingPattern(CHECK_OK);
+ catch_info.pattern = ParseBindingPattern(CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
@@ -5672,12 +5676,12 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
catch_info.inner_block = ParseBlock(nullptr, CHECK_OK);
catch_block->statements()->Add(catch_info.inner_block, zone());
impl()->ValidateCatchBlock(catch_info, CHECK_OK);
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
catch_block->set_scope(scope()->FinalizeBlockScope());
}
}
- catch_info.scope->set_end_position(scanner()->location().end_pos);
+ catch_info.scope->set_end_position(end_position());
} else {
catch_block = ParseBlock(nullptr, CHECK_OK);
}
@@ -5777,7 +5781,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this);
ExpressionT expression = ParseExpressionCoverGrammar(false, CHECK_OK);
- int lhs_end_pos = scanner()->location().end_pos;
+ int lhs_end_pos = end_position();
bool is_for_each = CheckInOrOf(&for_info.mode);
bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
@@ -5853,7 +5857,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
enumerable = ParseAssignmentExpression(true, CHECK_OK);
ValidateExpression(CHECK_OK);
} else {
- enumerable = ParseExpression(true, CHECK_OK);
+ enumerable = ParseExpression(CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
@@ -5861,7 +5865,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
Scope* for_scope = nullptr;
if (inner_block_scope != nullptr) {
for_scope = inner_block_scope->outer_scope();
- DCHECK(for_scope == scope());
+ DCHECK_EQ(for_scope, scope());
inner_block_scope->set_start_position(scanner()->location().beg_pos);
}
@@ -5882,7 +5886,7 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
body_block->statements()->Add(body, zone());
if (inner_block_scope != nullptr) {
- inner_block_scope->set_end_position(scanner()->location().end_pos);
+ inner_block_scope->set_end_position(end_position());
body_block->set_scope(inner_block_scope->FinalizeBlockScope());
}
}
@@ -5890,10 +5894,11 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations(
StatementT final_loop = impl()->InitializeForEachStatement(
loop, each_variable, enumerable, body_block);
- init_block = impl()->CreateForEachStatementTDZ(init_block, *for_info, ok);
+ init_block =
+ impl()->CreateForEachStatementTDZ(init_block, *for_info, CHECK_OK);
if (for_scope != nullptr) {
- for_scope->set_end_position(scanner()->location().end_pos);
+ for_scope->set_end_position(end_position());
for_scope = for_scope->FinalizeBlockScope();
}
@@ -5931,7 +5936,7 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
enumerable = ParseAssignmentExpression(true, CHECK_OK);
ValidateExpression(CHECK_OK);
} else {
- enumerable = ParseExpression(true, CHECK_OK);
+ enumerable = ParseExpression(CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
@@ -5965,10 +5970,10 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations(
scope()->set_start_position(scanner()->location().beg_pos);
loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next,
&body, CHECK_OK);
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
}
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
if (for_info->bound_names.length() > 0 &&
function_state_->contains_function_or_eval()) {
scope()->set_is_hidden();
@@ -6014,12 +6019,12 @@ typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
typename Types::Target target(this, loop);
if (peek() != Token::SEMICOLON) {
- *cond = ParseExpression(true, CHECK_OK);
+ *cond = ParseExpression(CHECK_OK);
}
Expect(Token::SEMICOLON, CHECK_OK);
if (peek() != Token::RPAREN) {
- ExpressionT exp = ParseExpression(true, CHECK_OK);
+ ExpressionT exp = ParseExpression(CHECK_OK);
*next = factory()->NewExpressionStatement(exp, exp->position());
}
Expect(Token::RPAREN, CHECK_OK);
@@ -6114,7 +6119,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
BlockState inner_state(&scope_, inner_block_scope);
ExpressionClassifier classifier(this);
ExpressionT lhs = each_variable = ParseLeftHandSideExpression(CHECK_OK);
- int lhs_end_pos = scanner()->location().end_pos;
+ int lhs_end_pos = end_position();
if (lhs->IsArrayLiteral() || lhs->IsObjectLiteral()) {
ValidateAssignmentPattern(CHECK_OK);
@@ -6149,7 +6154,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, nullptr, CHECK_OK);
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
if (has_declarations) {
@@ -6177,10 +6182,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement(
return final_loop;
}
- BlockT init_block =
- impl()->CreateForEachStatementTDZ(impl()->NullStatement(), for_info, ok);
+ BlockT init_block = impl()->CreateForEachStatementTDZ(impl()->NullStatement(),
+ for_info, CHECK_OK);
- scope()->set_end_position(scanner()->location().end_pos);
+ scope()->set_end_position(end_position());
Scope* for_scope = scope()->FinalizeBlockScope();
// Parsed for-in loop w/ variable declarations.
if (!impl()->IsNull(init_block)) {
@@ -6209,10 +6214,9 @@ void ParserBase<Impl>::ObjectLiteralChecker::CheckDuplicateProto(
template <typename Impl>
void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
- Token::Value property, PropertyKind type, bool is_generator, bool is_async,
+ Token::Value property, ParsePropertyKind type, ParseFunctionFlags flags,
bool is_static, bool* ok) {
- DCHECK(type == PropertyKind::kMethodProperty ||
- type == PropertyKind::kAccessorProperty);
+ DCHECK(type == ParsePropertyKind::kMethod || IsAccessor(type));
if (property == Token::SMI || property == Token::NUMBER) return;
@@ -6223,11 +6227,13 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
return;
}
} else if (IsConstructor()) {
- if (is_generator || is_async || type == PropertyKind::kAccessorProperty) {
+ if (flags != ParseFunctionFlag::kIsNormal || IsAccessor(type)) {
MessageTemplate::Template msg =
- is_generator ? MessageTemplate::kConstructorIsGenerator
- : is_async ? MessageTemplate::kConstructorIsAsync
- : MessageTemplate::kConstructorIsAccessor;
+ (flags & ParseFunctionFlag::kIsGenerator) != 0
+ ? MessageTemplate::kConstructorIsGenerator
+ : (flags & ParseFunctionFlag::kIsAsync) != 0
+ ? MessageTemplate::kConstructorIsAsync
+ : MessageTemplate::kConstructorIsAccessor;
this->parser()->ReportMessage(msg);
*ok = false;
return;
diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc
index 41ff551091..6d0d9fff21 100644
--- a/deps/v8/src/parsing/parser.cc
+++ b/deps/v8/src/parsing/parser.cc
@@ -29,56 +29,6 @@
namespace v8 {
namespace internal {
-
-
-// Helper for putting parts of the parse results into a temporary zone when
-// parsing inner function bodies.
-class DiscardableZoneScope {
- public:
- DiscardableZoneScope(Parser* parser, Zone* temp_zone, bool use_temp_zone)
- : fni_(parser->ast_value_factory_, temp_zone),
- parser_(parser),
- prev_fni_(parser->fni_),
- prev_zone_(parser->zone_),
- prev_allow_lazy_(parser->allow_lazy_),
- prev_temp_zoned_(parser->temp_zoned_) {
- if (use_temp_zone) {
- DCHECK(!parser_->temp_zoned_);
- parser_->allow_lazy_ = false;
- parser_->temp_zoned_ = true;
- parser_->fni_ = &fni_;
- parser_->zone_ = temp_zone;
- parser_->factory()->set_zone(temp_zone);
- if (parser_->reusable_preparser_ != nullptr) {
- parser_->reusable_preparser_->zone_ = temp_zone;
- parser_->reusable_preparser_->factory()->set_zone(temp_zone);
- }
- }
- }
- void Reset() {
- parser_->fni_ = prev_fni_;
- parser_->zone_ = prev_zone_;
- parser_->factory()->set_zone(prev_zone_);
- parser_->allow_lazy_ = prev_allow_lazy_;
- parser_->temp_zoned_ = prev_temp_zoned_;
- if (parser_->reusable_preparser_ != nullptr) {
- parser_->reusable_preparser_->zone_ = prev_zone_;
- parser_->reusable_preparser_->factory()->set_zone(prev_zone_);
- }
- }
- ~DiscardableZoneScope() { Reset(); }
-
- private:
- FuncNameInferrer fni_;
- Parser* parser_;
- FuncNameInferrer* prev_fni_;
- Zone* prev_zone_;
- bool prev_allow_lazy_;
- bool prev_temp_zoned_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableZoneScope);
-};
-
FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
bool call_super, int pos,
int end_pos) {
@@ -414,12 +364,12 @@ Parser::Parser(ParseInfo* info)
info->is_module(), true),
scanner_(info->unicode_cache(), info->character_stream(),
info->is_module()),
+ preparser_zone_(info->zone()->allocator(), ZONE_NAME),
reusable_preparser_(nullptr),
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
source_range_map_(info->source_range_map()),
target_stack_(nullptr),
total_preparse_skipped_(0),
- temp_zoned_(false),
consumed_preparsed_scope_data_(info->consumed_preparsed_scope_data()),
parameters_end_pos_(info->parameters_end_pos()) {
// Even though we were passed ParseInfo, we should not store it in
@@ -449,7 +399,6 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_static_fields(FLAG_harmony_static_fields);
set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
- set_allow_harmony_bigint(FLAG_harmony_bigint);
set_allow_harmony_numeric_separator(FLAG_harmony_numeric_separator);
set_allow_harmony_private_fields(FLAG_harmony_private_fields);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
@@ -458,22 +407,27 @@ Parser::Parser(ParseInfo* info)
}
}
-void Parser::DeserializeScopeChain(
- Isolate* isolate, ParseInfo* info,
- MaybeHandle<ScopeInfo> maybe_outer_scope_info) {
+void Parser::InitializeEmptyScopeChain(ParseInfo* info) {
+ DCHECK_NULL(original_scope_);
+ DCHECK_NULL(info->script_scope());
// TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native
// context, which will have the "this" binding for script scopes.
DeclarationScope* script_scope = NewScriptScope();
info->set_script_scope(script_scope);
- Scope* scope = script_scope;
+ original_scope_ = script_scope;
+}
+
+void Parser::DeserializeScopeChain(
+ Isolate* isolate, ParseInfo* info,
+ MaybeHandle<ScopeInfo> maybe_outer_scope_info) {
+ InitializeEmptyScopeChain(info);
Handle<ScopeInfo> outer_scope_info;
if (maybe_outer_scope_info.ToHandle(&outer_scope_info)) {
DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
- scope = Scope::DeserializeScopeChain(
- isolate, zone(), *outer_scope_info, script_scope, ast_value_factory(),
- Scope::DeserializationMode::kScopesOnly);
+ original_scope_ = Scope::DeserializeScopeChain(
+ isolate, zone(), *outer_scope_info, info->script_scope(),
+ ast_value_factory(), Scope::DeserializationMode::kScopesOnly);
}
- original_scope_ = scope;
}
namespace {
@@ -503,7 +457,6 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.ParseProgram");
base::ElapsedTimer timer;
if (V8_UNLIKELY(FLAG_log_function_events)) timer.Start();
- fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
// Initialize parser state.
DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info());
@@ -749,8 +702,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
DCHECK_NULL(target_stack_);
DCHECK(ast_value_factory());
- fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
- fni_->PushEnclosingName(raw_name);
+ fni_.PushEnclosingName(raw_name);
ResetFunctionLiteralId();
DCHECK_LT(0, info->function_literal_id());
@@ -2584,116 +2536,71 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
int function_literal_id = GetNextFunctionLiteralId();
ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr;
- Zone* outer_zone = zone();
- DeclarationScope* scope;
-
- {
- // Temporary zones can nest. When we migrate free variables (see below), we
- // need to recreate them in the previous Zone.
- AstNodeFactory previous_zone_ast_node_factory(ast_value_factory(), zone());
-
- // Open a new zone scope, which sets our AstNodeFactory to allocate in the
- // new temporary zone if the preconditions are satisfied, and ensures that
- // the previous zone is always restored after parsing the body. To be able
- // to do scope analysis correctly after full parsing, we migrate needed
- // information when the function is parsed.
- Zone temp_zone(zone()->allocator(), ZONE_NAME);
- DiscardableZoneScope zone_scope(this, &temp_zone, should_preparse);
-
- // This Scope lives in the main zone. We'll migrate data into that zone
- // later.
- scope = NewFunctionScope(kind, outer_zone);
- SetLanguageMode(scope, language_mode);
+ // This Scope lives in the main zone. We'll migrate data into that zone later.
+ Zone* parse_zone = should_preparse ? &preparser_zone_ : zone();
+ DeclarationScope* scope = NewFunctionScope(kind, parse_zone);
+ SetLanguageMode(scope, language_mode);
#ifdef DEBUG
- scope->SetScopeName(function_name);
- if (should_preparse) scope->set_needs_migration();
+ scope->SetScopeName(function_name);
#endif
- if (!is_wrapped) Expect(Token::LPAREN, CHECK_OK);
- scope->set_start_position(scanner()->location().beg_pos);
-
- // Eager or lazy parse? If is_lazy_top_level_function, we'll parse
- // lazily. We'll call SkipFunction, which may decide to
- // abort lazy parsing if it suspects that wasn't a good idea. If so (in
- // which case the parser is expected to have backtracked), or if we didn't
- // try to lazy parse in the first place, we'll have to parse eagerly.
- if (should_preparse) {
- DCHECK(parse_lazily());
- DCHECK(is_lazy_top_level_function || is_lazy_inner_function);
- DCHECK(!is_wrapped);
- Scanner::BookmarkScope bookmark(scanner());
- bookmark.Set();
- LazyParsingResult result = SkipFunction(
- function_name, kind, function_type, scope, &num_parameters,
- &produced_preparsed_scope_data, is_lazy_inner_function,
- is_lazy_top_level_function, CHECK_OK);
-
- if (result == kLazyParsingAborted) {
- DCHECK(is_lazy_top_level_function);
- bookmark.Apply();
- // This is probably an initialization function. Inform the compiler it
- // should also eager-compile this function.
- eager_compile_hint = FunctionLiteral::kShouldEagerCompile;
- scope->ResetAfterPreparsing(ast_value_factory(), true);
- zone_scope.Reset();
- // Trigger eager (re-)parsing, just below this block.
- should_preparse = false;
- }
- }
-
- if (should_preparse) {
- scope->AnalyzePartially(&previous_zone_ast_node_factory);
- } else {
- body = ParseFunction(
- function_name, pos, kind, function_type, scope, &num_parameters,
- &function_length, &has_duplicate_parameters, &expected_property_count,
- &suspend_count, arguments_for_wrapped_function, CHECK_OK);
- }
-
- DCHECK_EQ(should_preparse, temp_zoned_);
- if (V8_UNLIKELY(FLAG_log_function_events)) {
- double ms = timer.Elapsed().InMillisecondsF();
- const char* event_name = should_preparse
- ? (is_top_level ? "preparse-no-resolution"
- : "preparse-resolution")
- : "full-parse";
- logger_->FunctionEvent(
- event_name, script_id(), ms, scope->start_position(),
- scope->end_position(),
- reinterpret_cast<const char*>(function_name->raw_data()),
- function_name->byte_length());
- }
- if (V8_UNLIKELY(FLAG_runtime_stats)) {
- if (should_preparse) {
- RuntimeCallCounterId counter_id =
- parsing_on_main_thread_
- ? RuntimeCallCounterId::kPreParseWithVariableResolution
- : RuntimeCallCounterId::
- kPreParseBackgroundWithVariableResolution;
- if (is_top_level) {
- counter_id = parsing_on_main_thread_
- ? RuntimeCallCounterId::kPreParseNoVariableResolution
- : RuntimeCallCounterId::
- kPreParseBackgroundNoVariableResolution;
- }
- if (runtime_call_stats_) {
- runtime_call_stats_->CorrectCurrentCounterId(counter_id);
- }
- }
+ if (!is_wrapped) Expect(Token::LPAREN, CHECK_OK);
+ scope->set_start_position(position());
+
+ // Eager or lazy parse? If is_lazy_top_level_function, we'll parse
+ // lazily. We'll call SkipFunction, which may decide to
+ // abort lazy parsing if it suspects that wasn't a good idea. If so (in
+ // which case the parser is expected to have backtracked), or if we didn't
+ // try to lazy parse in the first place, we'll have to parse eagerly.
+ bool did_preparse_successfully =
+ should_preparse &&
+ SkipFunction(function_name, kind, function_type, scope, &num_parameters,
+ &produced_preparsed_scope_data, is_lazy_inner_function,
+ is_lazy_top_level_function, &eager_compile_hint, CHECK_OK);
+ if (!did_preparse_successfully) {
+ body = ParseFunction(
+ function_name, pos, kind, function_type, scope, &num_parameters,
+ &function_length, &has_duplicate_parameters, &expected_property_count,
+ &suspend_count, arguments_for_wrapped_function, CHECK_OK);
+ }
+
+ if (V8_UNLIKELY(FLAG_log_function_events)) {
+ double ms = timer.Elapsed().InMillisecondsF();
+ const char* event_name =
+ should_preparse
+ ? (is_top_level ? "preparse-no-resolution" : "preparse-resolution")
+ : "full-parse";
+ logger_->FunctionEvent(
+ event_name, script_id(), ms, scope->start_position(),
+ scope->end_position(),
+ reinterpret_cast<const char*>(function_name->raw_data()),
+ function_name->byte_length());
+ }
+ if (V8_UNLIKELY(FLAG_runtime_stats) && did_preparse_successfully) {
+ const RuntimeCallCounterId counters[2][2] = {
+ {RuntimeCallCounterId::kPreParseBackgroundNoVariableResolution,
+ RuntimeCallCounterId::kPreParseNoVariableResolution},
+ {RuntimeCallCounterId::kPreParseBackgroundWithVariableResolution,
+ RuntimeCallCounterId::kPreParseWithVariableResolution}};
+ if (runtime_call_stats_) {
+ bool tracked_variables =
+ PreParser::ShouldTrackUnresolvedVariables(is_lazy_top_level_function);
+ runtime_call_stats_->CorrectCurrentCounterId(
+ counters[tracked_variables][parsing_on_main_thread_]);
}
+ }
- // Validate function name. We can do this only after parsing the function,
- // since the function can declare itself strict.
- language_mode = scope->language_mode();
- CheckFunctionName(language_mode, function_name, function_name_validity,
- function_name_location, CHECK_OK);
+ // Validate function name. We can do this only after parsing the function,
+ // since the function can declare itself strict.
+ language_mode = scope->language_mode();
+ CheckFunctionName(language_mode, function_name, function_name_validity,
+ function_name_location, CHECK_OK);
- if (is_strict(language_mode)) {
- CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
- CHECK_OK);
- }
- CheckConflictingVarDeclarations(scope, CHECK_OK);
- } // DiscardableZoneScope goes out of scope.
+ if (is_strict(language_mode)) {
+ CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
+ CHECK_OK);
+ }
+ CheckConflictingVarDeclarations(scope, CHECK_OK);
FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
@@ -2708,19 +2615,20 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_literal->set_suspend_count(suspend_count);
if (should_infer_name) {
- DCHECK_NOT_NULL(fni_);
- fni_->AddFunction(function_literal);
+ fni_.AddFunction(function_literal);
}
return function_literal;
}
-Parser::LazyParsingResult Parser::SkipFunction(
+bool Parser::SkipFunction(
const AstRawString* function_name, FunctionKind kind,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, int* num_parameters,
ProducedPreParsedScopeData** produced_preparsed_scope_data,
- bool is_inner_function, bool may_abort, bool* ok) {
+ bool is_inner_function, bool may_abort,
+ FunctionLiteral::EagerCompileHint* hint, bool* ok) {
FunctionState function_state(&function_state_, &scope_, function_scope);
+ function_scope->set_zone(&preparser_zone_);
DCHECK_NE(kNoSourcePosition, function_scope->start_position());
DCHECK_EQ(kNoSourcePosition, parameters_end_pos_);
@@ -2729,8 +2637,7 @@ Parser::LazyParsingResult Parser::SkipFunction(
scanner()->current_token() == Token::ARROW);
// FIXME(marja): There are 2 ways to skip functions now. Unify them.
- DCHECK_NOT_NULL(consumed_preparsed_scope_data_);
- if (consumed_preparsed_scope_data_->HasData()) {
+ if (consumed_preparsed_scope_data_) {
DCHECK(FLAG_preparser_scope_analysis);
int end_position;
LanguageMode language_mode;
@@ -2752,9 +2659,13 @@ Parser::LazyParsingResult Parser::SkipFunction(
function_scope->RecordSuperPropertyUsage();
}
SkipFunctionLiterals(num_inner_functions);
- return kLazyParsingComplete;
+ function_scope->ResetAfterPreparsing(ast_value_factory_, false);
+ return true;
}
+ Scanner::BookmarkScope bookmark(scanner());
+ bookmark.Set();
+
// With no cached data, we partially parse the function, without building an
// AST. This gathers the data needed to build a lazy function.
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.PreParse");
@@ -2768,28 +2679,41 @@ Parser::LazyParsingResult Parser::SkipFunction(
may_abort, use_counts_, produced_preparsed_scope_data, this->script_id());
// Return immediately if pre-parser decided to abort parsing.
- if (result == PreParser::kPreParseAbort) return kLazyParsingAborted;
+ if (result == PreParser::kPreParseAbort) {
+ bookmark.Apply();
+ function_scope->ResetAfterPreparsing(ast_value_factory(), true);
+ *hint = FunctionLiteral::kShouldEagerCompile;
+ return false;
+ }
+
if (result == PreParser::kPreParseStackOverflow) {
// Propagate stack overflow.
set_stack_overflow();
*ok = false;
- return kLazyParsingComplete;
- }
- if (pending_error_handler()->has_pending_error()) {
+ } else if (pending_error_handler()->ErrorUnidentifiableByPreParser()) {
+ // If we encounter an error that the preparser can not identify we reset to
+ // the state before preparsing. The caller may then fully parse the function
+ // to identify the actual error.
+ bookmark.Apply();
+ function_scope->ResetAfterPreparsing(ast_value_factory(), true);
+ pending_error_handler()->ResetUnidentifiableError();
+ return false;
+ } else if (pending_error_handler()->has_pending_error()) {
*ok = false;
- return kLazyParsingComplete;
- }
+ } else {
+ set_allow_eval_cache(reusable_preparser()->allow_eval_cache());
- set_allow_eval_cache(reusable_preparser()->allow_eval_cache());
+ PreParserLogger* logger = reusable_preparser()->logger();
+ function_scope->set_end_position(logger->end());
+ Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
+ total_preparse_skipped_ +=
+ function_scope->end_position() - function_scope->start_position();
+ *num_parameters = logger->num_parameters();
+ SkipFunctionLiterals(logger->num_inner_functions());
+ function_scope->AnalyzePartially(factory());
+ }
- PreParserLogger* logger = reusable_preparser()->logger();
- function_scope->set_end_position(logger->end());
- Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
- total_preparse_skipped_ +=
- function_scope->end_position() - function_scope->start_position();
- *num_parameters = logger->num_parameters();
- SkipFunctionLiterals(logger->num_inner_functions());
- return kLazyParsingComplete;
+ return true;
}
Statement* Parser::BuildAssertIsCoercible(Variable* var,
@@ -2863,7 +2787,7 @@ Block* Parser::BuildParameterInitializationBlock(
DCHECK(!parameters.is_simple);
DCHECK(scope()->is_function_scope());
DCHECK_EQ(scope(), parameters.scope);
- Block* init_block = factory()->NewBlock(1, true);
+ Block* init_block = factory()->NewBlock(parameters.num_parameters(), true);
int index = 0;
for (auto parameter : parameters.params) {
DeclarationDescriptor descriptor;
@@ -3002,19 +2926,6 @@ Block* Parser::BuildRejectPromiseOnException(Block* inner_block) {
return result;
}
-Expression* Parser::BuildResolvePromise(Expression* value, int pos) {
- // %ResolvePromise(.promise, value), .promise
- ZonePtrList<Expression>* args =
- new (zone()) ZonePtrList<Expression>(2, zone());
- args->Add(factory()->NewVariableProxy(PromiseVariable()), zone());
- args->Add(value, zone());
- Expression* call_runtime =
- factory()->NewCallRuntime(Runtime::kInlineResolvePromise, args, pos);
- return factory()->NewBinaryOperation(
- Token::COMMA, call_runtime,
- factory()->NewVariableProxy(PromiseVariable()), pos);
-}
-
Expression* Parser::BuildRejectPromise(Expression* value, int pos) {
// %promise_internal_reject(.promise, value, false), .promise
// Disables the additional debug event for the rejection since a debug event
@@ -3038,7 +2949,7 @@ Variable* Parser::PromiseVariable() {
Variable* promise = function_state_->scope()->promise_var();
if (promise == nullptr) {
promise = function_state_->scope()->DeclarePromiseVar(
- ast_value_factory()->empty_string());
+ ast_value_factory()->dot_promise_string());
}
return promise;
}
@@ -3128,7 +3039,8 @@ ZonePtrList<Statement>* Parser::ParseFunction(
*function_length = formals.function_length;
ZonePtrList<Statement>* body = new (zone()) ZonePtrList<Statement>(8, zone());
- ParseFunctionBody(body, function_name, pos, formals, kind, function_type, ok);
+ ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
+ FunctionBodyType::kBlock, true, ok);
// Validate parameter names. We can do this only after parsing the function,
// since the function can declare itself strict.
@@ -3238,7 +3150,8 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
}
FunctionLiteral* Parser::CreateInitializerFunction(
- DeclarationScope* scope, ZonePtrList<ClassLiteral::Property>* fields) {
+ const char* name, DeclarationScope* scope,
+ ZonePtrList<ClassLiteral::Property>* fields) {
DCHECK_EQ(scope->function_kind(),
FunctionKind::kClassFieldsInitializerFunction);
// function() { .. class fields initializer .. }
@@ -3247,10 +3160,10 @@ FunctionLiteral* Parser::CreateInitializerFunction(
factory()->NewInitializeClassFieldsStatement(fields, kNoSourcePosition);
statements->Add(static_fields, zone());
return factory()->NewFunctionLiteral(
- ast_value_factory()->empty_string(), scope, statements, 0, 0, 0,
+ ast_value_factory()->GetOneByteString(name), scope, statements, 0, 0, 0,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kAnonymousExpression,
- FunctionLiteral::kShouldEagerCompile, scope->start_position(), true,
+ FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
GetNextFunctionLiteralId());
}
@@ -3285,13 +3198,15 @@ Expression* Parser::RewriteClassLiteral(Scope* block_scope,
FunctionLiteral* static_fields_initializer = nullptr;
if (class_info->has_static_class_fields) {
static_fields_initializer = CreateInitializerFunction(
- class_info->static_fields_scope, class_info->static_fields);
+ "<static_fields_initializer>", class_info->static_fields_scope,
+ class_info->static_fields);
}
FunctionLiteral* instance_fields_initializer_function = nullptr;
if (class_info->has_instance_class_fields) {
instance_fields_initializer_function = CreateInitializerFunction(
- class_info->instance_fields_scope, class_info->instance_fields);
+ "<instance_fields_initializer>", class_info->instance_fields_scope,
+ class_info->instance_fields);
class_info->constructor->set_requires_instance_fields_initializer(true);
}
@@ -3460,7 +3375,6 @@ void Parser::ParseOnBackground(ParseInfo* info) {
// position set at the end of the script (the top scope and possible eval
// scopes) and set their end position after we know the script length.
if (info->is_toplevel()) {
- fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
result = DoParseProgram(/* isolate = */ nullptr, info);
} else {
result =
@@ -3647,10 +3561,9 @@ void Parser::RewriteAsyncFunctionBody(ZonePtrList<Statement>* body,
// })
// }
- return_value = BuildResolvePromise(return_value, return_value->position());
- block->statements()->Add(
- factory()->NewReturnStatement(return_value, return_value->position()),
- zone());
+ block->statements()->Add(factory()->NewAsyncReturnStatement(
+ return_value, return_value->position()),
+ zone());
block = BuildRejectPromiseOnException(block);
body->Add(block, zone());
}
diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h
index 00e73f37a2..35de0656d3 100644
--- a/deps/v8/src/parsing/parser.h
+++ b/deps/v8/src/parsing/parser.h
@@ -11,11 +11,11 @@
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/base/compiler-specific.h"
+#include "src/base/threaded-list.h"
#include "src/globals.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparser.h"
-#include "src/utils.h"
#include "src/zone/zone-chunk-list.h"
namespace v8 {
@@ -31,7 +31,7 @@ class ParserTargetScope;
class PendingCompilationErrorHandler;
class PreParsedScopeData;
-class FunctionEntry BASE_EMBEDDED {
+class FunctionEntry {
public:
enum {
kStartPositionIndex,
@@ -109,7 +109,7 @@ struct ParserFormalParameters : FormalParametersBase {
explicit ParserFormalParameters(DeclarationScope* scope)
: FormalParametersBase(scope) {}
- ThreadedList<Parameter> params;
+ base::ThreadedList<Parameter> params;
};
template <>
@@ -135,12 +135,17 @@ struct ParserTypes<Parser> {
typedef v8::internal::BreakableStatement* BreakableStatement;
typedef v8::internal::ForStatement* ForStatement;
typedef v8::internal::IterationStatement* IterationStatement;
+ typedef v8::internal::FuncNameInferrer FuncNameInferrer;
+ typedef v8::internal::SourceRange SourceRange;
+ typedef v8::internal::SourceRangeScope SourceRangeScope;
// For constructing objects returned by the traversing functions.
typedef AstNodeFactory Factory;
typedef ParserTarget Target;
typedef ParserTargetScope TargetScope;
+
+ static constexpr bool ExpressionClassifierReportErrors = true;
};
class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
@@ -155,6 +160,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void ParseOnBackground(ParseInfo* info);
+ // Initializes an empty scope chain for top-level scripts, or scopes which
+ // consist of only the native context.
+ void InitializeEmptyScopeChain(ParseInfo* info);
+
// Deserialize the scope chain prior to parsing in which the script is going
// to be executed. If the script is a top-level script, or the scope chain
// consists of only a native context, maybe_outer_scope_info should be an
@@ -172,7 +181,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
private:
friend class ParserBase<Parser>;
- friend class v8::internal::ExpressionClassifier<ParserTypes<Parser>>;
+ friend class v8::internal::ExpressionClassifierErrorTracker<
+ ParserTypes<Parser>>;
friend bool v8::internal::parsing::ParseProgram(ParseInfo*, Isolate*);
friend bool v8::internal::parsing::ParseFunction(
ParseInfo*, Handle<SharedFunctionInfo> shared_info, Isolate*);
@@ -185,7 +195,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
bool parse_lazily() const { return mode_ == PARSE_LAZILY; }
enum Mode { PARSE_LAZILY, PARSE_EAGERLY };
- class ParsingModeScope BASE_EMBEDDED {
+ class ParsingModeScope {
public:
ParsingModeScope(Parser* parser, Mode mode)
: parser_(parser), old_mode_(parser->mode_) {
@@ -233,14 +243,12 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ParseInfo* info,
Zone* zone);
- void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate);
-
PreParser* reusable_preparser() {
if (reusable_preparser_ == nullptr) {
- reusable_preparser_ =
- new PreParser(zone(), &scanner_, stack_limit_, ast_value_factory(),
- pending_error_handler(), runtime_call_stats_, logger_,
- -1, parsing_module_, parsing_on_main_thread_);
+ reusable_preparser_ = new PreParser(
+ &preparser_zone_, &scanner_, stack_limit_, ast_value_factory(),
+ pending_error_handler(), runtime_call_stats_, logger_, -1,
+ parsing_module_, parsing_on_main_thread_);
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
SET_ALLOW(natives);
SET_ALLOW(harmony_do_expressions);
@@ -248,7 +256,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SET_ALLOW(harmony_static_fields);
SET_ALLOW(harmony_dynamic_import);
SET_ALLOW(harmony_import_meta);
- SET_ALLOW(harmony_bigint);
SET_ALLOW(harmony_private_fields);
SET_ALLOW(eval_cache);
#undef SET_ALLOW
@@ -315,7 +322,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name,
bool* ok);
FunctionLiteral* CreateInitializerFunction(
- DeclarationScope* scope, ZonePtrList<ClassLiteral::Property>* fields);
+ const char* name, DeclarationScope* scope,
+ ZonePtrList<ClassLiteral::Property>* fields);
V8_INLINE Statement* DeclareClass(const AstRawString* variable_name,
Expression* value,
ZonePtrList<const AstRawString>* names,
@@ -442,12 +450,19 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// by parsing the function with PreParser. Consumes the ending }.
// If may_abort == true, the (pre-)parser may decide to abort skipping
// in order to force the function to be eagerly parsed, after all.
- LazyParsingResult SkipFunction(
- const AstRawString* function_name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* num_parameters,
- ProducedPreParsedScopeData** produced_preparsed_scope_data,
- bool is_inner_function, bool may_abort, bool* ok);
+ // In case the preparser detects an error it cannot identify, it resets the
+ // scanner- and preparser state to the initial one, before PreParsing the
+ // function.
+ // SkipFunction returns true if it correctly parsed the function, including
+ // cases where we detect an error. It returns false, if we needed to stop
+ // parsing or could not identify an error correctly, meaning the caller needs
+ // to fully reparse. In this case it resets the scanner and preparser state.
+ bool SkipFunction(const AstRawString* function_name, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type,
+ DeclarationScope* function_scope, int* num_parameters,
+ ProducedPreParsedScopeData** produced_preparsed_scope_data,
+ bool is_inner_function, bool may_abort,
+ FunctionLiteral::EagerCompileHint* hint, bool* ok);
Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok);
@@ -532,7 +547,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* BuildInitialYield(int pos, FunctionKind kind);
Assignment* BuildCreateJSGeneratorObject(int pos, FunctionKind kind);
- Expression* BuildResolvePromise(Expression* value, int pos);
Expression* BuildRejectPromise(Expression* value, int pos);
Variable* PromiseVariable();
Variable* AsyncGeneratorAwaitVariable();
@@ -662,38 +676,30 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// Functions for encapsulating the differences between parsing and preparsing;
// operations interleaved with the recursive descent.
V8_INLINE void PushLiteralName(const AstRawString* id) {
- DCHECK_NOT_NULL(fni_);
- fni_->PushLiteralName(id);
+ fni_.PushLiteralName(id);
}
V8_INLINE void PushVariableName(const AstRawString* id) {
- DCHECK_NOT_NULL(fni_);
- fni_->PushVariableName(id);
+ fni_.PushVariableName(id);
}
V8_INLINE void PushPropertyName(Expression* expression) {
- DCHECK_NOT_NULL(fni_);
if (expression->IsPropertyName()) {
- fni_->PushLiteralName(expression->AsLiteral()->AsRawPropertyName());
+ fni_.PushLiteralName(expression->AsLiteral()->AsRawPropertyName());
} else {
- fni_->PushLiteralName(ast_value_factory()->anonymous_function_string());
+ fni_.PushLiteralName(ast_value_factory()->anonymous_function_string());
}
}
V8_INLINE void PushEnclosingName(const AstRawString* name) {
- DCHECK_NOT_NULL(fni_);
- fni_->PushEnclosingName(name);
+ fni_.PushEnclosingName(name);
}
V8_INLINE void AddFunctionForNameInference(FunctionLiteral* func_to_infer) {
- DCHECK_NOT_NULL(fni_);
- fni_->AddFunction(func_to_infer);
+ fni_.AddFunction(func_to_infer);
}
- V8_INLINE void InferFunctionName() {
- DCHECK_NOT_NULL(fni_);
- fni_->Infer();
- }
+ V8_INLINE void InferFunctionName() { fni_.Infer(); }
// If we assign a function literal to a property we pretenure the
// literal so it can be added as a constant function property.
@@ -784,6 +790,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
arg, error_type);
}
+ // Dummy implementation. The parser should never have a unidentifiable
+ // error.
+ V8_INLINE void ReportUnidentifiableError() { UNREACHABLE(); }
+
void ReportMessageAt(Scanner::Location source_location,
MessageTemplate::Template message,
const AstRawString* arg,
@@ -856,14 +866,14 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
const AstRawString* name, int start_position,
InferName infer = InferName::kYes) {
if (infer == InferName::kYes) {
- fni_->PushVariableName(name);
+ fni_.PushVariableName(name);
}
return NewUnresolved(name, start_position);
}
V8_INLINE Expression* ExpressionFromString(int pos) {
const AstRawString* symbol = GetSymbol();
- fni_->PushLiteralName(symbol);
+ fni_.PushLiteralName(symbol);
return factory()->NewStringLiteral(symbol, pos);
}
@@ -891,18 +901,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
factory()->NewThrow(exception, pos), pos);
}
- V8_INLINE void AddParameterInitializationBlock(
- const ParserFormalParameters& parameters, ZonePtrList<Statement>* body,
- bool is_async, bool* ok) {
- if (parameters.is_simple) return;
- auto* init_block = BuildParameterInitializationBlock(parameters, ok);
- if (!*ok) return;
- if (is_async) {
- init_block = BuildRejectPromiseOnException(init_block);
- }
- body->Add(init_block, zone());
- }
-
V8_INLINE void AddFormalParameter(ParserFormalParameters* parameters,
Expression* pattern,
Expression* initializer,
@@ -923,7 +921,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
V8_INLINE void DeclareFormalParameters(
DeclarationScope* scope,
- const ThreadedList<ParserFormalParameters::Parameter>& parameters,
+ const base::ThreadedList<ParserFormalParameters::Parameter>& parameters,
bool is_simple, bool* has_duplicate = nullptr) {
if (!is_simple) scope->SetHasNonSimpleParameters();
for (auto parameter : parameters) {
@@ -958,7 +956,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
void SetFunctionNameFromIdentifierRef(Expression* value,
Expression* identifier);
- V8_INLINE ZoneVector<typename ExpressionClassifier::Error>*
+ V8_INLINE ZoneList<typename ExpressionClassifier::Error>*
GetReportedErrorList() const {
return function_state_->GetReportedErrorList();
}
@@ -1094,11 +1092,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
}
// Parser's private field members.
- friend class DiscardableZoneScope; // Uses reusable_preparser_.
- // FIXME(marja): Make reusable_preparser_ always use its own temp Zone (call
- // DeleteAll after each function), so this won't be needed.
+ friend class PreParserZoneScope; // Uses reusable_preparser().
Scanner scanner_;
+ Zone preparser_zone_;
PreParser* reusable_preparser_;
Mode mode_;
@@ -1131,7 +1128,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// 'continue' statement targets). Upon construction, a new target is
// added; it is removed upon destruction.
-class ParserTarget BASE_EMBEDDED {
+class ParserTarget {
public:
ParserTarget(ParserBase<Parser>* parser, BreakableStatement* statement)
: variable_(&parser->impl()->target_stack_),
@@ -1151,7 +1148,7 @@ class ParserTarget BASE_EMBEDDED {
ParserTarget* previous_;
};
-class ParserTargetScope BASE_EMBEDDED {
+class ParserTargetScope {
public:
explicit ParserTargetScope(ParserBase<Parser>* parser)
: variable_(&parser->impl()->target_stack_),
diff --git a/deps/v8/src/parsing/pattern-rewriter.cc b/deps/v8/src/parsing/pattern-rewriter.cc
index ed3231c151..4465670a8f 100644
--- a/deps/v8/src/parsing/pattern-rewriter.cc
+++ b/deps/v8/src/parsing/pattern-rewriter.cc
@@ -31,38 +31,32 @@ class PatternRewriter final : public AstVisitor<PatternRewriter> {
const Parser::DeclarationParsingResult::Declaration* declaration,
ZonePtrList<const AstRawString>* names, bool* ok);
- static void RewriteDestructuringAssignment(Parser* parser,
- RewritableExpression* to_rewrite,
- Scope* scope);
+ static Expression* RewriteDestructuringAssignment(Parser* parser,
+ Assignment* to_rewrite,
+ Scope* scope);
private:
- enum PatternContext { BINDING, ASSIGNMENT, ASSIGNMENT_ELEMENT };
-
- class AssignmentElementScope {
- public:
- explicit AssignmentElementScope(PatternRewriter* rewriter)
- : rewriter_(rewriter), context_(rewriter->context()) {
- if (context_ == ASSIGNMENT) rewriter->context_ = ASSIGNMENT_ELEMENT;
- }
- ~AssignmentElementScope() { rewriter_->context_ = context_; }
-
- private:
- PatternRewriter* const rewriter_;
- const PatternContext context_;
- };
-
- PatternRewriter(Scope* scope, Parser* parser, PatternContext context)
+ enum PatternContext : uint8_t { BINDING, ASSIGNMENT };
+
+ PatternRewriter(Scope* scope, Parser* parser, PatternContext context,
+ const DeclarationDescriptor* descriptor = nullptr,
+ ZonePtrList<const AstRawString>* names = nullptr,
+ int initializer_position = kNoSourcePosition,
+ int value_beg_position = kNoSourcePosition,
+ bool declares_parameter_containing_sloppy_eval = false)
: scope_(scope),
parser_(parser),
- context_(context),
- initializer_position_(kNoSourcePosition),
- value_beg_position_(kNoSourcePosition),
block_(nullptr),
- descriptor_(nullptr),
- names_(nullptr),
+ descriptor_(descriptor),
+ names_(names),
current_value_(nullptr),
- recursion_level_(0),
- ok_(nullptr) {}
+ ok_(nullptr),
+ initializer_position_(initializer_position),
+ value_beg_position_(value_beg_position),
+ context_(context),
+ declares_parameter_containing_sloppy_eval_(
+ declares_parameter_containing_sloppy_eval),
+ recursion_level_(0) {}
#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
// Visiting functions for AST nodes make this an AstVisitor.
@@ -80,16 +74,34 @@ class PatternRewriter final : public AstVisitor<PatternRewriter> {
current_value_ = old_value;
}
+ Expression* Rewrite(Assignment* assign) {
+ DCHECK_EQ(Token::ASSIGN, assign->op());
+
+ int pos = assign->position();
+ DCHECK_NULL(block_);
+ block_ = factory()->NewBlock(8, true);
+ Variable* temp = nullptr;
+ Expression* pattern = assign->target();
+ Expression* old_value = current_value_;
+ current_value_ = assign->value();
+ if (pattern->IsObjectLiteral()) {
+ VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
+ } else {
+ DCHECK(pattern->IsArrayLiteral());
+ VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
+ }
+ DCHECK_NOT_NULL(temp);
+ current_value_ = old_value;
+ return factory()->NewDoExpression(block_, temp, pos);
+ }
+
void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);
bool IsBindingContext() const { return context_ == BINDING; }
- bool IsAssignmentContext() const {
- return context_ == ASSIGNMENT || context_ == ASSIGNMENT_ELEMENT;
- }
+ bool IsAssignmentContext() const { return context_ == ASSIGNMENT; }
bool IsSubPattern() const { return recursion_level_ > 1; }
- bool DeclaresParameterContainingSloppyEval() const;
void RewriteParameterScopes(Expression* expr);
Variable* CreateTempVar(Expression* value = nullptr);
@@ -103,15 +115,16 @@ class PatternRewriter final : public AstVisitor<PatternRewriter> {
Scope* const scope_;
Parser* const parser_;
- PatternContext context_;
- int initializer_position_;
- int value_beg_position_;
Block* block_;
const DeclarationDescriptor* descriptor_;
ZonePtrList<const AstRawString>* names_;
Expression* current_value_;
- int recursion_level_;
bool* ok_;
+ const int initializer_position_;
+ const int value_beg_position_;
+ PatternContext context_;
+ const bool declares_parameter_containing_sloppy_eval_ : 1;
+ int recursion_level_;
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
@@ -125,15 +138,18 @@ void Parser::DeclareAndInitializeVariables(
}
void Parser::RewriteDestructuringAssignment(RewritableExpression* to_rewrite) {
- PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope());
+ DCHECK(!to_rewrite->is_rewritten());
+ Assignment* assignment = to_rewrite->expression()->AsAssignment();
+ Expression* result = PatternRewriter::RewriteDestructuringAssignment(
+ this, assignment, scope());
+ to_rewrite->Rewrite(result);
}
Expression* Parser::RewriteDestructuringAssignment(Assignment* assignment) {
DCHECK_NOT_NULL(assignment);
DCHECK_EQ(Token::ASSIGN, assignment->op());
- auto to_rewrite = factory()->NewRewritableExpression(assignment, scope());
- RewriteDestructuringAssignment(to_rewrite);
- return to_rewrite->expression();
+ return PatternRewriter::RewriteDestructuringAssignment(this, assignment,
+ scope());
}
void PatternRewriter::DeclareAndInitializeVariables(
@@ -143,25 +159,26 @@ void PatternRewriter::DeclareAndInitializeVariables(
ZonePtrList<const AstRawString>* names, bool* ok) {
DCHECK(block->ignore_completion_value());
- PatternRewriter rewriter(declaration_descriptor->scope, parser, BINDING);
- rewriter.initializer_position_ = declaration->initializer_position;
- rewriter.value_beg_position_ = declaration->value_beg_position;
+ Scope* scope = declaration_descriptor->scope;
+ PatternRewriter rewriter(scope, parser, BINDING, declaration_descriptor,
+ names, declaration->initializer_position,
+ declaration->value_beg_position,
+ declaration_descriptor->declaration_kind ==
+ DeclarationDescriptor::PARAMETER &&
+ scope->is_block_scope());
rewriter.block_ = block;
- rewriter.descriptor_ = declaration_descriptor;
- rewriter.names_ = names;
rewriter.ok_ = ok;
rewriter.RecurseIntoSubpattern(declaration->pattern,
declaration->initializer);
}
-void PatternRewriter::RewriteDestructuringAssignment(
- Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
+Expression* PatternRewriter::RewriteDestructuringAssignment(
+ Parser* parser, Assignment* to_rewrite, Scope* scope) {
DCHECK(!scope->HasBeenRemoved());
- DCHECK(!to_rewrite->is_rewritten());
PatternRewriter rewriter(scope, parser, ASSIGNMENT);
- rewriter.RecurseIntoSubpattern(to_rewrite, nullptr);
+ return rewriter.Rewrite(to_rewrite);
}
void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
@@ -181,7 +198,16 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
DCHECK_NOT_NULL(descriptor_);
DCHECK_NOT_NULL(ok_);
- descriptor_->scope->RemoveUnresolved(pattern);
+ Scope* outer_function_scope = nullptr;
+ bool success;
+ if (declares_parameter_containing_sloppy_eval_) {
+ outer_function_scope = scope()->outer_scope();
+ success = outer_function_scope->RemoveUnresolved(pattern);
+ } else {
+ success = scope()->RemoveUnresolved(pattern);
+ }
+ USE(success);
+ DCHECK(success);
// Declare variable.
// Note that we *always* must treat the initial value via a separate init
@@ -192,15 +218,13 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// an initial value in the declaration (because they are initialized upon
// entering the function).
const AstRawString* name = pattern->raw_name();
- VariableProxy* proxy =
- factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
+ VariableProxy* proxy = pattern;
Declaration* declaration;
if (descriptor_->mode == VariableMode::kVar &&
- !descriptor_->scope->is_declaration_scope()) {
- DCHECK(descriptor_->scope->is_block_scope() ||
- descriptor_->scope->is_with_scope());
+ !scope()->is_declaration_scope()) {
+ DCHECK(scope()->is_block_scope() || scope()->is_with_scope());
declaration = factory()->NewNestedVariableDeclaration(
- proxy, descriptor_->scope, descriptor_->declaration_pos);
+ proxy, scope(), descriptor_->declaration_pos);
} else {
declaration =
factory()->NewVariableDeclaration(proxy, descriptor_->declaration_pos);
@@ -210,10 +234,6 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// a sloppy eval in a default parameter or function body, the parameter
// needs to be declared in the function's scope, not in the varblock
// scope which will be used for the initializer expression.
- Scope* outer_function_scope = nullptr;
- if (DeclaresParameterContainingSloppyEval()) {
- outer_function_scope = descriptor_->scope->outer_scope();
- }
Variable* var = parser_->Declare(
declaration, descriptor_->declaration_kind, descriptor_->mode,
Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
@@ -224,12 +244,11 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
DCHECK_NE(initializer_position_, kNoSourcePosition);
var->set_initializer_position(initializer_position_);
- Scope* declaration_scope =
- outer_function_scope != nullptr
- ? outer_function_scope
- : (IsLexicalVariableMode(descriptor_->mode)
- ? descriptor_->scope
- : descriptor_->scope->GetDeclarationScope());
+ Scope* declaration_scope = outer_function_scope != nullptr
+ ? outer_function_scope
+ : (IsLexicalVariableMode(descriptor_->mode)
+ ? scope()
+ : scope()->GetDeclarationScope());
if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
parser_->ReportMessage(MessageTemplate::kTooManyVariables);
*ok_ = false;
@@ -242,7 +261,7 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// If there's no initializer, we're done.
if (value == nullptr) return;
- Scope* var_init_scope = descriptor_->scope;
+ Scope* var_init_scope = scope();
Parser::MarkLoopVariableAsAssigned(var_init_scope, proxy->var(),
descriptor_->declaration_kind);
@@ -254,15 +273,15 @@ void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
//
// var v; v = x;
//
- // In particular, we need to re-lookup 'v' as it may be a different
- // 'v' than the 'v' in the declaration (e.g., if we are inside a
- // 'with' statement or 'catch' block). Global var declarations
- // also need special treatment.
-
- // For 'let' and 'const' declared variables the initialization always
- // assigns to the declared variable.
- // But for var declarations we need to do a new lookup.
- if (descriptor_->mode == VariableMode::kVar) {
+ // In particular, we need to re-lookup 'v' if it may be a different 'v' than
+ // the 'v' in the declaration (e.g., if we are inside a 'with' statement or
+ // 'catch' block).
+
+ // For 'let' and 'const' declared variables the initialization always assigns
+ // to the declared variable. But for var declarations that target a different
+ // scope we need to do a new lookup.
+ if (descriptor_->mode == VariableMode::kVar &&
+ var_init_scope != declaration_scope) {
proxy = var_init_scope->NewUnresolved(factory(), name);
} else {
DCHECK_NOT_NULL(proxy);
@@ -294,64 +313,13 @@ Variable* PatternRewriter::CreateTempVar(Expression* value) {
}
void PatternRewriter::VisitRewritableExpression(RewritableExpression* node) {
- if (!node->expression()->IsAssignment()) {
- // RewritableExpressions are also used for desugaring Spread, which is
- // orthogonal to PatternRewriter; just visit the underlying expression.
- DCHECK_EQ(AstNode::kArrayLiteral, node->expression()->node_type());
- return Visit(node->expression());
- } else if (context() != ASSIGNMENT) {
- // This is not a destructuring assignment. Mark the node as rewritten to
- // prevent redundant rewriting and visit the underlying expression.
- DCHECK(!node->is_rewritten());
- node->set_rewritten();
- return Visit(node->expression());
- }
-
+ DCHECK(node->expression()->IsAssignment());
+ // This is not a top-level destructuring assignment. Mark the node as
+ // rewritten to prevent redundant rewriting and visit the underlying
+ // expression.
DCHECK(!node->is_rewritten());
- DCHECK_EQ(ASSIGNMENT, context());
- Assignment* assign = node->expression()->AsAssignment();
- DCHECK_NOT_NULL(assign);
- DCHECK_EQ(Token::ASSIGN, assign->op());
-
- int pos = assign->position();
- Block* old_block = block_;
- block_ = factory()->NewBlock(8, true);
- Variable* temp = nullptr;
- Expression* pattern = assign->target();
- Expression* old_value = current_value_;
- current_value_ = assign->value();
- if (pattern->IsObjectLiteral()) {
- VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
- } else {
- DCHECK(pattern->IsArrayLiteral());
- VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
- }
- DCHECK_NOT_NULL(temp);
- current_value_ = old_value;
- Expression* expr = factory()->NewDoExpression(block_, temp, pos);
- node->Rewrite(expr);
- block_ = old_block;
- if (block_) {
- block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
- zone());
- }
-}
-
-bool PatternRewriter::DeclaresParameterContainingSloppyEval() const {
- // Need to check for a binding context to make sure we have a descriptor.
- if (IsBindingContext() &&
- // Only relevant for parameters.
- descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
- // And only when scope is a block scope;
- // without eval, it is a function scope.
- scope()->is_block_scope()) {
- DCHECK(scope()->is_declaration_scope());
- DCHECK(scope()->AsDeclarationScope()->calls_sloppy_eval());
- DCHECK(scope()->outer_scope()->is_function_scope());
- return true;
- }
-
- return false;
+ node->set_rewritten();
+ return Visit(node->expression());
}
// When an extra declaration scope needs to be inserted to account for
@@ -359,7 +327,7 @@ bool PatternRewriter::DeclaresParameterContainingSloppyEval() const {
// needs to be in that new inner scope which was added after initial
// parsing.
void PatternRewriter::RewriteParameterScopes(Expression* expr) {
- if (DeclaresParameterContainingSloppyEval()) {
+ if (declares_parameter_containing_sloppy_eval_) {
ReparentExpressionScope(parser_->stack_limit(), expr, scope());
}
}
@@ -428,7 +396,6 @@ void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
kNoSourcePosition);
}
- AssignmentElementScope element_scope(this);
RecurseIntoSubpattern(property->value(), value);
}
}
@@ -557,10 +524,7 @@ void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
factory()->NewExpressionStatement(assignment, nopos), zone());
}
- {
- AssignmentElementScope element_scope(this);
- RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
- }
+ RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
{
// completion = kNormalCompletion;
@@ -709,10 +673,6 @@ void PatternRewriter::VisitAssignment(Assignment* node) {
// <pattern> = temp === undefined ? <init> : temp;
DCHECK_EQ(Token::ASSIGN, node->op());
- // Rewriting of Assignment nodes for destructuring assignment
- // is handled in VisitRewritableExpression().
- DCHECK_NE(ASSIGNMENT, context());
-
auto initializer = node->value();
auto value = initializer;
auto temp = CreateTempVar(current_value_);
diff --git a/deps/v8/src/parsing/preparsed-scope-data-impl.h b/deps/v8/src/parsing/preparsed-scope-data-impl.h
new file mode 100644
index 0000000000..e2d31c07d5
--- /dev/null
+++ b/deps/v8/src/parsing/preparsed-scope-data-impl.h
@@ -0,0 +1,259 @@
+// 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_PREPARSED_SCOPE_DATA_IMPL_H_
+#define V8_PARSING_PREPARSED_SCOPE_DATA_IMPL_H_
+
+#include "src/parsing/preparsed-scope-data.h"
+
+#include "src/assert-scope.h"
+
+namespace v8 {
+namespace internal {
+
+// Classes which are internal to prepared-scope-data.cc, but are exposed in
+// a header for tests.
+
+struct PreParsedScopeByteDataConstants {
+#ifdef DEBUG
+ static constexpr int kMagicValue = 0xC0DE0DE;
+
+ static constexpr size_t kUint32Size = 5;
+ static constexpr size_t kUint8Size = 2;
+ static constexpr size_t kQuarterMarker = 0;
+ static constexpr size_t kPlaceholderSize = kUint32Size;
+#else
+ static constexpr size_t kUint32Size = 4;
+ static constexpr size_t kUint8Size = 1;
+ static constexpr size_t kPlaceholderSize = 0;
+#endif
+
+ static const size_t kSkippableFunctionDataSize =
+ 4 * kUint32Size + 1 * kUint8Size;
+};
+
+class PreParsedScopeDataBuilder::ByteData
+ : public ZoneObject,
+ public PreParsedScopeByteDataConstants {
+ public:
+ explicit ByteData(Zone* zone)
+ : backing_store_(zone), free_quarters_in_last_byte_(0) {}
+
+ void WriteUint32(uint32_t data);
+ void WriteUint8(uint8_t data);
+ void WriteQuarter(uint8_t data);
+
+#ifdef DEBUG
+ // For overwriting previously written data at position 0.
+ void OverwriteFirstUint32(uint32_t data);
+#endif
+
+ Handle<PodArray<uint8_t>> Serialize(Isolate* isolate);
+
+ size_t size() const { return backing_store_.size(); }
+
+ ZoneChunkList<uint8_t>::iterator begin() { return backing_store_.begin(); }
+
+ ZoneChunkList<uint8_t>::iterator end() { return backing_store_.end(); }
+
+ private:
+ ZoneChunkList<uint8_t> backing_store_;
+ uint8_t free_quarters_in_last_byte_;
+};
+
+template <class Data>
+class BaseConsumedPreParsedScopeData : public ConsumedPreParsedScopeData {
+ public:
+ class ByteData : public PreParsedScopeByteDataConstants {
+ public:
+ ByteData()
+ : data_(nullptr), index_(0), stored_quarters_(0), stored_byte_(0) {}
+
+ // Reading from the ByteData is only allowed when a ReadingScope is on the
+ // stack. This ensures that we have a DisallowHeapAllocation in place
+ // whenever ByteData holds a raw pointer into the heap.
+ class ReadingScope {
+ public:
+ ReadingScope(ByteData* consumed_data, Data* data)
+ : consumed_data_(consumed_data) {
+ consumed_data->data_ = data;
+ }
+ explicit ReadingScope(BaseConsumedPreParsedScopeData<Data>* parent)
+ : ReadingScope(parent->scope_data_.get(), parent->GetScopeData()) {}
+ ~ReadingScope() { consumed_data_->data_ = nullptr; }
+
+ private:
+ ByteData* consumed_data_;
+ DisallowHeapAllocation no_gc;
+ };
+
+ void SetPosition(int position) { index_ = position; }
+
+ size_t RemainingBytes() const {
+ DCHECK_NOT_NULL(data_);
+ return data_->length() - index_;
+ }
+
+ int32_t ReadUint32() {
+ DCHECK_NOT_NULL(data_);
+ DCHECK_GE(RemainingBytes(), kUint32Size);
+#ifdef DEBUG
+ // Check that there indeed is an integer following.
+ DCHECK_EQ(data_->get(index_++), kUint32Size);
+#endif
+ int32_t result = 0;
+ byte* p = reinterpret_cast<byte*>(&result);
+ for (int i = 0; i < 4; ++i) {
+ *p++ = data_->get(index_++);
+ }
+ stored_quarters_ = 0;
+ return result;
+ }
+
+ uint8_t ReadUint8() {
+ DCHECK_NOT_NULL(data_);
+ DCHECK_GE(RemainingBytes(), kUint8Size);
+#ifdef DEBUG
+ // Check that there indeed is a byte following.
+ DCHECK_EQ(data_->get(index_++), kUint8Size);
+#endif
+ stored_quarters_ = 0;
+ return data_->get(index_++);
+ }
+
+ uint8_t ReadQuarter() {
+ DCHECK_NOT_NULL(data_);
+ if (stored_quarters_ == 0) {
+ DCHECK_GE(RemainingBytes(), kUint8Size);
+#ifdef DEBUG
+ // Check that there indeed are quarters following.
+ DCHECK_EQ(data_->get(index_++), kQuarterMarker);
+#endif
+ stored_byte_ = data_->get(index_++);
+ stored_quarters_ = 4;
+ }
+ // Read the first 2 bits from stored_byte_.
+ uint8_t result = (stored_byte_ >> 6) & 3;
+ DCHECK_LE(result, 3);
+ --stored_quarters_;
+ stored_byte_ <<= 2;
+ return result;
+ }
+
+ private:
+ Data* data_;
+ int index_;
+ uint8_t stored_quarters_;
+ uint8_t stored_byte_;
+ };
+
+ BaseConsumedPreParsedScopeData()
+ : scope_data_(new ByteData()), child_index_(0) {}
+
+ virtual Data* GetScopeData() = 0;
+
+ virtual ProducedPreParsedScopeData* GetChildData(Zone* zone,
+ int child_index) = 0;
+
+ ProducedPreParsedScopeData* GetDataForSkippableFunction(
+ Zone* zone, int start_position, int* end_position, int* num_parameters,
+ int* num_inner_functions, bool* uses_super_property,
+ LanguageMode* language_mode) final;
+
+ void RestoreScopeAllocationData(DeclarationScope* scope) final;
+
+#ifdef DEBUG
+ void VerifyDataStart();
+#endif
+
+ private:
+ void RestoreData(Scope* scope);
+ void RestoreDataForVariable(Variable* var);
+ void RestoreDataForInnerScopes(Scope* scope);
+
+ std::unique_ptr<ByteData> scope_data_;
+ // When consuming the data, these indexes point to the data we're going to
+ // consume next.
+ int child_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseConsumedPreParsedScopeData);
+};
+
+// Implementation of ConsumedPreParsedScopeData for on-heap data.
+class OnHeapConsumedPreParsedScopeData final
+ : public BaseConsumedPreParsedScopeData<PodArray<uint8_t>> {
+ public:
+ OnHeapConsumedPreParsedScopeData(Isolate* isolate,
+ Handle<PreParsedScopeData> data);
+
+ PodArray<uint8_t>* GetScopeData() final;
+ ProducedPreParsedScopeData* GetChildData(Zone* zone, int child_index) final;
+
+ private:
+ Isolate* isolate_;
+ Handle<PreParsedScopeData> data_;
+};
+
+// Wraps a ZoneVector<uint8_t> to have with functions named the same as
+// PodArray<uint8_t>.
+class ZoneVectorWrapper {
+ public:
+ explicit ZoneVectorWrapper(ZoneVector<uint8_t>* data) : data_(data) {}
+
+ int length() const { return static_cast<int>(data_->size()); }
+
+ uint8_t get(int index) const { return data_->at(index); }
+
+ private:
+ ZoneVector<uint8_t>* data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoneVectorWrapper);
+};
+
+// A serialized PreParsedScopeData in zone memory (as apposed to being on-heap).
+class ZonePreParsedScopeData : public ZoneObject {
+ public:
+ ZonePreParsedScopeData(Zone* zone,
+ ZoneChunkList<uint8_t>::iterator byte_data_begin,
+ ZoneChunkList<uint8_t>::iterator byte_data_end,
+ int child_length);
+
+ Handle<PreParsedScopeData> Serialize(Isolate* isolate);
+
+ int child_length() const { return static_cast<int>(children_.size()); }
+
+ ZonePreParsedScopeData* get_child(int index) { return children_[index]; }
+
+ void set_child(int index, ZonePreParsedScopeData* child) {
+ children_[index] = child;
+ }
+
+ ZoneVector<uint8_t>* byte_data() { return &byte_data_; }
+
+ private:
+ ZoneVector<uint8_t> byte_data_;
+ ZoneVector<ZonePreParsedScopeData*> children_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZonePreParsedScopeData);
+};
+
+// Implementation of ConsumedPreParsedScopeData for PreParsedScopeData
+// serialized into zone memory.
+class ZoneConsumedPreParsedScopeData final
+ : public BaseConsumedPreParsedScopeData<ZoneVectorWrapper> {
+ public:
+ ZoneConsumedPreParsedScopeData(Zone* zone, ZonePreParsedScopeData* data);
+
+ ZoneVectorWrapper* GetScopeData() final;
+ ProducedPreParsedScopeData* GetChildData(Zone* zone, int child_index) final;
+
+ private:
+ ZonePreParsedScopeData* data_;
+ ZoneVectorWrapper scope_data_wrapper_;
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_PARSING_PREPARSED_SCOPE_DATA_IMPL_H_
diff --git a/deps/v8/src/parsing/preparsed-scope-data.cc b/deps/v8/src/parsing/preparsed-scope-data.cc
index 90e8819e32..9d61740753 100644
--- a/deps/v8/src/parsing/preparsed-scope-data.cc
+++ b/deps/v8/src/parsing/preparsed-scope-data.cc
@@ -4,11 +4,14 @@
#include "src/parsing/preparsed-scope-data.h"
+#include <vector>
+
#include "src/ast/scopes.h"
#include "src/ast/variables.h"
#include "src/handles.h"
#include "src/objects-inl.h"
#include "src/objects/shared-function-info.h"
+#include "src/parsing/preparsed-scope-data-impl.h"
#include "src/parsing/preparser.h"
namespace v8 {
@@ -24,22 +27,6 @@ class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {};
class VariableContextAllocatedField
: public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {};
-
-#ifdef DEBUG
-const int kMagicValue = 0xC0DE0DE;
-
-const size_t kUint32Size = 5;
-const size_t kUint8Size = 2;
-const size_t kQuarterMarker = 0;
-const size_t kPlaceholderSize = kUint32Size;
-#else
-const size_t kUint32Size = 4;
-const size_t kUint8Size = 1;
-const size_t kPlaceholderSize = 0;
-#endif
-
-const size_t kSkippableFunctionDataSize = 4 * kUint32Size + 1 * kUint8Size;
-
class LanguageField : public BitField8<LanguageMode, 0, 1> {};
class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {};
STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
@@ -48,7 +35,7 @@ STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
/*
- Internal data format for the backing store of ProducedPreparsedScopeData and
+ Internal data format for the backing store of PreParsedScopeDataBuilder and
PreParsedScopeData::scope_data (on the heap):
(Skippable function data:)
@@ -91,7 +78,7 @@ STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
*/
-void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) {
+void PreParsedScopeDataBuilder::ByteData::WriteUint32(uint32_t data) {
#ifdef DEBUG
// Save expected item size in debug mode.
backing_store_.push_back(kUint32Size);
@@ -104,7 +91,7 @@ void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) {
}
#ifdef DEBUG
-void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) {
+void PreParsedScopeDataBuilder::ByteData::OverwriteFirstUint32(uint32_t data) {
auto it = backing_store_.begin();
// Check that that position already holds an item of the expected size.
DCHECK_GE(backing_store_.size(), kUint32Size);
@@ -117,7 +104,7 @@ void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) {
}
#endif
-void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) {
+void PreParsedScopeDataBuilder::ByteData::WriteUint8(uint8_t data) {
#ifdef DEBUG
// Save expected item size in debug mode.
backing_store_.push_back(kUint8Size);
@@ -126,7 +113,7 @@ void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) {
free_quarters_in_last_byte_ = 0;
}
-void ProducedPreParsedScopeData::ByteData::WriteQuarter(uint8_t data) {
+void PreParsedScopeDataBuilder::ByteData::WriteQuarter(uint8_t data) {
DCHECK_LE(data, 3);
if (free_quarters_in_last_byte_ == 0) {
#ifdef DEBUG
@@ -144,7 +131,7 @@ void ProducedPreParsedScopeData::ByteData::WriteQuarter(uint8_t data) {
backing_store_.back() |= (data << shift_amount);
}
-Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize(
+Handle<PodArray<uint8_t>> PreParsedScopeDataBuilder::ByteData::Serialize(
Isolate* isolate) {
Handle<PodArray<uint8_t>> array = PodArray<uint8_t>::New(
isolate, static_cast<int>(backing_store_.size()), TENURED);
@@ -159,12 +146,13 @@ Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize(
return array;
}
-ProducedPreParsedScopeData::ProducedPreParsedScopeData(
- Zone* zone, ProducedPreParsedScopeData* parent)
+PreParsedScopeDataBuilder::PreParsedScopeDataBuilder(
+ Zone* zone, PreParsedScopeDataBuilder* parent)
: parent_(parent),
byte_data_(new (zone) ByteData(zone)),
data_for_inner_functions_(zone),
bailed_out_(false) {
+ DCHECK(FLAG_preparser_scope_analysis);
if (parent != nullptr) {
parent->data_for_inner_functions_.push_back(this);
}
@@ -174,59 +162,43 @@ ProducedPreParsedScopeData::ProducedPreParsedScopeData(
#endif
}
-// Create a ProducedPreParsedScopeData which is just a proxy for a previous
-// produced PreParsedScopeData.
-ProducedPreParsedScopeData::ProducedPreParsedScopeData(
- Handle<PreParsedScopeData> data, Zone* zone)
- : parent_(nullptr),
- byte_data_(nullptr),
- data_for_inner_functions_(zone),
- bailed_out_(false),
- previously_produced_preparsed_scope_data_(data) {}
-
-ProducedPreParsedScopeData::DataGatheringScope::DataGatheringScope(
+PreParsedScopeDataBuilder::DataGatheringScope::DataGatheringScope(
DeclarationScope* function_scope, PreParser* preparser)
: function_scope_(function_scope),
preparser_(preparser),
- produced_preparsed_scope_data_(nullptr) {
+ builder_(nullptr) {
if (FLAG_preparser_scope_analysis) {
- ProducedPreParsedScopeData* parent =
- preparser->produced_preparsed_scope_data();
+ PreParsedScopeDataBuilder* parent =
+ preparser->preparsed_scope_data_builder();
Zone* main_zone = preparser->main_zone();
- produced_preparsed_scope_data_ =
- new (main_zone) ProducedPreParsedScopeData(main_zone, parent);
- preparser->set_produced_preparsed_scope_data(
- produced_preparsed_scope_data_);
- function_scope->set_produced_preparsed_scope_data(
- produced_preparsed_scope_data_);
+ builder_ = new (main_zone) PreParsedScopeDataBuilder(main_zone, parent);
+ preparser->set_preparsed_scope_data_builder(builder_);
+ function_scope->set_preparsed_scope_data_builder(builder_);
}
}
-ProducedPreParsedScopeData::DataGatheringScope::~DataGatheringScope() {
- if (FLAG_preparser_scope_analysis) {
- preparser_->set_produced_preparsed_scope_data(
- produced_preparsed_scope_data_->parent_);
+PreParsedScopeDataBuilder::DataGatheringScope::~DataGatheringScope() {
+ if (builder_) {
+ preparser_->set_preparsed_scope_data_builder(builder_->parent_);
}
}
-void ProducedPreParsedScopeData::DataGatheringScope::MarkFunctionAsSkippable(
+void PreParsedScopeDataBuilder::DataGatheringScope::MarkFunctionAsSkippable(
int end_position, int num_inner_functions) {
- DCHECK(FLAG_preparser_scope_analysis);
- DCHECK_NOT_NULL(produced_preparsed_scope_data_);
- DCHECK_NOT_NULL(produced_preparsed_scope_data_->parent_);
- produced_preparsed_scope_data_->parent_->AddSkippableFunction(
+ DCHECK_NOT_NULL(builder_);
+ DCHECK_NOT_NULL(builder_->parent_);
+ builder_->parent_->AddSkippableFunction(
function_scope_->start_position(), end_position,
function_scope_->num_parameters(), num_inner_functions,
function_scope_->language_mode(), function_scope_->NeedsHomeObject());
}
-void ProducedPreParsedScopeData::AddSkippableFunction(
- int start_position, int end_position, int num_parameters,
- int num_inner_functions, LanguageMode language_mode,
- bool uses_super_property) {
- DCHECK(FLAG_preparser_scope_analysis);
- DCHECK(previously_produced_preparsed_scope_data_.is_null());
-
+void PreParsedScopeDataBuilder::AddSkippableFunction(int start_position,
+ int end_position,
+ int num_parameters,
+ int num_inner_functions,
+ LanguageMode language_mode,
+ bool uses_super_property) {
if (bailed_out_) {
return;
}
@@ -245,15 +217,14 @@ void ProducedPreParsedScopeData::AddSkippableFunction(
byte_data_->WriteQuarter(language_and_super);
}
-void ProducedPreParsedScopeData::SaveScopeAllocationData(
+void PreParsedScopeDataBuilder::SaveScopeAllocationData(
DeclarationScope* scope) {
- DCHECK(FLAG_preparser_scope_analysis);
- DCHECK(previously_produced_preparsed_scope_data_.is_null());
// The data contains a uint32 (reserved space for scope_data_start) and
// function data items, kSkippableFunctionDataSize each.
- DCHECK_GE(byte_data_->size(), kPlaceholderSize);
+ DCHECK_GE(byte_data_->size(), ByteData::kPlaceholderSize);
DCHECK_LE(byte_data_->size(), std::numeric_limits<uint32_t>::max());
- DCHECK_EQ(byte_data_->size() % kSkippableFunctionDataSize, kPlaceholderSize);
+ DCHECK_EQ(byte_data_->size() % ByteData::kSkippableFunctionDataSize,
+ ByteData::kPlaceholderSize);
if (bailed_out_) {
return;
@@ -262,7 +233,7 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData(
uint32_t scope_data_start = static_cast<uint32_t>(byte_data_->size());
// If there are no skippable inner functions, we don't need to save anything.
- if (scope_data_start == kPlaceholderSize) {
+ if (scope_data_start == ByteData::kPlaceholderSize) {
return;
}
@@ -271,7 +242,7 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData(
// For a data integrity check, write a value between data about skipped inner
// funcs and data about variables.
- byte_data_->WriteUint32(kMagicValue);
+ byte_data_->WriteUint32(ByteData::kMagicValue);
byte_data_->WriteUint32(scope->start_position());
byte_data_->WriteUint32(scope->end_position());
#endif
@@ -279,24 +250,19 @@ void ProducedPreParsedScopeData::SaveScopeAllocationData(
SaveDataForScope(scope);
}
-bool ProducedPreParsedScopeData::ContainsInnerFunctions() const {
- return byte_data_->size() > kPlaceholderSize;
+bool PreParsedScopeDataBuilder::ContainsInnerFunctions() const {
+ return byte_data_->size() > ByteData::kPlaceholderSize;
}
-MaybeHandle<PreParsedScopeData> ProducedPreParsedScopeData::Serialize(
+MaybeHandle<PreParsedScopeData> PreParsedScopeDataBuilder::Serialize(
Isolate* isolate) {
- if (!previously_produced_preparsed_scope_data_.is_null()) {
- DCHECK(!bailed_out_);
- DCHECK_EQ(data_for_inner_functions_.size(), 0);
- return previously_produced_preparsed_scope_data_;
- }
if (bailed_out_) {
return MaybeHandle<PreParsedScopeData>();
}
DCHECK(!ThisOrParentBailedOut());
- if (byte_data_->size() <= kPlaceholderSize) {
+ if (byte_data_->size() <= ByteData::kPlaceholderSize) {
// The data contains only the placeholder.
return MaybeHandle<PreParsedScopeData>();
}
@@ -322,7 +288,33 @@ MaybeHandle<PreParsedScopeData> ProducedPreParsedScopeData::Serialize(
return data;
}
-bool ProducedPreParsedScopeData::ScopeNeedsData(Scope* scope) {
+ZonePreParsedScopeData* PreParsedScopeDataBuilder::Serialize(Zone* zone) {
+ if (bailed_out_) {
+ return nullptr;
+ }
+
+ DCHECK(!ThisOrParentBailedOut());
+
+ if (byte_data_->size() <= ByteData::kPlaceholderSize) {
+ // The data contains only the placeholder.
+ return nullptr;
+ }
+
+ int child_length = static_cast<int>(data_for_inner_functions_.size());
+ ZonePreParsedScopeData* result = new (zone) ZonePreParsedScopeData(
+ zone, byte_data_->begin(), byte_data_->end(), child_length);
+
+ int i = 0;
+ for (const auto& item : data_for_inner_functions_) {
+ ZonePreParsedScopeData* child = item->Serialize(zone);
+ result->set_child(i, child);
+ i++;
+ }
+
+ return result;
+}
+
+bool PreParsedScopeDataBuilder::ScopeNeedsData(Scope* scope) {
if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
// Default constructors don't need data (they cannot contain inner functions
// defined by the user). Other functions do.
@@ -344,9 +336,9 @@ bool ProducedPreParsedScopeData::ScopeNeedsData(Scope* scope) {
return false;
}
-bool ProducedPreParsedScopeData::ScopeIsSkippableFunctionScope(Scope* scope) {
+bool PreParsedScopeDataBuilder::ScopeIsSkippableFunctionScope(Scope* scope) {
// Lazy non-arrow function scopes are skippable. Lazy functions are exactly
- // those Scopes which have their own ProducedPreParsedScopeData object. This
+ // those Scopes which have their own PreParsedScopeDataBuilder object. This
// logic ensures that the scope allocation data is consistent with the
// skippable function data (both agree on where the lazy function boundaries
// are).
@@ -355,10 +347,10 @@ bool ProducedPreParsedScopeData::ScopeIsSkippableFunctionScope(Scope* scope) {
}
DeclarationScope* declaration_scope = scope->AsDeclarationScope();
return !declaration_scope->is_arrow_scope() &&
- declaration_scope->produced_preparsed_scope_data() != nullptr;
+ declaration_scope->preparsed_scope_data_builder() != nullptr;
}
-void ProducedPreParsedScopeData::SaveDataForScope(Scope* scope) {
+void PreParsedScopeDataBuilder::SaveDataForScope(Scope* scope) {
DCHECK_NE(scope->end_position(), kNoSourcePosition);
if (!ScopeNeedsData(scope)) {
@@ -392,7 +384,7 @@ void ProducedPreParsedScopeData::SaveDataForScope(Scope* scope) {
SaveDataForInnerScopes(scope);
}
-void ProducedPreParsedScopeData::SaveDataForVariable(Variable* var) {
+void PreParsedScopeDataBuilder::SaveDataForVariable(Variable* var) {
#ifdef DEBUG
// Store the variable name in debug mode; this way we can check that we
// restore data to the correct variable.
@@ -410,7 +402,7 @@ void ProducedPreParsedScopeData::SaveDataForVariable(Variable* var) {
byte_data_->WriteQuarter(variable_data);
}
-void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) {
+void PreParsedScopeDataBuilder::SaveDataForInnerScopes(Scope* scope) {
// Inner scopes are stored in the reverse order, but we'd like to write the
// data in the logical order. There might be many inner scopes, so we don't
// want to recurse here.
@@ -419,9 +411,9 @@ void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) {
inner = inner->sibling()) {
if (ScopeIsSkippableFunctionScope(inner)) {
// Don't save data about function scopes, since they'll have their own
- // ProducedPreParsedScopeData where their data is saved.
+ // PreParsedScopeDataBuilder where their data is saved.
DCHECK_NOT_NULL(
- inner->AsDeclarationScope()->produced_preparsed_scope_data());
+ inner->AsDeclarationScope()->preparsed_scope_data_builder());
continue;
}
scopes.push_back(inner);
@@ -431,91 +423,83 @@ void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) {
}
}
-ConsumedPreParsedScopeData::ByteData::ReadingScope::ReadingScope(
- ConsumedPreParsedScopeData* parent)
- : ReadingScope(parent->scope_data_.get(), parent->data_->scope_data()) {}
+class BuilderProducedPreParsedScopeData final
+ : public ProducedPreParsedScopeData {
+ public:
+ explicit BuilderProducedPreParsedScopeData(PreParsedScopeDataBuilder* builder)
+ : builder_(builder) {}
-int32_t ConsumedPreParsedScopeData::ByteData::ReadUint32() {
- DCHECK_NOT_NULL(data_);
- DCHECK_GE(RemainingBytes(), kUint32Size);
-#ifdef DEBUG
- // Check that there indeed is an integer following.
- DCHECK_EQ(data_->get(index_++), kUint32Size);
-#endif
- int32_t result = 0;
- byte* p = reinterpret_cast<byte*>(&result);
- for (int i = 0; i < 4; ++i) {
- *p++ = data_->get(index_++);
+ MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) final {
+ return builder_->Serialize(isolate);
}
- stored_quarters_ = 0;
- return result;
-}
-uint8_t ConsumedPreParsedScopeData::ByteData::ReadUint8() {
- DCHECK_NOT_NULL(data_);
- DCHECK_GE(RemainingBytes(), kUint8Size);
-#ifdef DEBUG
- // Check that there indeed is a byte following.
- DCHECK_EQ(data_->get(index_++), kUint8Size);
-#endif
- stored_quarters_ = 0;
- return data_->get(index_++);
-}
+ ZonePreParsedScopeData* Serialize(Zone* zone) final {
+ return builder_->Serialize(zone);
+ };
-uint8_t ConsumedPreParsedScopeData::ByteData::ReadQuarter() {
- DCHECK_NOT_NULL(data_);
- if (stored_quarters_ == 0) {
- DCHECK_GE(RemainingBytes(), kUint8Size);
-#ifdef DEBUG
- // Check that there indeed are quarters following.
- DCHECK_EQ(data_->get(index_++), kQuarterMarker);
-#endif
- stored_byte_ = data_->get(index_++);
- stored_quarters_ = 4;
- }
- // Read the first 2 bits from stored_byte_.
- uint8_t result = (stored_byte_ >> 6) & 3;
- DCHECK_LE(result, 3);
- --stored_quarters_;
- stored_byte_ <<= 2;
- return result;
-}
+ private:
+ PreParsedScopeDataBuilder* builder_;
+};
-size_t ConsumedPreParsedScopeData::ByteData::RemainingBytes() const {
- DCHECK_NOT_NULL(data_);
- return data_->length() - index_;
-}
+class OnHeapProducedPreParsedScopeData final
+ : public ProducedPreParsedScopeData {
+ public:
+ explicit OnHeapProducedPreParsedScopeData(Handle<PreParsedScopeData> data)
+ : data_(data) {}
-ConsumedPreParsedScopeData::ConsumedPreParsedScopeData()
- : isolate_(nullptr), scope_data_(new ByteData()), child_index_(0) {}
+ MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) final {
+ return data_;
+ }
-ConsumedPreParsedScopeData::~ConsumedPreParsedScopeData() {}
+ ZonePreParsedScopeData* Serialize(Zone* zone) final {
+ // Not required.
+ UNREACHABLE();
+ };
-void ConsumedPreParsedScopeData::SetData(Isolate* isolate,
- Handle<PreParsedScopeData> data) {
- DCHECK_NOT_NULL(isolate);
- DCHECK(data->IsPreParsedScopeData());
- isolate_ = isolate;
- data_ = data;
-#ifdef DEBUG
- ByteData::ReadingScope reading_scope(this);
- int scope_data_start = scope_data_->ReadUint32();
- scope_data_->SetPosition(scope_data_start);
- DCHECK_EQ(scope_data_->ReadUint32(), kMagicValue);
- // The first data item is scope_data_start. Skip over it.
- scope_data_->SetPosition(kPlaceholderSize);
-#endif
+ private:
+ Handle<PreParsedScopeData> data_;
+};
+
+class ZoneProducedPreParsedScopeData final : public ProducedPreParsedScopeData {
+ public:
+ explicit ZoneProducedPreParsedScopeData(ZonePreParsedScopeData* data)
+ : data_(data) {}
+
+ MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) final {
+ return data_->Serialize(isolate);
+ }
+
+ ZonePreParsedScopeData* Serialize(Zone* zone) final { return data_; };
+
+ private:
+ ZonePreParsedScopeData* data_;
+};
+
+ProducedPreParsedScopeData* ProducedPreParsedScopeData::For(
+ PreParsedScopeDataBuilder* builder, Zone* zone) {
+ return new (zone) BuilderProducedPreParsedScopeData(builder);
+}
+
+ProducedPreParsedScopeData* ProducedPreParsedScopeData::For(
+ Handle<PreParsedScopeData> data, Zone* zone) {
+ return new (zone) OnHeapProducedPreParsedScopeData(data);
+}
+
+ProducedPreParsedScopeData* ProducedPreParsedScopeData::For(
+ ZonePreParsedScopeData* data, Zone* zone) {
+ return new (zone) ZoneProducedPreParsedScopeData(data);
}
+template <class Data>
ProducedPreParsedScopeData*
-ConsumedPreParsedScopeData::GetDataForSkippableFunction(
+BaseConsumedPreParsedScopeData<Data>::GetDataForSkippableFunction(
Zone* zone, int start_position, int* end_position, int* num_parameters,
int* num_inner_functions, bool* uses_super_property,
LanguageMode* language_mode) {
// The skippable function *must* be the next function in the data. Use the
// start position as a sanity check.
- ByteData::ReadingScope reading_scope(this);
- CHECK_GE(scope_data_->RemainingBytes(), kSkippableFunctionDataSize);
+ typename ByteData::ReadingScope reading_scope(this);
+ CHECK_GE(scope_data_->RemainingBytes(), ByteData::kSkippableFunctionDataSize);
int start_position_from_data = scope_data_->ReadUint32();
CHECK_EQ(start_position, start_position_from_data);
@@ -531,28 +515,19 @@ ConsumedPreParsedScopeData::GetDataForSkippableFunction(
// Retrieve the corresponding PreParsedScopeData and associate it to the
// skipped function. If the skipped functions contains inner functions, those
// can be skipped when the skipped function is eagerly parsed.
- CHECK_GT(data_->length(), child_index_);
- Object* child_data = data_->child_data(child_index_++);
- if (!child_data->IsPreParsedScopeData()) {
- return nullptr;
- }
- Handle<PreParsedScopeData> child_data_handle(
- PreParsedScopeData::cast(child_data), isolate_);
- return new (zone) ProducedPreParsedScopeData(child_data_handle, zone);
+ return GetChildData(zone, child_index_++);
}
-void ConsumedPreParsedScopeData::RestoreScopeAllocationData(
+template <class Data>
+void BaseConsumedPreParsedScopeData<Data>::RestoreScopeAllocationData(
DeclarationScope* scope) {
- DCHECK(FLAG_preparser_scope_analysis);
DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE);
- DCHECK(!data_.is_null());
-
- ByteData::ReadingScope reading_scope(this);
+ typename ByteData::ReadingScope reading_scope(this);
#ifdef DEBUG
int magic_value_from_data = scope_data_->ReadUint32();
// Check that we've consumed all inner function data.
- DCHECK_EQ(magic_value_from_data, kMagicValue);
+ DCHECK_EQ(magic_value_from_data, ByteData::kMagicValue);
int start_position_from_data = scope_data_->ReadUint32();
int end_position_from_data = scope_data_->ReadUint32();
@@ -566,7 +541,8 @@ void ConsumedPreParsedScopeData::RestoreScopeAllocationData(
DCHECK_EQ(scope_data_->RemainingBytes(), 0);
}
-void ConsumedPreParsedScopeData::RestoreData(Scope* scope) {
+template <typename Data>
+void BaseConsumedPreParsedScopeData<Data>::RestoreData(Scope* scope) {
if (scope->is_declaration_scope() &&
scope->AsDeclarationScope()->is_skipped_function()) {
return;
@@ -575,18 +551,12 @@ void ConsumedPreParsedScopeData::RestoreData(Scope* scope) {
// It's possible that scope is not present in the data at all (since PreParser
// doesn't create the corresponding scope). In this case, the Scope won't
// contain any variables for which we need the data.
- if (!ProducedPreParsedScopeData::ScopeNeedsData(scope)) {
+ if (!PreParsedScopeDataBuilder::ScopeNeedsData(scope)) {
return;
}
- if (scope_data_->RemainingBytes() < kUint8Size) {
- // Temporary debugging code for detecting inconsistent data. Write debug
- // information on the stack, then crash.
- isolate_->PushStackTraceAndDie();
- }
-
// scope_type is stored only in debug mode.
- CHECK_GE(scope_data_->RemainingBytes(), kUint8Size);
+ CHECK_GE(scope_data_->RemainingBytes(), ByteData::kUint8Size);
DCHECK_EQ(scope_data_->ReadUint8(), scope->scope_type());
uint32_t eval = scope_data_->ReadUint8();
@@ -613,7 +583,9 @@ void ConsumedPreParsedScopeData::RestoreData(Scope* scope) {
RestoreDataForInnerScopes(scope);
}
-void ConsumedPreParsedScopeData::RestoreDataForVariable(Variable* var) {
+template <typename Data>
+void BaseConsumedPreParsedScopeData<Data>::RestoreDataForVariable(
+ Variable* var) {
#ifdef DEBUG
const AstRawString* name = var->raw_name();
bool data_one_byte = scope_data_->ReadUint8();
@@ -647,7 +619,9 @@ void ConsumedPreParsedScopeData::RestoreDataForVariable(Variable* var) {
}
}
-void ConsumedPreParsedScopeData::RestoreDataForInnerScopes(Scope* scope) {
+template <typename Data>
+void BaseConsumedPreParsedScopeData<Data>::RestoreDataForInnerScopes(
+ Scope* scope) {
std::vector<Scope*> scopes;
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
@@ -658,5 +632,106 @@ void ConsumedPreParsedScopeData::RestoreDataForInnerScopes(Scope* scope) {
}
}
+#ifdef DEBUG
+template <class Data>
+void BaseConsumedPreParsedScopeData<Data>::VerifyDataStart() {
+ typename ByteData::ReadingScope reading_scope(this);
+ int scope_data_start = scope_data_->ReadUint32();
+ scope_data_->SetPosition(scope_data_start);
+ DCHECK_EQ(scope_data_->ReadUint32(), ByteData::kMagicValue);
+ // The first data item is scope_data_start. Skip over it.
+ scope_data_->SetPosition(ByteData::kPlaceholderSize);
+}
+#endif
+
+PodArray<uint8_t>* OnHeapConsumedPreParsedScopeData::GetScopeData() {
+ return data_->scope_data();
+}
+
+ProducedPreParsedScopeData* OnHeapConsumedPreParsedScopeData::GetChildData(
+ Zone* zone, int child_index) {
+ CHECK_GT(data_->length(), child_index);
+ Object* child_data = data_->child_data(child_index);
+ if (!child_data->IsPreParsedScopeData()) {
+ return nullptr;
+ }
+ Handle<PreParsedScopeData> child_data_handle(
+ PreParsedScopeData::cast(child_data), isolate_);
+ return ProducedPreParsedScopeData::For(child_data_handle, zone);
+}
+
+OnHeapConsumedPreParsedScopeData::OnHeapConsumedPreParsedScopeData(
+ Isolate* isolate, Handle<PreParsedScopeData> data)
+ : BaseConsumedPreParsedScopeData<PodArray<uint8_t>>(),
+ isolate_(isolate),
+ data_(data) {
+ DCHECK_NOT_NULL(isolate);
+ DCHECK(data->IsPreParsedScopeData());
+#ifdef DEBUG
+ VerifyDataStart();
+#endif
+}
+
+ZonePreParsedScopeData::ZonePreParsedScopeData(
+ Zone* zone, ZoneChunkList<uint8_t>::iterator byte_data_begin,
+ ZoneChunkList<uint8_t>::iterator byte_data_end, int child_length)
+ : byte_data_(byte_data_begin, byte_data_end, zone),
+ children_(child_length, zone) {}
+
+Handle<PreParsedScopeData> ZonePreParsedScopeData::Serialize(Isolate* isolate) {
+ int child_data_length = child_length();
+ Handle<PreParsedScopeData> result =
+ isolate->factory()->NewPreParsedScopeData(child_data_length);
+
+ Handle<PodArray<uint8_t>> scope_data_array = PodArray<uint8_t>::New(
+ isolate, static_cast<int>(byte_data()->size()), TENURED);
+ scope_data_array->copy_in(0, byte_data()->data(),
+ static_cast<int>(byte_data()->size()));
+ result->set_scope_data(*scope_data_array);
+
+ for (int i = 0; i < child_data_length; i++) {
+ ZonePreParsedScopeData* child = get_child(i);
+ if (child) {
+ Handle<PreParsedScopeData> child_data = child->Serialize(isolate);
+ result->set_child_data(i, *child_data);
+ }
+ }
+ return result;
+}
+
+ZoneConsumedPreParsedScopeData::ZoneConsumedPreParsedScopeData(
+ Zone* zone, ZonePreParsedScopeData* data)
+ : data_(data), scope_data_wrapper_(data_->byte_data()) {
+#ifdef DEBUG
+ VerifyDataStart();
+#endif
+}
+
+ZoneVectorWrapper* ZoneConsumedPreParsedScopeData::GetScopeData() {
+ return &scope_data_wrapper_;
+}
+
+ProducedPreParsedScopeData* ZoneConsumedPreParsedScopeData::GetChildData(
+ Zone* zone, int child_index) {
+ CHECK_GT(data_->child_length(), child_index);
+ ZonePreParsedScopeData* child_data = data_->get_child(child_index);
+ if (child_data == nullptr) {
+ return nullptr;
+ }
+ return ProducedPreParsedScopeData::For(child_data, zone);
+}
+
+std::unique_ptr<ConsumedPreParsedScopeData> ConsumedPreParsedScopeData::For(
+ Isolate* isolate, Handle<PreParsedScopeData> data) {
+ DCHECK(!data.is_null());
+ return base::make_unique<OnHeapConsumedPreParsedScopeData>(isolate, data);
+}
+
+std::unique_ptr<ConsumedPreParsedScopeData> ConsumedPreParsedScopeData::For(
+ Zone* zone, ZonePreParsedScopeData* data) {
+ if (data == nullptr) return {};
+ return base::make_unique<ZoneConsumedPreParsedScopeData>(zone, data);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/preparsed-scope-data.h b/deps/v8/src/parsing/preparsed-scope-data.h
index 61d67291a4..25298c4331 100644
--- a/deps/v8/src/parsing/preparsed-scope-data.h
+++ b/deps/v8/src/parsing/preparsed-scope-data.h
@@ -5,23 +5,21 @@
#ifndef V8_PARSING_PREPARSED_SCOPE_DATA_H_
#define V8_PARSING_PREPARSED_SCOPE_DATA_H_
-#include <set>
-#include <unordered_map>
-#include <vector>
-
#include "src/globals.h"
#include "src/handles.h"
-#include "src/objects/shared-function-info.h"
+#include "src/maybe-handles.h"
#include "src/zone/zone-chunk-list.h"
+#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
template <typename T>
-class Handle;
+class PodArray;
class PreParser;
class PreParsedScopeData;
+class ZonePreParsedScopeData;
/*
@@ -64,40 +62,15 @@ class PreParsedScopeData;
*/
-class ProducedPreParsedScopeData : public ZoneObject {
+class PreParsedScopeDataBuilder : public ZoneObject {
public:
- class ByteData : public ZoneObject {
- public:
- explicit ByteData(Zone* zone)
- : backing_store_(zone), free_quarters_in_last_byte_(0) {}
-
- void WriteUint32(uint32_t data);
- void WriteUint8(uint8_t data);
- void WriteQuarter(uint8_t data);
-
-#ifdef DEBUG
- // For overwriting previously written data at position 0.
- void OverwriteFirstUint32(uint32_t data);
-#endif
-
- Handle<PodArray<uint8_t>> Serialize(Isolate* isolate);
-
- size_t size() const { return backing_store_.size(); }
+ class ByteData;
- private:
- ZoneChunkList<uint8_t> backing_store_;
- uint8_t free_quarters_in_last_byte_;
- };
-
- // Create a ProducedPreParsedScopeData object which will collect data as we
+ // Create a PreParsedScopeDataBuilder object which will collect data as we
// parse.
- ProducedPreParsedScopeData(Zone* zone, ProducedPreParsedScopeData* parent);
-
- // Create a ProducedPreParsedScopeData which is just a proxy for a previous
- // produced PreParsedScopeData.
- ProducedPreParsedScopeData(Handle<PreParsedScopeData> data, Zone* zone);
+ PreParsedScopeDataBuilder(Zone* zone, PreParsedScopeDataBuilder* parent);
- ProducedPreParsedScopeData* parent() const { return parent_; }
+ PreParsedScopeDataBuilder* parent() const { return parent_; }
// For gathering the inner function data and splitting it up according to the
// laziness boundaries. Each lazy function gets its own
@@ -112,7 +85,7 @@ class ProducedPreParsedScopeData : public ZoneObject {
private:
DeclarationScope* function_scope_;
PreParser* preparser_;
- ProducedPreParsedScopeData* produced_preparsed_scope_data_;
+ PreParsedScopeDataBuilder* builder_;
DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
};
@@ -148,15 +121,15 @@ class ProducedPreParsedScopeData : public ZoneObject {
bool ContainsInnerFunctions() const;
- // If there is data (if the Scope contains skippable inner functions), move
- // the data into the heap and return a Handle to it; otherwise return a null
- // MaybeHandle.
- MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate);
-
static bool ScopeNeedsData(Scope* scope);
static bool ScopeIsSkippableFunctionScope(Scope* scope);
private:
+ friend class BuilderProducedPreParsedScopeData;
+
+ virtual MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate);
+ virtual ZonePreParsedScopeData* Serialize(Zone* zone);
+
void AddSkippableFunction(int start_position, int end_position,
int num_parameters, int num_inner_functions,
LanguageMode language_mode,
@@ -166,88 +139,72 @@ class ProducedPreParsedScopeData : public ZoneObject {
void SaveDataForVariable(Variable* var);
void SaveDataForInnerScopes(Scope* scope);
- ProducedPreParsedScopeData* parent_;
+ PreParsedScopeDataBuilder* parent_;
ByteData* byte_data_;
- ZoneChunkList<ProducedPreParsedScopeData*> data_for_inner_functions_;
+ ZoneChunkList<PreParsedScopeDataBuilder*> data_for_inner_functions_;
// Whether we've given up producing the data for this function.
bool bailed_out_;
- // ProducedPreParsedScopeData can also mask a Handle<PreParsedScopeData>
- // which was produced already earlier. This happens for deeper lazy functions.
- Handle<PreParsedScopeData> previously_produced_preparsed_scope_data_;
+ DISALLOW_COPY_AND_ASSIGN(PreParsedScopeDataBuilder);
+};
- DISALLOW_COPY_AND_ASSIGN(ProducedPreParsedScopeData);
+class ProducedPreParsedScopeData : public ZoneObject {
+ public:
+ // If there is data (if the Scope contains skippable inner functions), move
+ // the data into the heap and return a Handle to it; otherwise return a null
+ // MaybeHandle.
+ virtual MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) = 0;
+
+ // If there is data (if the Scope contains skippable inner functions), return
+ // an off-heap ZonePreParsedScopeData representing the data; otherwise
+ // return nullptr.
+ virtual ZonePreParsedScopeData* Serialize(Zone* zone) = 0;
+
+ // Create a ProducedPreParsedScopeData which is a proxy for a previous
+ // produced PreParsedScopeData in zone.
+ static ProducedPreParsedScopeData* For(PreParsedScopeDataBuilder* builder,
+ Zone* zone);
+
+ // Create a ProducedPreParsedScopeData which is a proxy for a previous
+ // produced PreParsedScopeData on the heap.
+ static ProducedPreParsedScopeData* For(Handle<PreParsedScopeData> data,
+ Zone* zone);
+
+ // Create a ProducedPreParsedScopeData which is a proxy for a previous
+ // produced PreParsedScopeData in zone.
+ static ProducedPreParsedScopeData* For(ZonePreParsedScopeData* data,
+ Zone* zone);
};
class ConsumedPreParsedScopeData {
public:
- class ByteData {
- public:
- ByteData()
- : data_(nullptr), index_(0), stored_quarters_(0), stored_byte_(0) {}
-
- // Reading from the ByteData is only allowed when a ReadingScope is on the
- // stack. This ensures that we have a DisallowHeapAllocation in place
- // whenever ByteData holds a raw pointer into the heap.
- class ReadingScope {
- public:
- ReadingScope(ByteData* consumed_data, PodArray<uint8_t>* data)
- : consumed_data_(consumed_data) {
- consumed_data->data_ = data;
- }
- explicit ReadingScope(ConsumedPreParsedScopeData* parent);
- ~ReadingScope() { consumed_data_->data_ = nullptr; }
-
- private:
- ByteData* consumed_data_;
- DisallowHeapAllocation no_gc;
- };
-
- void SetPosition(int position) { index_ = position; }
-
- int32_t ReadUint32();
- uint8_t ReadUint8();
- uint8_t ReadQuarter();
-
- size_t RemainingBytes() const;
-
- // private:
- PodArray<uint8_t>* data_;
- int index_;
- uint8_t stored_quarters_;
- uint8_t stored_byte_;
- };
-
- ConsumedPreParsedScopeData();
- ~ConsumedPreParsedScopeData();
+ // Creates a ConsumedPreParsedScopeData representing the data of an on-heap
+ // PreParsedScopeData |data|.
+ static std::unique_ptr<ConsumedPreParsedScopeData> For(
+ Isolate* isolate, Handle<PreParsedScopeData> data);
- void SetData(Isolate* isolate, Handle<PreParsedScopeData> data);
+ // Creates a ConsumedPreParsedScopeData representing the data of an off-heap
+ // ZonePreParsedScopeData |data|.
+ static std::unique_ptr<ConsumedPreParsedScopeData> For(
+ Zone* zone, ZonePreParsedScopeData* data);
- bool HasData() const { return !data_.is_null(); }
+ virtual ~ConsumedPreParsedScopeData() = default;
- ProducedPreParsedScopeData* GetDataForSkippableFunction(
+ virtual ProducedPreParsedScopeData* GetDataForSkippableFunction(
Zone* zone, int start_position, int* end_position, int* num_parameters,
int* num_inner_functions, bool* uses_super_property,
- LanguageMode* language_mode);
+ LanguageMode* language_mode) = 0;
// Restores the information needed for allocating the Scope's (and its
// subscopes') variables.
- void RestoreScopeAllocationData(DeclarationScope* scope);
+ virtual void RestoreScopeAllocationData(DeclarationScope* scope) = 0;
- private:
- void RestoreData(Scope* scope);
- void RestoreDataForVariable(Variable* var);
- void RestoreDataForInnerScopes(Scope* scope);
-
- Isolate* isolate_;
- Handle<PreParsedScopeData> data_;
- std::unique_ptr<ByteData> scope_data_;
- // When consuming the data, these indexes point to the data we're going to
- // consume next.
- int child_index_;
+ protected:
+ ConsumedPreParsedScopeData() = default;
+ private:
DISALLOW_COPY_AND_ASSIGN(ConsumedPreParsedScopeData);
};
diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc
index d449c8d76b..0e74014542 100644
--- a/deps/v8/src/parsing/preparser.cc
+++ b/deps/v8/src/parsing/preparser.cc
@@ -123,22 +123,23 @@ PreParser::PreParseResult PreParser::PreParseFunction(
int script_id) {
DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
use_counts_ = use_counts;
- DCHECK(!track_unresolved_variables_);
- track_unresolved_variables_ = is_inner_function;
set_script_id(script_id);
#ifdef DEBUG
function_scope->set_is_being_lazily_parsed(true);
#endif
+ track_unresolved_variables_ =
+ ShouldTrackUnresolvedVariables(is_inner_function);
+
// Start collecting data for a new function which might contain skippable
// functions.
- std::unique_ptr<ProducedPreParsedScopeData::DataGatheringScope>
- produced_preparsed_scope_data_scope;
+ std::unique_ptr<PreParsedScopeDataBuilder::DataGatheringScope>
+ preparsed_scope_data_builder_scope;
if (FLAG_preparser_scope_analysis && !IsArrowFunction(kind)) {
- track_unresolved_variables_ = true;
- produced_preparsed_scope_data_scope.reset(
- new ProducedPreParsedScopeData::DataGatheringScope(function_scope,
- this));
+ DCHECK(track_unresolved_variables_);
+ preparsed_scope_data_builder_scope.reset(
+ new PreParsedScopeDataBuilder::DataGatheringScope(function_scope,
+ this));
}
// In the preparser, we use the function literal ids to count how many
@@ -166,7 +167,11 @@ PreParser::PreParseResult PreParser::PreParseFunction(
formals_classifier.reset(new ExpressionClassifier(this, &duplicate_finder));
// We return kPreParseSuccess in failure cases too - errors are retrieved
// separately by Parser::SkipLazyFunctionBody.
- ParseFormalParameterList(&formals, CHECK_OK_VALUE(kPreParseSuccess));
+ ParseFormalParameterList(
+ &formals,
+ CHECK_OK_VALUE(pending_error_handler()->ErrorUnidentifiableByPreParser()
+ ? kPreParseNotIdentifiableError
+ : kPreParseSuccess));
Expect(Token::RPAREN, CHECK_OK_VALUE(kPreParseSuccess));
int formals_end_position = scanner()->location().end_pos;
@@ -205,27 +210,22 @@ PreParser::PreParseResult PreParser::PreParseFunction(
}
}
- if (!IsArrowFunction(kind) && track_unresolved_variables_ &&
- result == kLazyParsingComplete) {
- // Declare arguments after parsing the function since lexical 'arguments'
- // masks the arguments object. Declare arguments before declaring the
- // function var since the arguments object masks 'function arguments'.
- function_scope->DeclareArguments(ast_value_factory());
-
- DeclareFunctionNameVar(function_name, function_type, function_scope);
- }
-
use_counts_ = nullptr;
- track_unresolved_variables_ = false;
if (result == kLazyParsingAborted) {
+ DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
return kPreParseAbort;
} else if (stack_overflow()) {
+ DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
return kPreParseStackOverflow;
+ } else if (pending_error_handler()->ErrorUnidentifiableByPreParser()) {
+ DCHECK(!*ok);
+ return kPreParseNotIdentifiableError;
} else if (!*ok) {
DCHECK(pending_error_handler()->has_pending_error());
} else {
DCHECK_EQ(Token::RBRACE, scanner()->peek());
+ DCHECK(result == kLazyParsingComplete);
if (!IsArrowFunction(kind)) {
// Validate parameter names. We can do this only after parsing the
@@ -234,17 +234,37 @@ PreParser::PreParseResult PreParser::PreParseFunction(
is_sloppy(function_scope->language_mode()) && formals.is_simple &&
!IsConciseMethod(kind);
ValidateFormalParameters(function_scope->language_mode(),
- allow_duplicate_parameters,
- CHECK_OK_VALUE(kPreParseSuccess));
+ allow_duplicate_parameters, ok);
+ if (!*ok) {
+ if (pending_error_handler()->ErrorUnidentifiableByPreParser()) {
+ return kPreParseNotIdentifiableError;
+ } else {
+ return kPreParseSuccess;
+ }
+ }
+
+ if (track_unresolved_variables_) {
+ // Declare arguments after parsing the function since lexical
+ // 'arguments' masks the arguments object. Declare arguments before
+ // declaring the function var since the arguments object masks 'function
+ // arguments'.
+ function_scope->DeclareArguments(ast_value_factory());
- *produced_preparsed_scope_data = produced_preparsed_scope_data_;
+ DeclareFunctionNameVar(function_name, function_type, function_scope);
+ }
+
+ *produced_preparsed_scope_data = ProducedPreParsedScopeData::For(
+ preparsed_scope_data_builder_, main_zone());
}
+ DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
if (is_strict(function_scope->language_mode())) {
int end_pos = scanner()->location().end_pos;
CheckStrictOctalLiteral(function_scope->start_position(), end_pos, ok);
}
}
+
+ DCHECK(!pending_error_handler()->ErrorUnidentifiableByPreParser());
return kPreParseSuccess;
}
@@ -290,15 +310,15 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
// Start collecting data for a new function which might contain skippable
// functions.
- std::unique_ptr<ProducedPreParsedScopeData::DataGatheringScope>
- produced_preparsed_scope_data_scope;
+ std::unique_ptr<PreParsedScopeDataBuilder::DataGatheringScope>
+ preparsed_scope_data_builder_scope;
if (!function_state_->next_function_is_likely_called() &&
- produced_preparsed_scope_data_ != nullptr) {
+ preparsed_scope_data_builder_ != nullptr) {
DCHECK(FLAG_preparser_scope_analysis);
DCHECK(track_unresolved_variables_);
- produced_preparsed_scope_data_scope.reset(
- new ProducedPreParsedScopeData::DataGatheringScope(function_scope,
- this));
+ preparsed_scope_data_builder_scope.reset(
+ new PreParsedScopeDataBuilder::DataGatheringScope(function_scope,
+ this));
}
FunctionState function_state(&function_state_, &scope_, function_scope);
@@ -324,7 +344,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
int pos = function_token_pos == kNoSourcePosition ? peek_position()
: function_token_pos;
ParseFunctionBody(body, function_name, pos, formals, kind, function_type,
- CHECK_OK);
+ FunctionBodyType::kBlock, true, CHECK_OK);
// Parsing the body may change the language mode in our scope.
language_mode = function_scope->language_mode();
@@ -346,8 +366,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
}
- if (produced_preparsed_scope_data_scope) {
- produced_preparsed_scope_data_scope->MarkFunctionAsSkippable(
+ if (preparsed_scope_data_builder_scope) {
+ preparsed_scope_data_builder_scope->MarkFunctionAsSkippable(
end_position, GetLastFunctionLiteralId() - func_id);
}
if (V8_UNLIKELY(FLAG_log_function_events)) {
@@ -394,19 +414,19 @@ PreParserStatement PreParser::BuildParameterInitializationBlock(
DCHECK(scope()->is_function_scope());
if (FLAG_preparser_scope_analysis &&
scope()->AsDeclarationScope()->calls_sloppy_eval() &&
- produced_preparsed_scope_data_ != nullptr) {
+ preparsed_scope_data_builder_ != nullptr) {
// We cannot replicate the Scope structure constructed by the Parser,
// because we've lost information whether each individual parameter was
// simple or not. Give up trying to produce data to skip inner functions.
- if (produced_preparsed_scope_data_->parent() != nullptr) {
+ if (preparsed_scope_data_builder_->parent() != nullptr) {
// Lazy parsing started before the current function; the function which
// cannot contain skippable functions is the parent function. (Its inner
// functions cannot either; they are implicitly bailed out.)
- produced_preparsed_scope_data_->parent()->Bailout();
+ preparsed_scope_data_builder_->parent()->Bailout();
} else {
// Lazy parsing started at the current function; it cannot contain
// skippable functions.
- produced_preparsed_scope_data_->Bailout();
+ preparsed_scope_data_builder_->Bailout();
}
}
diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h
index 10c42fa940..65509a2029 100644
--- a/deps/v8/src/parsing/preparser.h
+++ b/deps/v8/src/parsing/preparser.h
@@ -10,7 +10,6 @@
#include "src/parsing/parser-base.h"
#include "src/parsing/preparser-logger.h"
#include "src/pending-compilation-error-handler.h"
-#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
@@ -23,7 +22,7 @@ namespace internal {
// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
// used.
-class ProducedPreParsedScopeData;
+class PreParsedScopeDataBuilder;
class PreParserIdentifier {
public:
@@ -87,16 +86,18 @@ class PreParserIdentifier {
friend class PreParserFactory;
};
-
class PreParserExpression {
public:
+ using VariableZoneThreadedListType =
+ ZoneThreadedList<VariableProxy, VariableProxy::PreParserNext>;
+
PreParserExpression()
: code_(TypeField::encode(kNull)), variables_(nullptr) {}
static PreParserExpression Null() { return PreParserExpression(); }
static PreParserExpression Default(
- ZonePtrList<VariableProxy>* variables = nullptr) {
+ VariableZoneThreadedListType* variables = nullptr) {
return PreParserExpression(TypeField::encode(kExpression), variables);
}
@@ -125,9 +126,7 @@ class PreParserExpression {
right.variables_);
}
if (right.variables_ != nullptr) {
- for (auto variable : *right.variables_) {
- left.variables_->Add(variable, zone);
- }
+ left.variables_->Append(std::move(*right.variables_));
}
return PreParserExpression(TypeField::encode(kExpression),
left.variables_);
@@ -135,7 +134,8 @@ class PreParserExpression {
return PreParserExpression(TypeField::encode(kExpression));
}
- static PreParserExpression Assignment(ZonePtrList<VariableProxy>* variables) {
+ static PreParserExpression Assignment(
+ VariableZoneThreadedListType* variables) {
return PreParserExpression(TypeField::encode(kExpression) |
ExpressionTypeField::encode(kAssignment),
variables);
@@ -146,13 +146,13 @@ class PreParserExpression {
}
static PreParserExpression ObjectLiteral(
- ZonePtrList<VariableProxy>* variables) {
+ VariableZoneThreadedListType* variables) {
return PreParserExpression(TypeField::encode(kObjectLiteralExpression),
variables);
}
static PreParserExpression ArrayLiteral(
- ZonePtrList<VariableProxy>* variables) {
+ VariableZoneThreadedListType* variables) {
return PreParserExpression(TypeField::encode(kArrayLiteralExpression),
variables);
}
@@ -171,10 +171,9 @@ class PreParserExpression {
IsUseAsmField::encode(true));
}
- static PreParserExpression This(ZonePtrList<VariableProxy>* variables) {
+ static PreParserExpression This() {
return PreParserExpression(TypeField::encode(kExpression) |
- ExpressionTypeField::encode(kThisExpression),
- variables);
+ ExpressionTypeField::encode(kThisExpression));
}
static PreParserExpression ThisPropertyWithPrivateFieldKey() {
@@ -336,7 +335,7 @@ class PreParserExpression {
if (variables_ != nullptr) {
DCHECK(IsIdentifier());
DCHECK(AsIdentifier().IsPrivateName());
- DCHECK_EQ(1, variables_->length());
+ DCHECK_EQ(1, variables_->LengthForTest());
variables_->first()->set_is_private_field();
}
}
@@ -374,8 +373,9 @@ class PreParserExpression {
kAssignment
};
- explicit PreParserExpression(uint32_t expression_code,
- ZonePtrList<VariableProxy>* variables = nullptr)
+ explicit PreParserExpression(
+ uint32_t expression_code,
+ VariableZoneThreadedListType* variables = nullptr)
: code_(expression_code), variables_(variables) {}
void AddVariable(VariableProxy* variable, Zone* zone) {
@@ -383,9 +383,9 @@ class PreParserExpression {
return;
}
if (variables_ == nullptr) {
- variables_ = new (zone) ZonePtrList<VariableProxy>(1, zone);
+ variables_ = new (zone) VariableZoneThreadedListType();
}
- variables_->Add(variable, zone);
+ variables_->Add(variable);
}
// The first three bits are for the Type.
@@ -410,64 +410,65 @@ class PreParserExpression {
uint32_t code_;
// If the PreParser is used in the variable tracking mode, PreParserExpression
// accumulates variables in that expression.
- ZonePtrList<VariableProxy>* variables_;
+ VariableZoneThreadedListType* variables_;
friend class PreParser;
friend class PreParserFactory;
- template <typename T>
- friend class PreParserList;
+ friend class PreParserExpressionList;
};
// The pre-parser doesn't need to build lists of expressions, identifiers, or
// the like. If the PreParser is used in variable tracking mode, it needs to
// build lists of variables though.
-template <typename T>
-class PreParserList {
+class PreParserExpressionList {
+ using VariableZoneThreadedListType =
+ ZoneThreadedList<VariableProxy, VariableProxy::PreParserNext>;
+
public:
// These functions make list->Add(some_expression) work (and do nothing).
- PreParserList() : length_(0), variables_(nullptr) {}
- PreParserList* operator->() { return this; }
- void Add(const T& element, Zone* zone);
+ PreParserExpressionList() : PreParserExpressionList(0) {}
+ PreParserExpressionList* operator->() { return this; }
+ void Add(const PreParserExpression& expression, Zone* zone) {
+ if (expression.variables_ != nullptr) {
+ DCHECK(FLAG_lazy_inner_functions);
+ DCHECK_NOT_NULL(zone);
+ if (variables_ == nullptr) {
+ variables_ = new (zone) VariableZoneThreadedListType();
+ }
+ variables_->Append(std::move(*expression.variables_));
+ }
+ ++length_;
+ }
int length() const { return length_; }
- static PreParserList Null() { return PreParserList(-1); }
+ static PreParserExpressionList Null() { return PreParserExpressionList(-1); }
bool IsNull() const { return length_ == -1; }
- void Set(int index, const T& element) {}
+ void Set(int index, const PreParserExpression& element) {}
private:
- explicit PreParserList(int n) : length_(n), variables_(nullptr) {}
+ explicit PreParserExpressionList(int n) : length_(n), variables_(nullptr) {}
int length_;
- ZonePtrList<VariableProxy>* variables_;
+
+ VariableZoneThreadedListType* variables_;
friend class PreParser;
friend class PreParserFactory;
};
-template <>
-inline void PreParserList<PreParserExpression>::Add(
- const PreParserExpression& expression, Zone* zone) {
- if (expression.variables_ != nullptr) {
- DCHECK(FLAG_lazy_inner_functions);
- DCHECK_NOT_NULL(zone);
- if (variables_ == nullptr) {
- variables_ = new (zone) ZonePtrList<VariableProxy>(1, zone);
- }
- for (auto identifier : (*expression.variables_)) {
- variables_->Add(identifier, zone);
- }
- }
- ++length_;
-}
-
-template <typename T>
-void PreParserList<T>::Add(const T& element, Zone* zone) {
- ++length_;
-}
+class PreParserStatement;
-typedef PreParserList<PreParserExpression> PreParserExpressionList;
+class PreParserStatementList {
+ public:
+ PreParserStatementList() : PreParserStatementList(false) {}
+ PreParserStatementList* operator->() { return this; }
+ void Add(const PreParserStatement& element, Zone* zone) {}
+ static PreParserStatementList Null() { return PreParserStatementList(true); }
+ bool IsNull() const { return is_null_; }
-class PreParserStatement;
-typedef PreParserList<PreParserStatement> PreParserStatementList;
+ private:
+ explicit PreParserStatementList(bool is_null) : is_null_(is_null) {}
+ bool is_null_;
+};
class PreParserStatement {
public:
@@ -530,8 +531,6 @@ class PreParserStatement {
// and PreParser.
PreParserStatement* operator->() { return this; }
- // TODO(adamk): These should return something even lighter-weight than
- // PreParserStatementList.
PreParserStatementList statements() { return PreParserStatementList(); }
PreParserStatementList cases() { return PreParserStatementList(); }
@@ -563,11 +562,6 @@ class PreParserFactory {
explicit PreParserFactory(AstValueFactory* ast_value_factory, Zone* zone)
: ast_node_factory_(ast_value_factory, zone), zone_(zone) {}
- void set_zone(Zone* zone) {
- ast_node_factory_.set_zone(zone);
- zone_ = zone;
- }
-
AstNodeFactory* ast_node_factory() { return &ast_node_factory_; }
PreParserExpression NewStringLiteral(const PreParserIdentifier& identifier,
@@ -852,19 +846,22 @@ class PreParserFactory {
struct PreParserFormalParameters : FormalParametersBase {
struct Parameter : public ZoneObject {
- Parameter(ZonePtrList<VariableProxy>* variables, bool is_rest)
+ using VariableZoneThreadedListType =
+ ZoneThreadedList<VariableProxy, VariableProxy::PreParserNext>;
+
+ Parameter(VariableZoneThreadedListType* variables, bool is_rest)
: variables_(variables), is_rest(is_rest) {}
Parameter** next() { return &next_parameter; }
Parameter* const* next() const { return &next_parameter; }
- ZonePtrList<VariableProxy>* variables_;
+ VariableZoneThreadedListType* variables_;
Parameter* next_parameter = nullptr;
bool is_rest : 1;
};
explicit PreParserFormalParameters(DeclarationScope* scope)
: FormalParametersBase(scope) {}
- ThreadedList<Parameter> params;
+ base::ThreadedList<Parameter> params;
};
@@ -881,6 +878,48 @@ class PreParserTargetScope {
explicit PreParserTargetScope(ParserBase<PreParser>* preparser) {}
};
+class PreParserFuncNameInferrer {
+ public:
+ PreParserFuncNameInferrer(AstValueFactory* avf, Zone* zone) {}
+ void RemoveAsyncKeywordFromEnd() const {}
+ void Infer() const {}
+ void RemoveLastFunction() const {}
+
+ class State {
+ public:
+ explicit State(PreParserFuncNameInferrer* fni) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(State);
+ };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PreParserFuncNameInferrer);
+};
+
+class PreParserSourceRange {
+ public:
+ PreParserSourceRange() {}
+ PreParserSourceRange(int start, int end) {}
+ static PreParserSourceRange Empty() { return PreParserSourceRange(); }
+ static PreParserSourceRange OpenEnded(int32_t start) { return Empty(); }
+ static const PreParserSourceRange& ContinuationOf(
+ const PreParserSourceRange& that, int end) {
+ return that;
+ }
+};
+
+class PreParserSourceRangeScope {
+ public:
+ PreParserSourceRangeScope(Scanner* scanner, PreParserSourceRange* range) {}
+ const PreParserSourceRange& Finalize() const { return range_; }
+
+ private:
+ PreParserSourceRange range_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PreParserSourceRangeScope);
+};
+
template <>
struct ParserTypes<PreParser> {
typedef ParserBase<PreParser> Base;
@@ -910,6 +949,10 @@ struct ParserTypes<PreParser> {
typedef PreParserTarget Target;
typedef PreParserTargetScope TargetScope;
+ typedef PreParserFuncNameInferrer FuncNameInferrer;
+ typedef PreParserSourceRange SourceRange;
+ typedef PreParserSourceRangeScope SourceRangeScope;
+ static constexpr bool ExpressionClassifierReportErrors = false;
};
@@ -937,6 +980,7 @@ class PreParser : public ParserBase<PreParser> {
enum PreParseResult {
kPreParseStackOverflow,
kPreParseAbort,
+ kPreParseNotIdentifiableError,
kPreParseSuccess
};
@@ -952,7 +996,7 @@ class PreParser : public ParserBase<PreParser> {
parsing_module, parsing_on_main_thread),
use_counts_(nullptr),
track_unresolved_variables_(false),
- produced_preparsed_scope_data_(nullptr) {}
+ preparsed_scope_data_builder_(nullptr) {}
static bool IsPreParser() { return true; }
@@ -980,13 +1024,17 @@ class PreParser : public ParserBase<PreParser> {
ProducedPreParsedScopeData** produced_preparser_scope_data,
int script_id);
- ProducedPreParsedScopeData* produced_preparsed_scope_data() const {
- return produced_preparsed_scope_data_;
+ V8_INLINE static bool ShouldTrackUnresolvedVariables(bool is_inner_function) {
+ return FLAG_preparser_scope_analysis || is_inner_function;
+ }
+
+ PreParsedScopeDataBuilder* preparsed_scope_data_builder() const {
+ return preparsed_scope_data_builder_;
}
- void set_produced_preparsed_scope_data(
- ProducedPreParsedScopeData* produced_preparsed_scope_data) {
- produced_preparsed_scope_data_ = produced_preparsed_scope_data;
+ void set_preparsed_scope_data_builder(
+ PreParsedScopeDataBuilder* preparsed_scope_data_builder) {
+ preparsed_scope_data_builder_ = preparsed_scope_data_builder;
}
private:
@@ -1009,12 +1057,13 @@ class PreParser : public ParserBase<PreParser> {
return pending_error_handler_;
}
- V8_INLINE LazyParsingResult
- SkipFunction(const AstRawString* name, FunctionKind kind,
- FunctionLiteral::FunctionType function_type,
- DeclarationScope* function_scope, int* num_parameters,
- ProducedPreParsedScopeData** produced_preparsed_scope_data,
- bool is_inner_function, bool may_abort, bool* ok) {
+ V8_INLINE bool SkipFunction(
+ const AstRawString* name, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type,
+ DeclarationScope* function_scope, int* num_parameters,
+ ProducedPreParsedScopeData** produced_preparsed_scope_data,
+ bool is_inner_function, bool may_abort,
+ FunctionLiteral::EagerCompileHint* hint, bool* ok) {
UNREACHABLE();
}
@@ -1509,6 +1558,10 @@ class PreParser : public ParserBase<PreParser> {
arg, error_type);
}
+ V8_INLINE void ReportUnidentifiableError() {
+ pending_error_handler()->SetUnidentifiableError();
+ }
+
V8_INLINE void ReportMessageAt(Scanner::Location source_location,
MessageTemplate::Template message,
const PreParserIdentifier& arg,
@@ -1558,16 +1611,12 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE PreParserExpression ThisExpression(int pos = kNoSourcePosition) {
- ZonePtrList<VariableProxy>* variables = nullptr;
if (track_unresolved_variables_) {
- VariableProxy* proxy = scope()->NewUnresolved(
- factory()->ast_node_factory(), ast_value_factory()->this_string(),
- pos, THIS_VARIABLE);
-
- variables = new (zone()) ZonePtrList<VariableProxy>(1, zone());
- variables->Add(proxy, zone());
+ scope()->NewUnresolved(factory()->ast_node_factory(),
+ ast_value_factory()->this_string(), pos,
+ THIS_VARIABLE);
}
- return PreParserExpression::This(variables);
+ return PreParserExpression::This();
}
V8_INLINE PreParserExpression NewSuperPropertyReference(int pos) {
@@ -1648,14 +1697,6 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Jump();
}
- V8_INLINE void AddParameterInitializationBlock(
- const PreParserFormalParameters& parameters, PreParserStatementList body,
- bool is_async, bool* ok) {
- if (!parameters.is_simple) {
- BuildParameterInitializationBlock(parameters, ok);
- }
- }
-
V8_INLINE void AddFormalParameter(PreParserFormalParameters* parameters,
const PreParserExpression& pattern,
const PreParserExpression& initializer,
@@ -1671,14 +1712,15 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void DeclareFormalParameters(
DeclarationScope* scope,
- const ThreadedList<PreParserFormalParameters::Parameter>& parameters,
+ const base::ThreadedList<PreParserFormalParameters::Parameter>&
+ parameters,
bool is_simple) {
if (!is_simple) scope->SetHasNonSimpleParameters();
if (track_unresolved_variables_) {
DCHECK(FLAG_lazy_inner_functions);
for (auto parameter : parameters) {
DCHECK_IMPLIES(is_simple, parameter->variables_ != nullptr);
- DCHECK_IMPLIES(is_simple, parameter->variables_->length() == 1);
+ DCHECK_IMPLIES(is_simple, parameter->variables_->LengthForTest() == 1);
// Make sure each parameter is added only once even if it's a
// destructuring parameter which contains multiple names.
bool add_parameter = true;
@@ -1733,7 +1775,7 @@ class PreParser : public ParserBase<PreParser> {
const PreParserExpression& value, const PreParserExpression& identifier) {
}
- V8_INLINE ZoneVector<typename ExpressionClassifier::Error>*
+ V8_INLINE ZoneList<typename ExpressionClassifier::Error>*
GetReportedErrorList() const {
return function_state_->GetReportedErrorList();
}
@@ -1758,7 +1800,7 @@ class PreParser : public ParserBase<PreParser> {
bool track_unresolved_variables_;
PreParserLogger log_;
- ProducedPreParsedScopeData* produced_preparsed_scope_data_;
+ PreParsedScopeDataBuilder* preparsed_scope_data_builder_;
};
PreParserExpression PreParser::SpreadCall(const PreParserExpression& function,
diff --git a/deps/v8/src/parsing/scanner-character-streams.cc b/deps/v8/src/parsing/scanner-character-streams.cc
index d38fdd7c42..8472e9f4fc 100644
--- a/deps/v8/src/parsing/scanner-character-streams.cc
+++ b/deps/v8/src/parsing/scanner-character-streams.cc
@@ -4,6 +4,9 @@
#include "src/parsing/scanner-character-streams.h"
+#include <memory>
+#include <vector>
+
#include "include/v8.h"
#include "src/counters.h"
#include "src/globals.h"
@@ -15,21 +18,50 @@
namespace v8 {
namespace internal {
+class ScopedExternalStringLock {
+ public:
+ explicit ScopedExternalStringLock(ExternalString* string) {
+ DCHECK(string);
+ if (string->IsExternalOneByteString()) {
+ resource_ = ExternalOneByteString::cast(string)->resource();
+ } else {
+ DCHECK(string->IsExternalTwoByteString());
+ resource_ = ExternalTwoByteString::cast(string)->resource();
+ }
+ DCHECK(resource_);
+ resource_->Lock();
+ }
+
+ // Copying a lock increases the locking depth.
+ ScopedExternalStringLock(const ScopedExternalStringLock& other)
+ : resource_(other.resource_) {
+ resource_->Lock();
+ }
+
+ ~ScopedExternalStringLock() { resource_->Unlock(); }
+
+ private:
+ // Not nullptr.
+ const v8::String::ExternalStringResourceBase* resource_;
+};
+
namespace {
const unibrow::uchar kUtf8Bom = 0xFEFF;
} // namespace
template <typename Char>
-struct HeapStringType;
+struct CharTraits;
template <>
-struct HeapStringType<uint8_t> {
+struct CharTraits<uint8_t> {
typedef SeqOneByteString String;
+ typedef ExternalOneByteString ExternalString;
};
template <>
-struct HeapStringType<uint16_t> {
+struct CharTraits<uint16_t> {
typedef SeqTwoByteString String;
+ typedef ExternalTwoByteString ExternalString;
};
template <typename Char>
@@ -47,16 +79,21 @@ struct Range {
template <typename Char>
class OnHeapStream {
public:
- typedef typename HeapStringType<Char>::String String;
+ typedef typename CharTraits<Char>::String String;
OnHeapStream(Handle<String> string, size_t start_offset, size_t end)
: string_(string), start_offset_(start_offset), length_(end) {}
- Range<Char> GetDataAt(size_t pos) {
+ OnHeapStream(const OnHeapStream& other) : start_offset_(0), length_(0) {
+ UNREACHABLE();
+ }
+
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
return {&string_->GetChars()[start_offset_ + Min(length_, pos)],
&string_->GetChars()[start_offset_ + length_]};
}
+ static const bool kCanBeCloned = false;
static const bool kCanAccessHeap = true;
private:
@@ -69,14 +106,42 @@ class OnHeapStream {
// ExternalTwoByteString.
template <typename Char>
class ExternalStringStream {
+ typedef typename CharTraits<Char>::ExternalString ExternalString;
+
public:
- ExternalStringStream(const Char* data, size_t end)
- : data_(data), length_(end) {}
+ ExternalStringStream(ExternalString* string, size_t start_offset,
+ size_t length)
+ : lock_(string),
+ data_(string->GetChars() + start_offset),
+ length_(length) {}
+
+ ExternalStringStream(const ExternalStringStream& other)
+ : lock_(other.lock_), data_(other.data_), length_(other.length_) {}
- Range<Char> GetDataAt(size_t pos) {
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
return {&data_[Min(length_, pos)], &data_[length_]};
}
+ static const bool kCanBeCloned = true;
+ static const bool kCanAccessHeap = false;
+
+ private:
+ ScopedExternalStringLock lock_;
+ const Char* const data_;
+ const size_t length_;
+};
+
+// A Char stream backed by a C array. Testing only.
+template <typename Char>
+class TestingStream {
+ public:
+ TestingStream(const Char* data, size_t length)
+ : data_(data), length_(length) {}
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
+ return {&data_[Min(length_, pos)], &data_[length_]};
+ }
+
+ static const bool kCanBeCloned = true;
static const bool kCanAccessHeap = false;
private:
@@ -88,12 +153,16 @@ class ExternalStringStream {
template <typename Char>
class ChunkedStream {
public:
- ChunkedStream(ScriptCompiler::ExternalSourceStream* source,
- RuntimeCallStats* stats)
- : source_(source), stats_(stats) {}
+ explicit ChunkedStream(ScriptCompiler::ExternalSourceStream* source)
+ : source_(source) {}
+
+ ChunkedStream(const ChunkedStream& other) {
+ // TODO(rmcilroy): Implement cloning for chunked streams.
+ UNREACHABLE();
+ }
- Range<Char> GetDataAt(size_t pos) {
- Chunk chunk = FindChunk(pos);
+ Range<Char> GetDataAt(size_t pos, RuntimeCallStats* stats) {
+ Chunk chunk = FindChunk(pos, stats);
size_t buffer_end = chunk.length;
size_t buffer_pos = Min(buffer_end, pos - chunk.position);
return {&chunk.data[buffer_pos], &chunk.data[buffer_end]};
@@ -103,6 +172,7 @@ class ChunkedStream {
for (Chunk& chunk : chunks_) delete[] chunk.data;
}
+ static const bool kCanBeCloned = false;
static const bool kCanAccessHeap = false;
private:
@@ -116,13 +186,13 @@ class ChunkedStream {
size_t end_position() const { return position + length; }
};
- Chunk FindChunk(size_t position) {
- while (V8_UNLIKELY(chunks_.empty())) FetchChunk(size_t{0});
+ Chunk FindChunk(size_t position, RuntimeCallStats* stats) {
+ while (V8_UNLIKELY(chunks_.empty())) FetchChunk(size_t{0}, stats);
// Walk forwards while the position is in front of the current chunk.
while (position >= chunks_.back().end_position() &&
chunks_.back().length > 0) {
- FetchChunk(chunks_.back().end_position());
+ FetchChunk(chunks_.back().end_position(), stats);
}
// Walk backwards.
@@ -142,11 +212,11 @@ class ChunkedStream {
length / sizeof(Char));
}
- void FetchChunk(size_t position) {
+ void FetchChunk(size_t position, RuntimeCallStats* stats) {
const uint8_t* data = nullptr;
size_t length;
{
- RuntimeCallTimerScope scope(stats_,
+ RuntimeCallTimerScope scope(stats,
RuntimeCallCounterId::kGetMoreDataCallback);
length = source_->GetMoreData(&data);
}
@@ -154,102 +224,11 @@ class ChunkedStream {
}
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).
@@ -261,6 +240,16 @@ class BufferedCharacterStream : public Utf16CharacterStream {
buffer_pos_ = pos;
}
+ bool can_be_cloned() const final {
+ return ByteStream<uint16_t>::kCanBeCloned;
+ }
+
+ std::unique_ptr<Utf16CharacterStream> Clone() const override {
+ CHECK(can_be_cloned());
+ return std::unique_ptr<Utf16CharacterStream>(
+ new BufferedCharacterStream<ByteStream>(*this));
+ }
+
protected:
bool ReadBlock() final {
size_t position = pos();
@@ -268,7 +257,8 @@ class BufferedCharacterStream : public Utf16CharacterStream {
buffer_start_ = &buffer_[0];
buffer_cursor_ = buffer_start_;
- Range<uint8_t> range = byte_stream_.GetDataAt(position);
+ Range<uint8_t> range =
+ byte_stream_.GetDataAt(position, runtime_call_stats());
if (range.length() == 0) {
buffer_end_ = buffer_start_;
return false;
@@ -280,9 +270,14 @@ class BufferedCharacterStream : public Utf16CharacterStream {
return true;
}
- bool can_access_heap() final { return ByteStream<uint8_t>::kCanAccessHeap; }
+ bool can_access_heap() const final {
+ return ByteStream<uint8_t>::kCanAccessHeap;
+ }
private:
+ BufferedCharacterStream(const BufferedCharacterStream<ByteStream>& other)
+ : byte_stream_(other.byte_stream_) {}
+
static const size_t kBufferSize = 512;
uc16 buffer_[kBufferSize];
ByteStream<uint8_t> byte_stream_;
@@ -298,11 +293,25 @@ class UnbufferedCharacterStream : public Utf16CharacterStream {
buffer_pos_ = pos;
}
+ bool can_access_heap() const final {
+ return ByteStream<uint16_t>::kCanAccessHeap;
+ }
+
+ bool can_be_cloned() const final {
+ return ByteStream<uint16_t>::kCanBeCloned;
+ }
+
+ std::unique_ptr<Utf16CharacterStream> Clone() const override {
+ return std::unique_ptr<Utf16CharacterStream>(
+ new UnbufferedCharacterStream<ByteStream>(*this));
+ }
+
protected:
bool ReadBlock() final {
size_t position = pos();
buffer_pos_ = position;
- Range<uint16_t> range = byte_stream_.GetDataAt(position);
+ Range<uint16_t> range =
+ byte_stream_.GetDataAt(position, runtime_call_stats());
buffer_start_ = range.start;
buffer_end_ = range.end;
buffer_cursor_ = buffer_start_;
@@ -313,7 +322,8 @@ class UnbufferedCharacterStream : public Utf16CharacterStream {
return true;
}
- bool can_access_heap() final { return ByteStream<uint16_t>::kCanAccessHeap; }
+ UnbufferedCharacterStream(const UnbufferedCharacterStream<ByteStream>& other)
+ : byte_stream_(other.byte_stream_) {}
ByteStream<uint16_t> byte_stream_;
};
@@ -346,7 +356,7 @@ class RelocatingCharacterStream
}
void UpdateBufferPointers() {
- Range<uint16_t> range = byte_stream_.GetDataAt(0);
+ Range<uint16_t> range = byte_stream_.GetDataAt(0, runtime_call_stats());
if (range.start != buffer_start_) {
buffer_cursor_ = (buffer_cursor_ - buffer_start_) + range.start;
buffer_start_ = range.start;
@@ -412,16 +422,20 @@ bool BufferedUtf16CharacterStream::ReadBlock() {
class Utf8ExternalStreamingStream : public BufferedUtf16CharacterStream {
public:
Utf8ExternalStreamingStream(
- ScriptCompiler::ExternalSourceStream* source_stream,
- RuntimeCallStats* stats)
+ ScriptCompiler::ExternalSourceStream* source_stream)
: current_({0, {0, 0, 0, unibrow::Utf8::State::kAccept}}),
- source_stream_(source_stream),
- stats_(stats) {}
+ source_stream_(source_stream) {}
~Utf8ExternalStreamingStream() final {
for (size_t i = 0; i < chunks_.size(); i++) delete[] chunks_[i].data;
}
- bool can_access_heap() final { return false; }
+ bool can_access_heap() const final { return false; }
+
+ bool can_be_cloned() const final { return false; }
+
+ std::unique_ptr<Utf16CharacterStream> Clone() const override {
+ UNREACHABLE();
+ }
protected:
size_t FillBuffer(size_t position) final;
@@ -468,7 +482,6 @@ class Utf8ExternalStreamingStream : public BufferedUtf16CharacterStream {
std::vector<Chunk> chunks_;
Position current_;
ScriptCompiler::ExternalSourceStream* source_stream_;
- RuntimeCallStats* stats_;
};
bool Utf8ExternalStreamingStream::SkipToPosition(size_t position) {
@@ -562,7 +575,7 @@ void Utf8ExternalStreamingStream::FillBufferFromCurrentChunk() {
}
bool Utf8ExternalStreamingStream::FetchChunk() {
- RuntimeCallTimerScope scope(stats_,
+ RuntimeCallTimerScope scope(runtime_call_stats(),
RuntimeCallCounterId::kGetMoreDataCallback);
DCHECK_EQ(current_.chunk_no, chunks_.size());
DCHECK(chunks_.empty() || chunks_.back().length != 0);
@@ -704,14 +717,12 @@ Utf16CharacterStream* ScannerStream::For(Isolate* isolate, Handle<String> data,
}
if (data->IsExternalOneByteString()) {
return new BufferedCharacterStream<ExternalStringStream>(
- static_cast<size_t>(start_pos),
- ExternalOneByteString::cast(*data)->GetChars() + start_offset,
- static_cast<size_t>(end_pos));
+ static_cast<size_t>(start_pos), ExternalOneByteString::cast(*data),
+ start_offset, static_cast<size_t>(end_pos));
} else if (data->IsExternalTwoByteString()) {
return new UnbufferedCharacterStream<ExternalStringStream>(
- static_cast<size_t>(start_pos),
- ExternalTwoByteString::cast(*data)->GetChars() + start_offset,
- static_cast<size_t>(end_pos));
+ static_cast<size_t>(start_pos), ExternalTwoByteString::cast(*data),
+ start_offset, static_cast<size_t>(end_pos));
} else if (data->IsSeqOneByteString()) {
return new BufferedCharacterStream<OnHeapStream>(
static_cast<size_t>(start_pos), Handle<SeqOneByteString>::cast(data),
@@ -734,24 +745,23 @@ 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<ExternalStringStream>(
+ new BufferedCharacterStream<TestingStream>(
static_cast<size_t>(0), reinterpret_cast<const uint8_t*>(data),
static_cast<size_t>(length)));
}
Utf16CharacterStream* ScannerStream::For(
ScriptCompiler::ExternalSourceStream* source_stream,
- v8::ScriptCompiler::StreamedSource::Encoding encoding,
- RuntimeCallStats* stats) {
+ v8::ScriptCompiler::StreamedSource::Encoding encoding) {
switch (encoding) {
case v8::ScriptCompiler::StreamedSource::TWO_BYTE:
return new UnbufferedCharacterStream<ChunkedStream>(
- static_cast<size_t>(0), source_stream, stats);
+ static_cast<size_t>(0), source_stream);
case v8::ScriptCompiler::StreamedSource::ONE_BYTE:
return new BufferedCharacterStream<ChunkedStream>(static_cast<size_t>(0),
- source_stream, stats);
+ source_stream);
case v8::ScriptCompiler::StreamedSource::UTF8:
- return new Utf8ExternalStreamingStream(source_stream, stats);
+ return new Utf8ExternalStreamingStream(source_stream);
}
UNREACHABLE();
}
diff --git a/deps/v8/src/parsing/scanner-character-streams.h b/deps/v8/src/parsing/scanner-character-streams.h
index 091ef5b8ea..4c85f5383f 100644
--- a/deps/v8/src/parsing/scanner-character-streams.h
+++ b/deps/v8/src/parsing/scanner-character-streams.h
@@ -24,8 +24,7 @@ class V8_EXPORT_PRIVATE ScannerStream {
int start_pos, int end_pos);
static Utf16CharacterStream* For(
ScriptCompiler::ExternalSourceStream* source_stream,
- ScriptCompiler::StreamedSource::Encoding encoding,
- RuntimeCallStats* stats);
+ ScriptCompiler::StreamedSource::Encoding encoding);
static std::unique_ptr<Utf16CharacterStream> ForTesting(const char* data);
static std::unique_ptr<Utf16CharacterStream> ForTesting(const char* data,
diff --git a/deps/v8/src/parsing/scanner-inl.h b/deps/v8/src/parsing/scanner-inl.h
index 809ef655a7..9647957062 100644
--- a/deps/v8/src/parsing/scanner-inl.h
+++ b/deps/v8/src/parsing/scanner-inl.h
@@ -5,25 +5,354 @@
#ifndef V8_PARSING_SCANNER_INL_H_
#define V8_PARSING_SCANNER_INL_H_
+#include "src/char-predicates-inl.h"
#include "src/parsing/scanner.h"
#include "src/unicode-cache-inl.h"
namespace v8 {
namespace internal {
+// Make sure tokens are stored as a single byte.
+STATIC_ASSERT(sizeof(Token::Value) == 1);
+
+// Table of one-character tokens, by character (0x00..0x7F only).
+// clang-format off
+static const Token::Value one_char_tokens[] = {
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LPAREN, // 0x28
+ Token::RPAREN, // 0x29
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COMMA, // 0x2C
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COLON, // 0x3A
+ Token::SEMICOLON, // 0x3B
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::CONDITIONAL, // 0x3F
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACK, // 0x5B
+ Token::ILLEGAL,
+ Token::RBRACK, // 0x5D
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACE, // 0x7B
+ Token::ILLEGAL,
+ Token::RBRACE, // 0x7D
+ Token::BIT_NOT, // 0x7E
+ Token::ILLEGAL
+};
+// clang-format on
+
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('a') \
+ KEYWORD("arguments", Token::ARGUMENTS) \
+ KEYWORD("as", Token::AS) \
+ KEYWORD("async", Token::ASYNC) \
+ KEYWORD("await", Token::AWAIT) \
+ KEYWORD("anonymous", Token::ANONYMOUS) \
+ KEYWORD_GROUP('b') \
+ KEYWORD("break", Token::BREAK) \
+ KEYWORD_GROUP('c') \
+ KEYWORD("case", Token::CASE) \
+ KEYWORD("catch", Token::CATCH) \
+ KEYWORD("class", Token::CLASS) \
+ KEYWORD("const", Token::CONST) \
+ KEYWORD("constructor", Token::CONSTRUCTOR) \
+ KEYWORD("continue", Token::CONTINUE) \
+ KEYWORD_GROUP('d') \
+ KEYWORD("debugger", Token::DEBUGGER) \
+ KEYWORD("default", Token::DEFAULT) \
+ KEYWORD("delete", Token::DELETE) \
+ KEYWORD("do", Token::DO) \
+ KEYWORD_GROUP('e') \
+ KEYWORD("else", Token::ELSE) \
+ KEYWORD("enum", Token::ENUM) \
+ KEYWORD("eval", Token::EVAL) \
+ KEYWORD("export", Token::EXPORT) \
+ KEYWORD("extends", Token::EXTENDS) \
+ KEYWORD_GROUP('f') \
+ KEYWORD("false", Token::FALSE_LITERAL) \
+ KEYWORD("finally", Token::FINALLY) \
+ KEYWORD("for", Token::FOR) \
+ KEYWORD("from", Token::FROM) \
+ KEYWORD("function", Token::FUNCTION) \
+ KEYWORD_GROUP('g') \
+ KEYWORD("get", Token::GET) \
+ KEYWORD_GROUP('i') \
+ KEYWORD("if", Token::IF) \
+ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("import", Token::IMPORT) \
+ KEYWORD("in", Token::IN) \
+ KEYWORD("instanceof", Token::INSTANCEOF) \
+ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('l') \
+ KEYWORD("let", Token::LET) \
+ KEYWORD_GROUP('m') \
+ KEYWORD("meta", Token::META) \
+ KEYWORD_GROUP('n') \
+ KEYWORD("name", Token::NAME) \
+ KEYWORD("new", Token::NEW) \
+ KEYWORD("null", Token::NULL_LITERAL) \
+ KEYWORD_GROUP('o') \
+ KEYWORD("of", Token::OF) \
+ KEYWORD_GROUP('p') \
+ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("prototype", Token::PROTOTYPE) \
+ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('r') \
+ KEYWORD("return", Token::RETURN) \
+ KEYWORD_GROUP('s') \
+ KEYWORD("set", Token::SET) \
+ KEYWORD("static", Token::STATIC) \
+ KEYWORD("super", Token::SUPER) \
+ KEYWORD("switch", Token::SWITCH) \
+ KEYWORD_GROUP('t') \
+ KEYWORD("target", Token::TARGET) \
+ KEYWORD("this", Token::THIS) \
+ KEYWORD("throw", Token::THROW) \
+ KEYWORD("true", Token::TRUE_LITERAL) \
+ KEYWORD("try", Token::TRY) \
+ KEYWORD("typeof", Token::TYPEOF) \
+ KEYWORD_GROUP('u') \
+ KEYWORD("undefined", Token::UNDEFINED) \
+ KEYWORD_GROUP('v') \
+ KEYWORD("var", Token::VAR) \
+ KEYWORD("void", Token::VOID) \
+ KEYWORD_GROUP('w') \
+ KEYWORD("while", Token::WHILE) \
+ KEYWORD("with", Token::WITH) \
+ KEYWORD_GROUP('y') \
+ KEYWORD("yield", Token::YIELD) \
+ KEYWORD_GROUP('_') \
+ KEYWORD("__proto__", Token::PROTO_UNDERSCORED) \
+ KEYWORD_GROUP('#') \
+ KEYWORD("#constructor", Token::PRIVATE_CONSTRUCTOR)
+
+V8_INLINE Token::Value KeywordOrIdentifierToken(const uint8_t* input,
+ int input_length) {
+ DCHECK_GE(input_length, 1);
+ const int kMinLength = 2;
+ const int kMaxLength = 12;
+ if (input_length < kMinLength || input_length > kMaxLength) {
+ return Token::IDENTIFIER;
+ }
+ switch (input[0]) {
+ default:
+#define KEYWORD_GROUP_CASE(ch) \
+ break; \
+ case ch:
+#define KEYWORD(keyword, token) \
+ { \
+ /* 'keyword' is a char array, so sizeof(keyword) is */ \
+ /* strlen(keyword) plus 1 for the NUL char. */ \
+ const int keyword_length = sizeof(keyword) - 1; \
+ STATIC_ASSERT(keyword_length >= kMinLength); \
+ STATIC_ASSERT(keyword_length <= kMaxLength); \
+ DCHECK_EQ(input[0], keyword[0]); \
+ DCHECK(token == Token::FUTURE_STRICT_RESERVED_WORD || \
+ 0 == strncmp(keyword, Token::String(token), sizeof(keyword))); \
+ if (input_length == keyword_length && input[1] == keyword[1] && \
+ (keyword_length <= 2 || input[2] == keyword[2]) && \
+ (keyword_length <= 3 || input[3] == keyword[3]) && \
+ (keyword_length <= 4 || input[4] == keyword[4]) && \
+ (keyword_length <= 5 || input[5] == keyword[5]) && \
+ (keyword_length <= 6 || input[6] == keyword[6]) && \
+ (keyword_length <= 7 || input[7] == keyword[7]) && \
+ (keyword_length <= 8 || input[8] == keyword[8]) && \
+ (keyword_length <= 9 || input[9] == keyword[9]) && \
+ (keyword_length <= 10 || input[10] == keyword[10])) { \
+ return token; \
+ } \
+ }
+ KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
+ }
+ return Token::IDENTIFIER;
+#undef KEYWORDS
+#undef KEYWORD
+#undef KEYWORD_GROUP_CASE
+}
+
+V8_INLINE Token::Value Scanner::ScanIdentifierOrKeyword() {
+ LiteralScope literal(this);
+ return ScanIdentifierOrKeywordInner(&literal);
+}
+
+V8_INLINE Token::Value Scanner::ScanIdentifierOrKeywordInner(
+ LiteralScope* literal) {
+ DCHECK(unicode_cache_->IsIdentifierStart(c0_));
+ bool escaped = false;
+ if (IsInRange(c0_, 'a', 'z') || c0_ == '_') {
+ do {
+ 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 {
+ AddLiteralChar(static_cast<char>(c0_));
+ Advance();
+ } while (IsAsciiIdentifier(c0_));
+
+ if (c0_ <= kMaxAscii && c0_ != '\\') {
+ literal->Complete();
+ return Token::IDENTIFIER;
+ }
+ } 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();
+ Token::Value token =
+ KeywordOrIdentifierToken(chars.start(), chars.length());
+ if (token == Token::IDENTIFIER ||
+ token == Token::FUTURE_STRICT_RESERVED_WORD ||
+ Token::IsContextualKeyword(token))
+ literal->Complete();
+ return token;
+ }
+ } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '$') {
+ do {
+ AddLiteralChar(static_cast<char>(c0_));
+ Advance();
+ } while (IsAsciiIdentifier(c0_));
+
+ if (c0_ <= kMaxAscii && c0_ != '\\') {
+ literal->Complete();
+ return Token::IDENTIFIER;
+ }
+ } else if (c0_ == '\\') {
+ escaped = true;
+ uc32 c = ScanIdentifierUnicodeEscape();
+ DCHECK(!unicode_cache_->IsIdentifierStart(-1));
+ if (c == '\\' || !unicode_cache_->IsIdentifierStart(c)) {
+ return Token::ILLEGAL;
+ }
+ AddLiteralChar(c);
+ }
+
+ return ScanIdentifierOrKeywordInnerSlow(literal, escaped);
+}
+
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));
+ // We won't skip behind the end of input.
+ DCHECK(!unicode_cache_->IsWhiteSpaceOrLineTerminator(kEndOfInput));
- // Advance as long as character is a WhiteSpace or LineTerminator.
- // Remember if the latter is the case.
- if (unibrow::IsLineTerminator(c0_)) {
+ // Advance as long as character is a WhiteSpace or LineTerminator.
+ while (unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_)) {
+ if (!next().after_line_terminator && unibrow::IsLineTerminator(c0_)) {
next().after_line_terminator = true;
- } else if (!unicode_cache_->IsWhiteSpace(c0_)) {
- break;
}
Advance();
}
@@ -37,6 +366,191 @@ V8_INLINE Token::Value Scanner::SkipWhiteSpace() {
return Token::WHITESPACE;
}
+V8_INLINE Token::Value Scanner::ScanSingleToken() {
+ Token::Value token;
+ do {
+ next().location.beg_pos = source_pos();
+
+ if (static_cast<unsigned>(c0_) <= 0x7F) {
+ Token::Value token = one_char_tokens[c0_];
+ if (token != Token::ILLEGAL) {
+ Advance();
+ return token;
+ }
+ }
+
+ switch (c0_) {
+ case '"':
+ case '\'':
+ return ScanString();
+
+ case '<':
+ // < <= << <<= <!--
+ Advance();
+ if (c0_ == '=') return Select(Token::LTE);
+ if (c0_ == '<') return Select('=', Token::ASSIGN_SHL, Token::SHL);
+ if (c0_ == '!') {
+ token = ScanHtmlComment();
+ continue;
+ }
+ return Token::LT;
+
+ case '>':
+ // > >= >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') return Select(Token::GTE);
+ if (c0_ == '>') {
+ // >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') return Select(Token::ASSIGN_SAR);
+ if (c0_ == '>') return Select('=', Token::ASSIGN_SHR, Token::SHR);
+ return Token::SAR;
+ }
+ return Token::GT;
+
+ case '=':
+ // = == === =>
+ Advance();
+ if (c0_ == '=') return Select('=', Token::EQ_STRICT, Token::EQ);
+ if (c0_ == '>') return Select(Token::ARROW);
+ return Token::ASSIGN;
+
+ case '!':
+ // ! != !==
+ Advance();
+ if (c0_ == '=') return Select('=', Token::NE_STRICT, Token::NE);
+ return Token::NOT;
+
+ case '+':
+ // + ++ +=
+ Advance();
+ if (c0_ == '+') return Select(Token::INC);
+ if (c0_ == '=') return Select(Token::ASSIGN_ADD);
+ return Token::ADD;
+
+ case '-':
+ // - -- --> -=
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '>' && next().after_line_terminator) {
+ // For compatibility with SpiderMonkey, we skip lines that
+ // start with an HTML comment end '-->'.
+ token = SkipSingleHTMLComment();
+ continue;
+ }
+ return Token::DEC;
+ }
+ if (c0_ == '=') return Select(Token::ASSIGN_SUB);
+ return Token::SUB;
+
+ case '*':
+ // * *=
+ Advance();
+ if (c0_ == '*') return Select('=', Token::ASSIGN_EXP, Token::EXP);
+ if (c0_ == '=') return Select(Token::ASSIGN_MUL);
+ return Token::MUL;
+
+ case '%':
+ // % %=
+ return Select('=', Token::ASSIGN_MOD, Token::MOD);
+
+ case '/':
+ // / // /* /=
+ Advance();
+ if (c0_ == '/') {
+ uc32 c = Peek();
+ if (c == '#' || c == '@') {
+ Advance();
+ Advance();
+ token = SkipSourceURLComment();
+ continue;
+ }
+ token = SkipSingleLineComment();
+ continue;
+ }
+ if (c0_ == '*') {
+ token = SkipMultiLineComment();
+ continue;
+ }
+ if (c0_ == '=') return Select(Token::ASSIGN_DIV);
+ return Token::DIV;
+
+ case '&':
+ // & && &=
+ Advance();
+ if (c0_ == '&') return Select(Token::AND);
+ if (c0_ == '=') return Select(Token::ASSIGN_BIT_AND);
+ return Token::BIT_AND;
+
+ case '|':
+ // | || |=
+ Advance();
+ if (c0_ == '|') return Select(Token::OR);
+ if (c0_ == '=') return Select(Token::ASSIGN_BIT_OR);
+ return Token::BIT_OR;
+
+ case '^':
+ // ^ ^=
+ return Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
+
+ case '.':
+ // . Number
+ Advance();
+ if (IsDecimalDigit(c0_)) return ScanNumber(true);
+ if (c0_ == '.') {
+ if (Peek() == '.') {
+ Advance();
+ Advance();
+ return Token::ELLIPSIS;
+ }
+ }
+ return Token::PERIOD;
+
+ case '`':
+ Advance();
+ return ScanTemplateSpan();
+
+ case '#':
+ return ScanPrivateName();
+
+ default:
+ if (unicode_cache_->IsIdentifierStart(c0_) ||
+ (CombineSurrogatePair() &&
+ unicode_cache_->IsIdentifierStart(c0_))) {
+ Token::Value token = ScanIdentifierOrKeyword();
+ if (!Token::IsContextualKeyword(token)) return token;
+
+ next().contextual_token = token;
+ return Token::IDENTIFIER;
+ }
+ if (IsDecimalDigit(c0_)) return ScanNumber(false);
+ if (c0_ == kEndOfInput) return Token::EOS;
+ token = SkipWhiteSpace();
+ continue;
+ }
+ // Continue scanning for tokens as long as we're just skipping whitespace.
+ } while (token == Token::WHITESPACE);
+
+ return token;
+}
+
+void Scanner::Scan() {
+ next().literal_chars.Drop();
+ next().raw_literal_chars.Drop();
+ next().contextual_token = Token::UNINITIALIZED;
+ next().invalid_template_escape_message = MessageTemplate::kNone;
+
+ next().token = ScanSingleToken();
+ next().location.end_pos = source_pos();
+
+#ifdef DEBUG
+ SanityCheckTokenDesc(current());
+ SanityCheckTokenDesc(next());
+ SanityCheckTokenDesc(next_next());
+#endif
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc
index 781832c2e6..525b1bc681 100644
--- a/deps/v8/src/parsing/scanner.cc
+++ b/deps/v8/src/parsing/scanner.cc
@@ -11,7 +11,6 @@
#include <cmath>
#include "src/ast/ast-value-factory.h"
-#include "src/char-predicates-inl.h"
#include "src/conversions-inl.h"
#include "src/objects/bigint.h"
#include "src/parsing/duplicate-finder.h" // For Scanner::FindSymbol
@@ -134,7 +133,6 @@ const size_t Scanner::BookmarkScope::kBookmarkWasApplied =
void Scanner::BookmarkScope::Set() {
DCHECK_EQ(bookmark_, kNoBookmark);
- 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
@@ -160,11 +158,11 @@ void Scanner::BookmarkScope::Apply() {
bookmark_ = kBookmarkWasApplied;
}
-bool Scanner::BookmarkScope::HasBeenSet() {
+bool Scanner::BookmarkScope::HasBeenSet() const {
return bookmark_ != kNoBookmark && bookmark_ != kBookmarkWasApplied;
}
-bool Scanner::BookmarkScope::HasBeenApplied() {
+bool Scanner::BookmarkScope::HasBeenApplied() const {
return bookmark_ == kBookmarkWasApplied;
}
@@ -175,12 +173,11 @@ 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),
- is_module_(is_module) {
+ is_module_(is_module),
+ octal_pos_(Location::invalid()),
+ octal_message_(MessageTemplate::kNone) {
DCHECK_NOT_NULL(source);
}
@@ -234,146 +231,7 @@ uc32 Scanner::ScanUnlimitedLengthHexNumber(int max_value, int beg_pos) {
return x;
}
-
-// Ensure that tokens can be stored in a byte.
-STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
-
-// Table of one-character tokens, by character (0x00..0x7F only).
-// clang-format off
-static const byte one_char_tokens[] = {
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LPAREN, // 0x28
- Token::RPAREN, // 0x29
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::COMMA, // 0x2C
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::COLON, // 0x3A
- Token::SEMICOLON, // 0x3B
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::CONDITIONAL, // 0x3F
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LBRACK, // 0x5B
- Token::ILLEGAL,
- Token::RBRACK, // 0x5D
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LBRACE, // 0x7B
- Token::ILLEGAL,
- Token::RBRACE, // 0x7D
- Token::BIT_NOT, // 0x7E
- Token::ILLEGAL
-};
-// clang-format on
-
Token::Value Scanner::Next() {
- if (next().token == Token::EOS) next().location = current().location;
// Rotate through tokens.
TokenDesc* previous = current_;
current_ = next_;
@@ -395,7 +253,6 @@ Token::Value Scanner::Next() {
return current().token;
}
-
Token::Value Scanner::PeekAhead() {
DCHECK(next().token != Token::DIV);
DCHECK(next().token != Token::ASSIGN_DIV);
@@ -534,250 +391,6 @@ Token::Value Scanner::ScanHtmlComment() {
return SkipSingleHTMLComment();
}
-void Scanner::Scan() {
- next().literal_chars.Drop();
- next().raw_literal_chars.Drop();
- next().invalid_template_escape_message = MessageTemplate::kNone;
-
- Token::Value token;
- do {
- if (static_cast<unsigned>(c0_) <= 0x7F) {
- 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;
- Advance();
- return;
- }
- }
-
- // Remember the position of the next token
- next().location.beg_pos = source_pos();
-
- switch (c0_) {
- case '"':
- case '\'':
- token = ScanString();
- break;
-
- case '<':
- // < <= << <<= <!--
- Advance();
- if (c0_ == '=') {
- token = Select(Token::LTE);
- } else if (c0_ == '<') {
- token = Select('=', Token::ASSIGN_SHL, Token::SHL);
- } else if (c0_ == '!') {
- token = ScanHtmlComment();
- } else {
- token = Token::LT;
- }
- break;
-
- case '>':
- // > >= >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') {
- token = Select(Token::GTE);
- } else if (c0_ == '>') {
- // >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') {
- token = Select(Token::ASSIGN_SAR);
- } else if (c0_ == '>') {
- token = Select('=', Token::ASSIGN_SHR, Token::SHR);
- } else {
- token = Token::SAR;
- }
- } else {
- token = Token::GT;
- }
- break;
-
- case '=':
- // = == === =>
- Advance();
- if (c0_ == '=') {
- token = Select('=', Token::EQ_STRICT, Token::EQ);
- } else if (c0_ == '>') {
- token = Select(Token::ARROW);
- } else {
- token = Token::ASSIGN;
- }
- break;
-
- case '!':
- // ! != !==
- Advance();
- if (c0_ == '=') {
- token = Select('=', Token::NE_STRICT, Token::NE);
- } else {
- token = Token::NOT;
- }
- break;
-
- case '+':
- // + ++ +=
- Advance();
- if (c0_ == '+') {
- token = Select(Token::INC);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_ADD);
- } else {
- token = Token::ADD;
- }
- break;
-
- case '-':
- // - -- --> -=
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '>' && HasLineTerminatorBeforeNext()) {
- // For compatibility with SpiderMonkey, we skip lines that
- // start with an HTML comment end '-->'.
- token = SkipSingleHTMLComment();
- } else {
- token = Token::DEC;
- }
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_SUB);
- } else {
- token = Token::SUB;
- }
- break;
-
- case '*':
- // * *=
- Advance();
- if (c0_ == '*') {
- token = Select('=', Token::ASSIGN_EXP, Token::EXP);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_MUL);
- } else {
- token = Token::MUL;
- }
- break;
-
- case '%':
- // % %=
- token = Select('=', Token::ASSIGN_MOD, Token::MOD);
- break;
-
- case '/':
- // / // /* /=
- Advance();
- if (c0_ == '/') {
- uc32 c = Peek();
- if (c == '#' || c == '@') {
- Advance();
- Advance();
- token = SkipSourceURLComment();
- } else {
- token = SkipSingleLineComment();
- }
- } else if (c0_ == '*') {
- token = SkipMultiLineComment();
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_DIV);
- } else {
- token = Token::DIV;
- }
- break;
-
- case '&':
- // & && &=
- Advance();
- if (c0_ == '&') {
- token = Select(Token::AND);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_BIT_AND);
- } else {
- token = Token::BIT_AND;
- }
- break;
-
- case '|':
- // | || |=
- Advance();
- if (c0_ == '|') {
- token = Select(Token::OR);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_BIT_OR);
- } else {
- token = Token::BIT_OR;
- }
- break;
-
- case '^':
- // ^ ^=
- token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
- break;
-
- case '.':
- // . Number
- Advance();
- if (IsDecimalDigit(c0_)) {
- token = ScanNumber(true);
- } else {
- token = Token::PERIOD;
- if (c0_ == '.') {
- if (Peek() == '.') {
- Advance();
- Advance();
- token = Token::ELLIPSIS;
- }
- }
- }
- break;
-
- case '`':
- token = ScanTemplateStart();
- break;
-
- case '#':
- token = ScanPrivateName();
- break;
-
- default:
- if (unicode_cache_->IsIdentifierStart(c0_) ||
- (CombineSurrogatePair() &&
- unicode_cache_->IsIdentifierStart(c0_))) {
- token = ScanIdentifierOrKeyword();
- } else if (IsDecimalDigit(c0_)) {
- token = ScanNumber(false);
- } else if (c0_ == kEndOfInput) {
- token = Token::EOS;
- } else {
- token = SkipWhiteSpace();
- if (token == Token::ILLEGAL) Advance();
- }
- break;
- }
-
- // Continue scanning for tokens as long as we're just skipping
- // whitespace.
- } while (token == Token::WHITESPACE);
-
- next().location.end_pos = source_pos();
- if (Token::IsContextualKeyword(token)) {
- next().token = Token::IDENTIFIER;
- next().contextual_token = token;
- } else {
- next().token = token;
- next().contextual_token = Token::UNINITIALIZED;
- }
-
-#ifdef DEBUG
- SanityCheckTokenDesc(current());
- SanityCheckTokenDesc(next());
- SanityCheckTokenDesc(next_next());
-#endif
-}
-
#ifdef DEBUG
void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const {
// Most tokens should not have literal_chars or even raw_literal chars.
@@ -916,7 +529,7 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
// can be reported later (in strict mode).
// We don't report the error immediately, because the octal escape can
// occur before the "use strict" directive.
- if (c != '0' || i > 0 || c0_ == '8' || c0_ == '9') {
+ if (c != '0' || i > 0 || IsNonOctalDecimalDigit(c0_)) {
octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
octal_message_ = capture_raw ? MessageTemplate::kTemplateOctalLiteral
: MessageTemplate::kStrictOctalEscape;
@@ -993,7 +606,7 @@ Token::Value Scanner::ScanTemplateSpan() {
Token::Value result = Token::TEMPLATE_SPAN;
LiteralScope literal(this);
- StartRawLiteral();
+ next().raw_literal_chars.Start();
const bool capture_raw = true;
while (true) {
uc32 c = c0_;
@@ -1053,14 +666,6 @@ Token::Value Scanner::ScanTemplateSpan() {
return result;
}
-Token::Value Scanner::ScanTemplateStart() {
- DCHECK_EQ(next_next().token, Token::UNINITIALIZED);
- DCHECK_EQ(c0_, '`');
- 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) {
@@ -1200,11 +805,11 @@ bool Scanner::ScanImplicitOctalDigits(int start_pos,
while (true) {
// (possible) octal number
- if (c0_ == '8' || c0_ == '9') {
+ if (IsNonOctalDecimalDigit(c0_)) {
*kind = DECIMAL_WITH_LEADING_ZERO;
return true;
}
- if (c0_ < '0' || '7' < c0_) {
+ if (!IsOctalDigit(c0_)) {
// Octal literal finished.
octal_pos_ = Location(start_pos, source_pos());
octal_message_ = MessageTemplate::kStrictOctalLiteral;
@@ -1272,7 +877,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
AddLiteralCharAdvance();
kind = BINARY;
if (!ScanBinaryDigits()) return Token::ILLEGAL;
- } else if ('0' <= c0_ && c0_ <= '7') {
+ } else if (IsOctalDigit(c0_)) {
kind = IMPLICIT_OCTAL;
if (!ScanImplicitOctalDigits(start_pos, &kind)) {
return Token::ILLEGAL;
@@ -1280,7 +885,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
if (kind == DECIMAL_WITH_LEADING_ZERO) {
at_start = false;
}
- } else if (c0_ == '8' || c0_ == '9') {
+ } else if (IsNonOctalDecimalDigit(c0_)) {
kind = DECIMAL_WITH_LEADING_ZERO;
} else if (allow_harmony_numeric_separator() && c0_ == '_') {
ReportScannerError(Location(source_pos(), source_pos() + 1),
@@ -1326,7 +931,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
}
bool is_bigint = false;
- if (allow_harmony_bigint() && c0_ == 'n' && !seen_period &&
+ if (c0_ == 'n' && !seen_period &&
(kind == DECIMAL || kind == HEX || kind == OCTAL || kind == BINARY)) {
// Check that the literal is within our limits for BigInt length.
// For simplicity, use 4 bits per character to calculate the maximum
@@ -1399,197 +1004,8 @@ uc32 Scanner::ScanUnicodeEscape() {
return ScanHexNumber<capture_raw, unicode>(4);
}
-
-// ----------------------------------------------------------------------------
-// Keyword Matcher
-
-#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
- KEYWORD_GROUP('a') \
- KEYWORD("arguments", Token::ARGUMENTS) \
- KEYWORD("as", Token::AS) \
- KEYWORD("async", Token::ASYNC) \
- KEYWORD("await", Token::AWAIT) \
- KEYWORD("anonymous", Token::ANONYMOUS) \
- KEYWORD_GROUP('b') \
- KEYWORD("break", Token::BREAK) \
- KEYWORD_GROUP('c') \
- KEYWORD("case", Token::CASE) \
- KEYWORD("catch", Token::CATCH) \
- KEYWORD("class", Token::CLASS) \
- KEYWORD("const", Token::CONST) \
- KEYWORD("constructor", Token::CONSTRUCTOR) \
- KEYWORD("continue", Token::CONTINUE) \
- KEYWORD_GROUP('d') \
- KEYWORD("debugger", Token::DEBUGGER) \
- KEYWORD("default", Token::DEFAULT) \
- KEYWORD("delete", Token::DELETE) \
- KEYWORD("do", Token::DO) \
- KEYWORD_GROUP('e') \
- KEYWORD("else", Token::ELSE) \
- KEYWORD("enum", Token::ENUM) \
- KEYWORD("eval", Token::EVAL) \
- KEYWORD("export", Token::EXPORT) \
- KEYWORD("extends", Token::EXTENDS) \
- KEYWORD_GROUP('f') \
- KEYWORD("false", Token::FALSE_LITERAL) \
- KEYWORD("finally", Token::FINALLY) \
- KEYWORD("for", Token::FOR) \
- KEYWORD("from", Token::FROM) \
- KEYWORD("function", Token::FUNCTION) \
- KEYWORD_GROUP('g') \
- KEYWORD("get", Token::GET) \
- KEYWORD_GROUP('i') \
- KEYWORD("if", Token::IF) \
- KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("import", Token::IMPORT) \
- KEYWORD("in", Token::IN) \
- KEYWORD("instanceof", Token::INSTANCEOF) \
- KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('l') \
- KEYWORD("let", Token::LET) \
- KEYWORD_GROUP('m') \
- KEYWORD("meta", Token::META) \
- KEYWORD_GROUP('n') \
- KEYWORD("name", Token::NAME) \
- KEYWORD("new", Token::NEW) \
- KEYWORD("null", Token::NULL_LITERAL) \
- KEYWORD_GROUP('o') \
- KEYWORD("of", Token::OF) \
- KEYWORD_GROUP('p') \
- KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("prototype", Token::PROTOTYPE) \
- KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('r') \
- KEYWORD("return", Token::RETURN) \
- KEYWORD_GROUP('s') \
- KEYWORD("set", Token::SET) \
- KEYWORD("static", Token::STATIC) \
- KEYWORD("super", Token::SUPER) \
- KEYWORD("switch", Token::SWITCH) \
- KEYWORD_GROUP('t') \
- KEYWORD("target", Token::TARGET) \
- KEYWORD("this", Token::THIS) \
- KEYWORD("throw", Token::THROW) \
- KEYWORD("true", Token::TRUE_LITERAL) \
- KEYWORD("try", Token::TRY) \
- KEYWORD("typeof", Token::TYPEOF) \
- KEYWORD_GROUP('u') \
- KEYWORD("undefined", Token::UNDEFINED) \
- KEYWORD_GROUP('v') \
- KEYWORD("var", Token::VAR) \
- KEYWORD("void", Token::VOID) \
- KEYWORD_GROUP('w') \
- KEYWORD("while", Token::WHILE) \
- KEYWORD("with", Token::WITH) \
- KEYWORD_GROUP('y') \
- KEYWORD("yield", Token::YIELD) \
- KEYWORD_GROUP('_') \
- KEYWORD("__proto__", Token::PROTO_UNDERSCORED) \
- KEYWORD_GROUP('#') \
- KEYWORD("#constructor", Token::PRIVATE_CONSTRUCTOR)
-
-static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
- int input_length) {
- DCHECK_GE(input_length, 1);
- const int kMinLength = 2;
- const int kMaxLength = 12;
- if (input_length < kMinLength || input_length > kMaxLength) {
- return Token::IDENTIFIER;
- }
- switch (input[0]) {
- default:
-#define KEYWORD_GROUP_CASE(ch) \
- break; \
- case ch:
-#define KEYWORD(keyword, token) \
- { \
- /* 'keyword' is a char array, so sizeof(keyword) is */ \
- /* strlen(keyword) plus 1 for the NUL char. */ \
- const int keyword_length = sizeof(keyword) - 1; \
- STATIC_ASSERT(keyword_length >= kMinLength); \
- STATIC_ASSERT(keyword_length <= kMaxLength); \
- DCHECK_EQ(input[0], keyword[0]); \
- DCHECK(token == Token::FUTURE_STRICT_RESERVED_WORD || \
- 0 == strncmp(keyword, Token::String(token), sizeof(keyword))); \
- if (input_length == keyword_length && input[1] == keyword[1] && \
- (keyword_length <= 2 || input[2] == keyword[2]) && \
- (keyword_length <= 3 || input[3] == keyword[3]) && \
- (keyword_length <= 4 || input[4] == keyword[4]) && \
- (keyword_length <= 5 || input[5] == keyword[5]) && \
- (keyword_length <= 6 || input[6] == keyword[6]) && \
- (keyword_length <= 7 || input[7] == keyword[7]) && \
- (keyword_length <= 8 || input[8] == keyword[8]) && \
- (keyword_length <= 9 || input[9] == keyword[9]) && \
- (keyword_length <= 10 || input[10] == keyword[10])) { \
- return token; \
- } \
- }
- KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
- }
- return Token::IDENTIFIER;
-#undef KEYWORDS
-#undef KEYWORD
-#undef KEYWORD_GROUP_CASE
-}
-
-Token::Value Scanner::ScanIdentifierOrKeyword() {
- LiteralScope literal(this);
- return ScanIdentifierOrKeywordInner(&literal);
-}
-
-Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) {
- DCHECK(unicode_cache_->IsIdentifierStart(c0_));
- bool escaped = false;
- if (IsInRange(c0_, 'a', 'z') || c0_ == '_') {
- do {
- 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 {
- AddLiteralChar(static_cast<char>(c0_));
- Advance();
- } while (IsAsciiIdentifier(c0_));
-
- if (c0_ <= kMaxAscii && c0_ != '\\') {
- literal->Complete();
- return Token::IDENTIFIER;
- }
- } 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();
- Token::Value token =
- KeywordOrIdentifierToken(chars.start(), chars.length());
- if (token == Token::IDENTIFIER ||
- token == Token::FUTURE_STRICT_RESERVED_WORD ||
- Token::IsContextualKeyword(token))
- literal->Complete();
- return token;
- }
- } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '$') {
- do {
- AddLiteralChar(static_cast<char>(c0_));
- Advance();
- } while (IsAsciiIdentifier(c0_));
-
- if (c0_ <= kMaxAscii && c0_ != '\\') {
- literal->Complete();
- return Token::IDENTIFIER;
- }
- } else if (c0_ == '\\') {
- escaped = true;
- uc32 c = ScanIdentifierUnicodeEscape();
- DCHECK(!unicode_cache_->IsIdentifierStart(-1));
- if (c == '\\' || !unicode_cache_->IsIdentifierStart(c)) {
- return Token::ILLEGAL;
- }
- AddLiteralChar(c);
- }
-
+Token::Value Scanner::ScanIdentifierOrKeywordInnerSlow(LiteralScope* literal,
+ bool escaped) {
while (true) {
if (c0_ == '\\') {
escaped = true;
@@ -1645,18 +1061,12 @@ bool Scanner::ScanRegExpPattern() {
// Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
bool in_character_class = false;
- 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);
// Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
// the scanner should pass uninterpreted bodies to the RegExp
// constructor.
LiteralScope literal(this);
- if (seen_equal) {
+ if (next().token == Token::ASSIGN_DIV) {
AddLiteralChar('=');
}
diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h
index e592debd8e..83002b53c8 100644
--- a/deps/v8/src/parsing/scanner.h
+++ b/deps/v8/src/parsing/scanner.h
@@ -21,13 +21,13 @@
namespace v8 {
namespace internal {
-
class AstRawString;
class AstValueFactory;
class DuplicateFinder;
class ExternalOneByteString;
class ExternalTwoByteString;
class ParserRecorder;
+class RuntimeCallStats;
class UnicodeCache;
// ---------------------------------------------------------------------
@@ -38,7 +38,7 @@ class Utf16CharacterStream {
public:
static const uc32 kEndOfInput = -1;
- virtual ~Utf16CharacterStream() {}
+ virtual ~Utf16CharacterStream() = default;
inline uc32 Peek() {
if (V8_LIKELY(buffer_cursor_ < buffer_end_)) {
@@ -109,8 +109,21 @@ class Utf16CharacterStream {
}
}
+ // Returns true if the stream can be cloned with Clone.
+ // TODO(rmcilroy): Remove this once ChunkedStreams can be cloned.
+ virtual bool can_be_cloned() const = 0;
+
+ // Clones the character stream to enable another independent scanner to access
+ // the same underlying stream.
+ virtual std::unique_ptr<Utf16CharacterStream> Clone() const = 0;
+
// Returns true if the stream could access the V8 heap after construction.
- virtual bool can_access_heap() = 0;
+ virtual bool can_access_heap() const = 0;
+
+ RuntimeCallStats* runtime_call_stats() const { return runtime_call_stats_; }
+ void set_runtime_call_stats(RuntimeCallStats* runtime_call_stats) {
+ runtime_call_stats_ = runtime_call_stats;
+ }
protected:
Utf16CharacterStream(const uint16_t* buffer_start,
@@ -172,6 +185,7 @@ class Utf16CharacterStream {
const uint16_t* buffer_cursor_;
const uint16_t* buffer_end_;
size_t buffer_pos_;
+ RuntimeCallStats* runtime_call_stats_;
};
// ----------------------------------------------------------------------------
@@ -186,12 +200,12 @@ class Scanner {
: scanner_(scanner), bookmark_(kNoBookmark) {
DCHECK_NOT_NULL(scanner_);
}
- ~BookmarkScope() {}
+ ~BookmarkScope() = default;
void Set();
void Apply();
- bool HasBeenSet();
- bool HasBeenApplied();
+ bool HasBeenSet() const;
+ bool HasBeenApplied() const;
private:
static const size_t kNoBookmark;
@@ -233,19 +247,21 @@ class Scanner {
// Returns the token following peek()
Token::Value PeekAhead();
// Returns the current token again.
- Token::Value current_token() { return current().token; }
+ Token::Value current_token() const { 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() const {
+ return current().contextual_token;
+ }
+ Token::Value next_contextual_token() const { return next().contextual_token; }
// Returns the location information for the current token
// (the token last returned by Next()).
- Location location() const { return current().location; }
+ const 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; }
MessageTemplate::Template error() const { return scanner_error_; }
- Location error_location() const { return scanner_error_location_; }
+ const Location& error_location() const { return scanner_error_location_; }
bool has_invalid_template_escape() const {
return current().invalid_template_escape_message != MessageTemplate::kNone;
@@ -264,13 +280,14 @@ class Scanner {
// One token look-ahead (past the token returned by Next()).
Token::Value peek() const { return next().token; }
- Location peek_location() const { return next().location; }
+ const Location& peek_location() const { return next().location; }
bool literal_contains_escapes() const {
return LiteralContainsEscapes(current());
}
const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory) const;
+
const AstRawString* NextSymbol(AstValueFactory* ast_value_factory) const;
const AstRawString* CurrentRawSymbol(
AstValueFactory* ast_value_factory) const;
@@ -286,7 +303,7 @@ class Scanner {
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.
@@ -297,7 +314,7 @@ class Scanner {
// (which was escape-processed already).
// 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) ||
+ return (current_contextual_token() == token) ||
(current().literal_chars.is_used() &&
current().literal_chars.Equals(Vector<const char>(
Token::String(token), Token::StringLength(token))));
@@ -308,11 +325,11 @@ class Scanner {
current().literal_chars.Equals(
Vector<const char>("use strict", strlen("use strict")));
}
- bool IsGetOrSet(bool* is_get, bool* is_set) const {
- *is_get = CurrentMatchesContextual(Token::GET);
- *is_set = CurrentMatchesContextual(Token::SET);
- return *is_get || *is_set;
- }
+
+ bool IsGet() { return CurrentMatchesContextual(Token::GET); }
+
+ bool IsSet() { return CurrentMatchesContextual(Token::SET); }
+
bool IsLet() const {
return CurrentMatches(Token::LET) ||
CurrentMatchesContextualEscaped(Token::LET);
@@ -324,7 +341,7 @@ class Scanner {
bool IsDuplicateSymbol(DuplicateFinder* duplicate_finder,
AstValueFactory* ast_value_factory) const;
- UnicodeCache* unicode_cache() { return unicode_cache_; }
+ UnicodeCache* unicode_cache() const { return unicode_cache_; }
// Returns the location of the last seen octal literal.
Location octal_position() const { return octal_pos_; }
@@ -362,10 +379,9 @@ class Scanner {
Maybe<RegExp::Flags> ScanRegExpFlags();
// 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(source_pos() - 1, next().location.beg_pos);
return ScanTemplateSpan();
}
@@ -374,8 +390,6 @@ class Scanner {
bool FoundHtmlComment() const { return found_html_comment_; }
- bool allow_harmony_bigint() const { return allow_harmony_bigint_; }
- void set_allow_harmony_bigint(bool allow) { allow_harmony_bigint_ = allow; }
bool allow_harmony_private_fields() const {
return allow_harmony_private_fields_;
}
@@ -389,34 +403,19 @@ class Scanner {
allow_harmony_numeric_separator_ = allow;
}
+ const Utf16CharacterStream* stream() const { return source_; }
+
private:
// Scoped helper for saving & restoring scanner error state.
// This is used for tagged template literals, in which normally forbidden
// escape sequences are allowed.
class ErrorState;
- // Scoped helper for literal recording. Automatically drops the literal
- // if aborting the scanning before it's complete.
- class LiteralScope {
- public:
- explicit LiteralScope(Scanner* self) : scanner_(self), complete_(false) {
- scanner_->StartLiteral();
- }
- ~LiteralScope() {
- if (!complete_) scanner_->DropLiteral();
- }
- void Complete() { complete_ = true; }
-
- private:
- Scanner* scanner_;
- bool complete_;
- };
-
// LiteralBuffer - Collector of chars of literals.
class LiteralBuffer {
public:
LiteralBuffer()
- : position_(0), is_one_byte_(true), is_used_(false), backing_store_() {}
+ : backing_store_(), position_(0), is_one_byte_(true), is_used_(false) {}
~LiteralBuffer() { backing_store_.Dispose(); }
@@ -506,14 +505,32 @@ class Scanner {
void ExpandBuffer();
void ConvertToTwoByte();
+ Vector<byte> backing_store_;
int position_;
bool is_one_byte_;
bool is_used_;
- Vector<byte> backing_store_;
DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
};
+ // Scoped helper for literal recording. Automatically drops the literal
+ // if aborting the scanning before it's complete.
+ class LiteralScope {
+ public:
+ explicit LiteralScope(Scanner* scanner)
+ : buffer_(&scanner->next().literal_chars), complete_(false) {
+ buffer_->Start();
+ }
+ ~LiteralScope() {
+ if (!complete_) buffer_->Drop();
+ }
+ void Complete() { complete_ = true; }
+
+ private:
+ LiteralBuffer* buffer_;
+ bool complete_;
+ };
+
// The current and look-ahead token.
struct TokenDesc {
Location location = {0, 0};
@@ -538,7 +555,7 @@ class Scanner {
};
static const int kCharacterLookaheadBufferSize = 1;
- const int kMaxAscii = 127;
+ static const int kMaxAscii = 127;
// Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
template <bool capture_raw>
@@ -574,11 +591,6 @@ class Scanner {
// Seek to the next_ token at the given position.
void SeekNext(size_t position);
- // Literal buffer support
- inline void StartLiteral() { next().literal_chars.Start(); }
-
- inline void StartRawLiteral() { next().raw_literal_chars.Start(); }
-
V8_INLINE void AddLiteralChar(uc32 c) { next().literal_chars.AddChar(c); }
V8_INLINE void AddLiteralChar(char c) { next().literal_chars.AddChar(c); }
@@ -587,14 +599,7 @@ class Scanner {
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.Drop();
- next().raw_literal_chars.Drop();
- }
-
- inline void AddLiteralCharAdvance() {
+ V8_INLINE void AddLiteralCharAdvance() {
AddLiteralChar(c0_);
Advance();
}
@@ -714,7 +719,8 @@ class Scanner {
uc32 ScanUnlimitedLengthHexNumber(int max_value, int beg_pos);
// Scans a single JavaScript token.
- void Scan();
+ V8_INLINE Token::Value ScanSingleToken();
+ V8_INLINE void Scan();
V8_INLINE Token::Value SkipWhiteSpace();
Token::Value SkipSingleHTMLComment();
@@ -738,8 +744,10 @@ class Scanner {
bool ScanImplicitOctalDigits(int start_pos, NumberKind* kind);
Token::Value ScanNumber(bool seen_period);
- Token::Value ScanIdentifierOrKeyword();
- Token::Value ScanIdentifierOrKeywordInner(LiteralScope* literal);
+ V8_INLINE Token::Value ScanIdentifierOrKeyword();
+ V8_INLINE Token::Value ScanIdentifierOrKeywordInner(LiteralScope* literal);
+ Token::Value ScanIdentifierOrKeywordInnerSlow(LiteralScope* literal,
+ bool escaped);
Token::Value ScanString();
Token::Value ScanPrivateName();
@@ -779,13 +787,7 @@ class Scanner {
void SanityCheckTokenDesc(const TokenDesc&) const;
#endif
- UnicodeCache* unicode_cache_;
-
- // Values parsed from magic comments.
- LiteralBuffer source_url_;
- LiteralBuffer source_mapping_url_;
-
- TokenDesc token_storage_[3];
+ UnicodeCache* const unicode_cache_;
TokenDesc& next() { return *next_; }
@@ -800,23 +802,28 @@ class Scanner {
// Input stream. Must be initialized to an Utf16CharacterStream.
Utf16CharacterStream* const source_;
- // Last-seen positions of potentially problematic tokens.
- Location octal_pos_;
- MessageTemplate::Template octal_message_;
-
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_;
+ TokenDesc token_storage_[3];
+
// Whether this scanner encountered an HTML comment.
bool found_html_comment_;
// Harmony flags to allow ESNext features.
- bool allow_harmony_bigint_;
bool allow_harmony_private_fields_;
bool allow_harmony_numeric_separator_;
const bool is_module_;
+ // Values parsed from magic comments.
+ LiteralBuffer source_url_;
+ LiteralBuffer source_mapping_url_;
+
+ // Last-seen positions of potentially problematic tokens.
+ Location octal_pos_;
+ MessageTemplate::Template octal_message_;
+
MessageTemplate::Template scanner_error_;
Location scanner_error_location_;
};
diff --git a/deps/v8/src/parsing/token.cc b/deps/v8/src/parsing/token.cc
index 258c7b5d09..4cbf244a2b 100644
--- a/deps/v8/src/parsing/token.cc
+++ b/deps/v8/src/parsing/token.cc
@@ -29,7 +29,6 @@ const uint8_t Token::string_length_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
const int8_t Token::precedence_[NUM_TOKENS] = {TOKEN_LIST(T, T, T)};
#undef T
-
#define KT(a, b, c) 'T',
#define KK(a, b, c) 'K',
#define KC(a, b, c) 'C',
diff --git a/deps/v8/src/parsing/token.h b/deps/v8/src/parsing/token.h
index 660f24361c..e1c6239e36 100644
--- a/deps/v8/src/parsing/token.h
+++ b/deps/v8/src/parsing/token.h
@@ -7,6 +7,7 @@
#include "src/base/logging.h"
#include "src/globals.h"
+#include "src/utils.h"
namespace v8 {
namespace internal {
@@ -32,6 +33,27 @@ namespace internal {
#define IGNORE_TOKEN(name, string, precedence)
+/* Binary operators sorted by precedence */
+#define BINARY_OP_TOKEN_LIST(T, E) \
+ E(T, BIT_OR, "|", 6) \
+ E(T, BIT_XOR, "^", 7) \
+ E(T, BIT_AND, "&", 8) \
+ E(T, SHL, "<<", 11) \
+ E(T, SAR, ">>", 11) \
+ E(T, SHR, ">>>", 11) \
+ E(T, ADD, "+", 12) \
+ E(T, SUB, "-", 12) \
+ E(T, MUL, "*", 13) \
+ E(T, DIV, "/", 13) \
+ E(T, MOD, "%", 13) \
+ E(T, EXP, "**", 14)
+
+#define EXPAND_BINOP_ASSIGN_TOKEN(T, name, string, precedence) \
+ T(ASSIGN_##name, string "=", 2)
+
+#define EXPAND_BINOP_TOKEN(T, name, string, precedence) \
+ T(name, string, precedence)
+
#define TOKEN_LIST(T, K, C) \
/* End of source indicator. */ \
T(EOS, "EOS", 0) \
@@ -57,18 +79,7 @@ namespace internal {
/* contiguous and sorted in the same order! */ \
T(INIT, "=init", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \
- T(ASSIGN_BIT_OR, "|=", 2) \
- T(ASSIGN_BIT_XOR, "^=", 2) \
- T(ASSIGN_BIT_AND, "&=", 2) \
- T(ASSIGN_SHL, "<<=", 2) \
- T(ASSIGN_SAR, ">>=", 2) \
- T(ASSIGN_SHR, ">>>=", 2) \
- T(ASSIGN_ADD, "+=", 2) \
- T(ASSIGN_SUB, "-=", 2) \
- T(ASSIGN_MUL, "*=", 2) \
- T(ASSIGN_DIV, "/=", 2) \
- T(ASSIGN_MOD, "%=", 2) \
- T(ASSIGN_EXP, "**=", 2) \
+ BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN) \
\
/* Binary operators sorted by precedence. */ \
/* IsBinaryOp() relies on this block of enum values */ \
@@ -76,25 +87,14 @@ namespace internal {
T(COMMA, ",", 1) \
T(OR, "||", 4) \
T(AND, "&&", 5) \
- T(BIT_OR, "|", 6) \
- T(BIT_XOR, "^", 7) \
- T(BIT_AND, "&", 8) \
- T(SHL, "<<", 11) \
- T(SAR, ">>", 11) \
- T(SHR, ">>>", 11) \
- T(ADD, "+", 12) \
- T(SUB, "-", 12) \
- T(MUL, "*", 13) \
- T(DIV, "/", 13) \
- T(MOD, "%", 13) \
- T(EXP, "**", 14) \
+ BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_TOKEN) \
\
/* Compare operators sorted by precedence. */ \
/* IsCompareOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \
T(EQ, "==", 9) \
- T(NE, "!=", 9) \
T(EQ_STRICT, "===", 9) \
+ T(NE, "!=", 9) \
T(NE_STRICT, "!==", 9) \
T(LT, "<", 10) \
T(GT, ">", 10) \
@@ -131,7 +131,6 @@ namespace internal {
K(NEW, "new", 0) \
K(RETURN, "return", 0) \
K(SWITCH, "switch", 0) \
- K(THIS, "this", 0) \
K(THROW, "throw", 0) \
K(TRY, "try", 0) \
/* TYPEOF */ \
@@ -139,6 +138,7 @@ namespace internal {
/* VOID */ \
K(WHILE, "while", 0) \
K(WITH, "with", 0) \
+ K(THIS, "this", 0) \
\
/* Literals (ECMA-262, section 7.8, page 16). */ \
K(NULL_LITERAL, "null", 0) \
@@ -146,33 +146,34 @@ namespace internal {
K(FALSE_LITERAL, "false", 0) \
T(NUMBER, nullptr, 0) \
T(SMI, nullptr, 0) \
- T(STRING, nullptr, 0) \
T(BIGINT, nullptr, 0) \
+ T(STRING, nullptr, 0) \
\
+ /* BEGIN AnyIdentifier */ \
/* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, nullptr, 0) \
- T(PRIVATE_NAME, nullptr, 0) \
- \
- /* Future reserved words (ECMA-262, section 7.6.1.2). */ \
- T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
K(ASYNC, "async", 0) \
/* `await` is a reserved word in module code only */ \
K(AWAIT, "await", 0) \
+ K(YIELD, "yield", 0) \
+ K(LET, "let", 0) \
+ K(STATIC, "static", 0) \
+ /* Future reserved words (ECMA-262, section 7.6.1.2). */ \
+ T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
+ T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
+ K(ENUM, "enum", 0) \
+ /* END AnyIdentifier */ \
K(CLASS, "class", 0) \
K(CONST, "const", 0) \
- K(ENUM, "enum", 0) \
K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \
- K(LET, "let", 0) \
- K(STATIC, "static", 0) \
- K(YIELD, "yield", 0) \
K(SUPER, "super", 0) \
+ T(PRIVATE_NAME, nullptr, 0) \
\
/* Illegal token - not able to scan. */ \
T(ILLEGAL, "ILLEGAL", 0) \
T(ESCAPED_KEYWORD, nullptr, 0) \
- T(ESCAPED_STRICT_RESERVED_WORD, nullptr, 0) \
\
/* Scanner-internal use only. */ \
T(WHITESPACE, nullptr, 0) \
@@ -205,127 +206,103 @@ class Token {
public:
// All token values.
#define T(name, string, precedence) name,
- enum Value { TOKEN_LIST(T, T, T) NUM_TOKENS };
+ enum Value : uint8_t { TOKEN_LIST(T, T, T) NUM_TOKENS };
#undef T
// Returns a string corresponding to the C++ token name
// (e.g. "LT" for the token LT).
- static const char* Name(Value tok) {
- DCHECK(tok < NUM_TOKENS); // tok is unsigned
- return name_[tok];
+ static const char* Name(Value token) {
+ DCHECK_GT(NUM_TOKENS, token); // token is unsigned
+ return name_[token];
}
+ static char TypeForTesting(Value token) { return token_type[token]; }
+
// Predicates
- static bool IsKeyword(Value tok) {
- return token_type[tok] == 'K';
+ static bool IsKeyword(Value token) { return token_type[token] == 'K'; }
+ static bool IsContextualKeyword(Value token) {
+ return IsInRange(token, GET, ANONYMOUS);
}
- static bool IsContextualKeyword(Value tok) { return token_type[tok] == 'C'; }
- static bool IsIdentifier(Value tok, LanguageMode language_mode,
+ static bool IsIdentifier(Value token, LanguageMode language_mode,
bool is_generator, bool disallow_await) {
- switch (tok) {
- case IDENTIFIER:
- case ASYNC:
- return true;
- case ESCAPED_STRICT_RESERVED_WORD:
- case FUTURE_STRICT_RESERVED_WORD:
- case LET:
- case STATIC:
- return is_sloppy(language_mode);
- case YIELD:
- return !is_generator && is_sloppy(language_mode);
- case AWAIT:
- return !disallow_await;
- default:
- return false;
+ if (IsInRange(token, IDENTIFIER, ASYNC)) return true;
+ if (IsInRange(token, LET, ESCAPED_STRICT_RESERVED_WORD)) {
+ return is_sloppy(language_mode);
}
- UNREACHABLE();
+ if (token == AWAIT) return !disallow_await;
+ if (token == YIELD) return !is_generator && is_sloppy(language_mode);
+ return false;
}
- static bool IsAssignmentOp(Value tok) {
- return INIT <= tok && tok <= ASSIGN_EXP;
+ static bool IsAnyIdentifier(Value token) {
+ return IsInRange(token, IDENTIFIER, ENUM);
}
- static bool IsBinaryOp(Value op) { return COMMA <= op && op <= EXP; }
+ static bool IsStrictReservedWord(Value token) {
+ return IsInRange(token, LET, ESCAPED_STRICT_RESERVED_WORD);
+ }
- static bool IsCompareOp(Value op) {
- return EQ <= op && op <= IN;
+ static bool IsLiteral(Value token) {
+ return IsInRange(token, NULL_LITERAL, STRING);
}
- static bool IsOrderedRelationalCompareOp(Value op) {
- return op == LT || op == LTE || op == GT || op == GTE;
+ static bool IsAssignmentOp(Value token) {
+ return IsInRange(token, INIT, ASSIGN_EXP);
}
+ static bool IsGetOrSet(Value op) { return IsInRange(op, GET, SET); }
+
+ static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, EXP); }
- static bool IsEqualityOp(Value op) {
- return op == EQ || op == EQ_STRICT;
+ static bool IsCompareOp(Value op) { return IsInRange(op, EQ, IN); }
+
+ static bool IsOrderedRelationalCompareOp(Value op) {
+ return IsInRange(op, LT, GTE);
}
+ static bool IsEqualityOp(Value op) { return IsInRange(op, EQ, EQ_STRICT); }
+
static Value BinaryOpForAssignment(Value op) {
- DCHECK(IsAssignmentOp(op));
- switch (op) {
- case Token::ASSIGN_BIT_OR:
- return Token::BIT_OR;
- case Token::ASSIGN_BIT_XOR:
- return Token::BIT_XOR;
- case Token::ASSIGN_BIT_AND:
- return Token::BIT_AND;
- case Token::ASSIGN_SHL:
- return Token::SHL;
- case Token::ASSIGN_SAR:
- return Token::SAR;
- case Token::ASSIGN_SHR:
- return Token::SHR;
- case Token::ASSIGN_ADD:
- return Token::ADD;
- case Token::ASSIGN_SUB:
- return Token::SUB;
- case Token::ASSIGN_MUL:
- return Token::MUL;
- case Token::ASSIGN_DIV:
- return Token::DIV;
- case Token::ASSIGN_MOD:
- return Token::MOD;
- case Token::ASSIGN_EXP:
- return Token::EXP;
- default:
- UNREACHABLE();
- }
+ DCHECK(IsInRange(op, ASSIGN_BIT_OR, ASSIGN_EXP));
+ Value result = static_cast<Value>(op - ASSIGN_BIT_OR + BIT_OR);
+ DCHECK(IsBinaryOp(result));
+ return result;
}
static bool IsBitOp(Value op) {
- return (BIT_OR <= op && op <= SHR) || op == BIT_NOT;
+ return IsInRange(op, BIT_OR, SHR) || op == BIT_NOT;
}
static bool IsUnaryOp(Value op) {
- return (NOT <= op && op <= VOID) || op == ADD || op == SUB;
+ return IsInRange(op, NOT, VOID) || IsInRange(op, ADD, SUB);
}
- static bool IsCountOp(Value op) {
- return op == INC || op == DEC;
- }
+ static bool IsCountOp(Value op) { return IsInRange(op, INC, DEC); }
+
+ static bool IsShiftOp(Value op) { return IsInRange(op, SHL, SHR); }
- static bool IsShiftOp(Value op) {
- return (SHL <= op) && (op <= SHR);
+ static bool IsTrivialExpressionToken(Value op) {
+ return IsInRange(op, THIS, IDENTIFIER);
}
// Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or nullptr if the token doesn't
// have a (unique) string (e.g. an IDENTIFIER).
- static const char* String(Value tok) {
- DCHECK(tok < NUM_TOKENS); // tok is unsigned.
- return string_[tok];
+ static const char* String(Value token) {
+ DCHECK_GT(NUM_TOKENS, token); // token is unsigned
+ return string_[token];
}
- static uint8_t StringLength(Value tok) {
- DCHECK(tok < NUM_TOKENS);
- return string_length_[tok];
+ static uint8_t StringLength(Value token) {
+ DCHECK_GT(NUM_TOKENS, token); // token is unsigned
+ return string_length_[token];
}
// Returns the precedence > 0 for binary and compare
// operators; returns 0 otherwise.
- static int Precedence(Value tok) {
- DCHECK(tok < NUM_TOKENS); // tok is unsigned.
- return precedence_[tok];
+ static int Precedence(Value token) {
+ DCHECK_GT(NUM_TOKENS, token); // token is unsigned
+ return precedence_[token];
}
private: