Merge V8 5.3.332.45. DO NOT MERGE
Test: Manual
FPIIM-449
Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/src/parsing/OWNERS b/src/parsing/OWNERS
index a5daeb3..44cc4ed 100644
--- a/src/parsing/OWNERS
+++ b/src/parsing/OWNERS
@@ -4,4 +4,4 @@
littledan@chromium.org
marja@chromium.org
rossberg@chromium.org
-
+vogelheim@chromium.org
diff --git a/src/parsing/expression-classifier.h b/src/parsing/expression-classifier.h
index 3f70ed8..8e13d0e 100644
--- a/src/parsing/expression-classifier.h
+++ b/src/parsing/expression-classifier.h
@@ -13,35 +13,55 @@
namespace internal {
+#define ERROR_CODES(T) \
+ T(ExpressionProduction, 0) \
+ T(FormalParameterInitializerProduction, 1) \
+ T(BindingPatternProduction, 2) \
+ T(AssignmentPatternProduction, 3) \
+ T(DistinctFormalParametersProduction, 4) \
+ T(StrictModeFormalParametersProduction, 5) \
+ T(ArrowFormalParametersProduction, 6) \
+ T(LetPatternProduction, 7) \
+ T(CoverInitializedNameProduction, 8) \
+ T(TailCallExpressionProduction, 9) \
+ T(AsyncArrowFormalParametersProduction, 10) \
+ T(AsyncBindingPatternProduction, 11)
+
+
template <typename Traits>
class ExpressionClassifier {
public:
+ enum ErrorKind : unsigned {
+#define DEFINE_ERROR_KIND(NAME, CODE) k##NAME = CODE,
+ ERROR_CODES(DEFINE_ERROR_KIND)
+#undef DEFINE_ERROR_KIND
+ kUnusedError = 15 // Larger than error codes; should fit in 4 bits
+ };
+
struct Error {
- Error()
+ V8_INLINE Error()
: location(Scanner::Location::invalid()),
message(MessageTemplate::kNone),
+ kind(kUnusedError),
type(kSyntaxError),
arg(nullptr) {}
+ V8_INLINE explicit Error(Scanner::Location loc,
+ MessageTemplate::Template msg, ErrorKind k,
+ const char* a = nullptr,
+ ParseErrorType t = kSyntaxError)
+ : location(loc), message(msg), kind(k), type(t), arg(a) {}
Scanner::Location location;
- MessageTemplate::Template message : 30;
+ MessageTemplate::Template message : 26;
+ unsigned kind : 4;
ParseErrorType type : 2;
const char* arg;
};
- enum TargetProduction {
- ExpressionProduction = 1 << 0,
- FormalParameterInitializerProduction = 1 << 1,
- BindingPatternProduction = 1 << 2,
- AssignmentPatternProduction = 1 << 3,
- DistinctFormalParametersProduction = 1 << 4,
- StrictModeFormalParametersProduction = 1 << 5,
- ArrowFormalParametersProduction = 1 << 6,
- LetPatternProduction = 1 << 7,
- CoverInitializedNameProduction = 1 << 8,
- TailCallExpressionProduction = 1 << 9,
- AsyncArrowFormalParametersProduction = 1 << 10,
- AsyncBindingPatternProduction = 1 << 11,
+ enum TargetProduction : unsigned {
+#define DEFINE_PRODUCTION(NAME, CODE) NAME = 1 << CODE,
+ ERROR_CODES(DEFINE_PRODUCTION)
+#undef DEFINE_PRODUCTION
ExpressionProductions =
(ExpressionProduction | FormalParameterInitializerProduction |
@@ -58,63 +78,75 @@
AsyncArrowFormalParametersProduction | AsyncBindingPatternProduction)
};
- enum FunctionProperties { NonSimpleParameter = 1 << 0 };
+ enum FunctionProperties : unsigned {
+ NonSimpleParameter = 1 << 0
+ };
explicit ExpressionClassifier(const Traits* t)
: zone_(t->zone()),
non_patterns_to_rewrite_(t->GetNonPatternList()),
+ reported_errors_(t->GetReportedErrorList()),
+ duplicate_finder_(nullptr),
invalid_productions_(0),
- function_properties_(0),
- duplicate_finder_(nullptr) {
+ function_properties_(0) {
+ reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
non_pattern_begin_ = non_patterns_to_rewrite_->length();
}
ExpressionClassifier(const Traits* t, DuplicateFinder* duplicate_finder)
: zone_(t->zone()),
non_patterns_to_rewrite_(t->GetNonPatternList()),
+ reported_errors_(t->GetReportedErrorList()),
+ duplicate_finder_(duplicate_finder),
invalid_productions_(0),
- function_properties_(0),
- duplicate_finder_(duplicate_finder) {
+ function_properties_(0) {
+ reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
non_pattern_begin_ = non_patterns_to_rewrite_->length();
}
~ExpressionClassifier() { Discard(); }
- bool is_valid(unsigned productions) const {
+ V8_INLINE bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
}
- DuplicateFinder* duplicate_finder() const { return duplicate_finder_; }
+ V8_INLINE DuplicateFinder* duplicate_finder() const {
+ return duplicate_finder_;
+ }
- bool is_valid_expression() const { return is_valid(ExpressionProduction); }
+ V8_INLINE bool is_valid_expression() const {
+ return is_valid(ExpressionProduction);
+ }
- bool is_valid_formal_parameter_initializer() const {
+ V8_INLINE bool is_valid_formal_parameter_initializer() const {
return is_valid(FormalParameterInitializerProduction);
}
- bool is_valid_binding_pattern() const {
+ V8_INLINE bool is_valid_binding_pattern() const {
return is_valid(BindingPatternProduction);
}
- bool is_valid_assignment_pattern() const {
+ V8_INLINE bool is_valid_assignment_pattern() const {
return is_valid(AssignmentPatternProduction);
}
- bool is_valid_arrow_formal_parameters() const {
+ V8_INLINE bool is_valid_arrow_formal_parameters() const {
return is_valid(ArrowFormalParametersProduction);
}
- bool is_valid_formal_parameter_list_without_duplicates() const {
+ V8_INLINE bool is_valid_formal_parameter_list_without_duplicates() const {
return is_valid(DistinctFormalParametersProduction);
}
// Note: callers should also check
// is_valid_formal_parameter_list_without_duplicates().
- bool is_valid_strict_mode_formal_parameters() const {
+ V8_INLINE bool is_valid_strict_mode_formal_parameters() const {
return is_valid(StrictModeFormalParametersProduction);
}
- bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); }
+ V8_INLINE bool is_valid_let_pattern() const {
+ return is_valid(LetPatternProduction);
+ }
bool is_valid_async_arrow_formal_parameters() const {
return is_valid(AsyncArrowFormalParametersProduction);
@@ -124,58 +156,65 @@
return is_valid(AsyncBindingPatternProduction);
}
- const Error& expression_error() const { return expression_error_; }
-
- const Error& formal_parameter_initializer_error() const {
- return formal_parameter_initializer_error_;
+ V8_INLINE const Error& expression_error() const {
+ return reported_error(kExpressionProduction);
}
- const Error& binding_pattern_error() const { return binding_pattern_error_; }
-
- const Error& assignment_pattern_error() const {
- return assignment_pattern_error_;
+ V8_INLINE const Error& formal_parameter_initializer_error() const {
+ return reported_error(kFormalParameterInitializerProduction);
}
- const Error& arrow_formal_parameters_error() const {
- return arrow_formal_parameters_error_;
+ V8_INLINE const Error& binding_pattern_error() const {
+ return reported_error(kBindingPatternProduction);
}
- const Error& duplicate_formal_parameter_error() const {
- return duplicate_formal_parameter_error_;
+ V8_INLINE const Error& assignment_pattern_error() const {
+ return reported_error(kAssignmentPatternProduction);
}
- const Error& strict_mode_formal_parameter_error() const {
- return strict_mode_formal_parameter_error_;
+ V8_INLINE const Error& arrow_formal_parameters_error() const {
+ return reported_error(kArrowFormalParametersProduction);
}
- const Error& let_pattern_error() const { return let_pattern_error_; }
+ V8_INLINE const Error& duplicate_formal_parameter_error() const {
+ return reported_error(kDistinctFormalParametersProduction);
+ }
- bool has_cover_initialized_name() const {
+ V8_INLINE const Error& strict_mode_formal_parameter_error() const {
+ return reported_error(kStrictModeFormalParametersProduction);
+ }
+
+ V8_INLINE const Error& let_pattern_error() const {
+ return reported_error(kLetPatternProduction);
+ }
+
+ V8_INLINE bool has_cover_initialized_name() const {
return !is_valid(CoverInitializedNameProduction);
}
- const Error& cover_initialized_name_error() const {
- return cover_initialized_name_error_;
+
+ V8_INLINE const Error& cover_initialized_name_error() const {
+ return reported_error(kCoverInitializedNameProduction);
}
- bool has_tail_call_expression() const {
+ V8_INLINE bool has_tail_call_expression() const {
return !is_valid(TailCallExpressionProduction);
}
- const Error& tail_call_expression_error() const {
- return tail_call_expression_error_;
+ V8_INLINE const Error& tail_call_expression_error() const {
+ return reported_error(kTailCallExpressionProduction);
}
- const Error& async_arrow_formal_parameters_error() const {
- return async_arrow_formal_parameters_error_;
+ V8_INLINE const Error& async_arrow_formal_parameters_error() const {
+ return reported_error(kAsyncArrowFormalParametersProduction);
}
- const Error& async_binding_pattern_error() const {
- return async_binding_pattern_error_;
+ V8_INLINE const Error& async_binding_pattern_error() const {
+ return reported_error(kAsyncBindingPatternProduction);
}
- bool is_simple_parameter_list() const {
+ V8_INLINE bool is_simple_parameter_list() const {
return !(function_properties_ & NonSimpleParameter);
}
- void RecordNonSimpleParameter() {
+ V8_INLINE void RecordNonSimpleParameter() {
function_properties_ |= NonSimpleParameter;
}
@@ -184,9 +223,7 @@
const char* arg = nullptr) {
if (!is_valid_expression()) return;
invalid_productions_ |= ExpressionProduction;
- expression_error_.location = loc;
- expression_error_.message = message;
- expression_error_.arg = arg;
+ Add(Error(loc, message, kExpressionProduction, arg));
}
void RecordExpressionError(const Scanner::Location& loc,
@@ -194,10 +231,7 @@
ParseErrorType type, const char* arg = nullptr) {
if (!is_valid_expression()) return;
invalid_productions_ |= ExpressionProduction;
- expression_error_.location = loc;
- expression_error_.message = message;
- expression_error_.arg = arg;
- expression_error_.type = type;
+ Add(Error(loc, message, kExpressionProduction, arg, type));
}
void RecordFormalParameterInitializerError(const Scanner::Location& loc,
@@ -205,9 +239,7 @@
const char* arg = nullptr) {
if (!is_valid_formal_parameter_initializer()) return;
invalid_productions_ |= FormalParameterInitializerProduction;
- formal_parameter_initializer_error_.location = loc;
- formal_parameter_initializer_error_.message = message;
- formal_parameter_initializer_error_.arg = arg;
+ Add(Error(loc, message, kFormalParameterInitializerProduction, arg));
}
void RecordBindingPatternError(const Scanner::Location& loc,
@@ -215,9 +247,7 @@
const char* arg = nullptr) {
if (!is_valid_binding_pattern()) return;
invalid_productions_ |= BindingPatternProduction;
- binding_pattern_error_.location = loc;
- binding_pattern_error_.message = message;
- binding_pattern_error_.arg = arg;
+ Add(Error(loc, message, kBindingPatternProduction, arg));
}
void RecordAssignmentPatternError(const Scanner::Location& loc,
@@ -225,9 +255,7 @@
const char* arg = nullptr) {
if (!is_valid_assignment_pattern()) return;
invalid_productions_ |= AssignmentPatternProduction;
- assignment_pattern_error_.location = loc;
- assignment_pattern_error_.message = message;
- assignment_pattern_error_.arg = arg;
+ Add(Error(loc, message, kAssignmentPatternProduction, arg));
}
void RecordPatternError(const Scanner::Location& loc,
@@ -242,9 +270,7 @@
const char* arg = nullptr) {
if (!is_valid_arrow_formal_parameters()) return;
invalid_productions_ |= ArrowFormalParametersProduction;
- arrow_formal_parameters_error_.location = loc;
- arrow_formal_parameters_error_.message = message;
- arrow_formal_parameters_error_.arg = arg;
+ Add(Error(loc, message, kArrowFormalParametersProduction, arg));
}
void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
@@ -252,9 +278,7 @@
const char* arg = nullptr) {
if (!is_valid_async_arrow_formal_parameters()) return;
invalid_productions_ |= AsyncArrowFormalParametersProduction;
- async_arrow_formal_parameters_error_.location = loc;
- async_arrow_formal_parameters_error_.message = message;
- async_arrow_formal_parameters_error_.arg = arg;
+ Add(Error(loc, message, kAsyncArrowFormalParametersProduction, arg));
}
void RecordAsyncBindingPatternError(const Scanner::Location& loc,
@@ -262,17 +286,14 @@
const char* arg = nullptr) {
if (!is_valid_async_binding_pattern()) return;
invalid_productions_ |= AsyncBindingPatternProduction;
- async_binding_pattern_error_.location = loc;
- async_binding_pattern_error_.message = message;
- async_binding_pattern_error_.arg = arg;
+ Add(Error(loc, message, kAsyncBindingPatternProduction, arg));
}
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
if (!is_valid_formal_parameter_list_without_duplicates()) return;
invalid_productions_ |= DistinctFormalParametersProduction;
- duplicate_formal_parameter_error_.location = loc;
- duplicate_formal_parameter_error_.message = MessageTemplate::kParamDupe;
- duplicate_formal_parameter_error_.arg = nullptr;
+ Add(Error(loc, MessageTemplate::kParamDupe,
+ kDistinctFormalParametersProduction));
}
// Record a binding that would be invalid in strict mode. Confusingly this
@@ -283,9 +304,7 @@
const char* arg = nullptr) {
if (!is_valid_strict_mode_formal_parameters()) return;
invalid_productions_ |= StrictModeFormalParametersProduction;
- strict_mode_formal_parameter_error_.location = loc;
- strict_mode_formal_parameter_error_.message = message;
- strict_mode_formal_parameter_error_.arg = arg;
+ Add(Error(loc, message, kStrictModeFormalParametersProduction, arg));
}
void RecordLetPatternError(const Scanner::Location& loc,
@@ -293,9 +312,7 @@
const char* arg = nullptr) {
if (!is_valid_let_pattern()) return;
invalid_productions_ |= LetPatternProduction;
- let_pattern_error_.location = loc;
- let_pattern_error_.message = message;
- let_pattern_error_.arg = arg;
+ Add(Error(loc, message, kLetPatternProduction, arg));
}
void RecordCoverInitializedNameError(const Scanner::Location& loc,
@@ -303,9 +320,7 @@
const char* arg = nullptr) {
if (has_cover_initialized_name()) return;
invalid_productions_ |= CoverInitializedNameProduction;
- cover_initialized_name_error_.location = loc;
- cover_initialized_name_error_.message = message;
- cover_initialized_name_error_.arg = arg;
+ Add(Error(loc, message, kCoverInitializedNameProduction, arg));
}
void RecordTailCallExpressionError(const Scanner::Location& loc,
@@ -313,83 +328,102 @@
const char* arg = nullptr) {
if (has_tail_call_expression()) return;
invalid_productions_ |= TailCallExpressionProduction;
- tail_call_expression_error_.location = loc;
- tail_call_expression_error_.message = message;
- tail_call_expression_error_.arg = arg;
+ Add(Error(loc, message, kTailCallExpressionProduction, arg));
}
void ForgiveCoverInitializedNameError() {
+ if (!(invalid_productions_ & CoverInitializedNameProduction)) return;
+ Error& e = reported_error(kCoverInitializedNameProduction);
+ e.kind = kUnusedError;
invalid_productions_ &= ~CoverInitializedNameProduction;
- cover_initialized_name_error_ = Error();
}
void ForgiveAssignmentPatternError() {
+ if (!(invalid_productions_ & AssignmentPatternProduction)) return;
+ Error& e = reported_error(kAssignmentPatternProduction);
+ e.kind = kUnusedError;
invalid_productions_ &= ~AssignmentPatternProduction;
- assignment_pattern_error_ = Error();
}
void Accumulate(ExpressionClassifier* inner,
unsigned productions = StandardProductions,
bool merge_non_patterns = true) {
+ DCHECK_EQ(inner->reported_errors_, reported_errors_);
+ DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_);
+ DCHECK_EQ(inner->reported_errors_end_, reported_errors_->length());
if (merge_non_patterns) MergeNonPatterns(inner);
// Propagate errors from inner, but don't overwrite already recorded
// errors.
unsigned non_arrow_inner_invalid_productions =
inner->invalid_productions_ & ~ArrowFormalParametersProduction;
- if (non_arrow_inner_invalid_productions == 0) return;
- unsigned non_arrow_productions =
- productions & ~ArrowFormalParametersProduction;
- unsigned errors =
- non_arrow_productions & non_arrow_inner_invalid_productions;
- errors &= ~invalid_productions_;
- if (errors != 0) {
- invalid_productions_ |= errors;
- if (errors & ExpressionProduction)
- expression_error_ = inner->expression_error_;
- if (errors & FormalParameterInitializerProduction)
- formal_parameter_initializer_error_ =
- inner->formal_parameter_initializer_error_;
- if (errors & BindingPatternProduction)
- binding_pattern_error_ = inner->binding_pattern_error_;
- if (errors & AssignmentPatternProduction)
- assignment_pattern_error_ = inner->assignment_pattern_error_;
- if (errors & DistinctFormalParametersProduction)
- duplicate_formal_parameter_error_ =
- inner->duplicate_formal_parameter_error_;
- if (errors & StrictModeFormalParametersProduction)
- strict_mode_formal_parameter_error_ =
- inner->strict_mode_formal_parameter_error_;
- if (errors & LetPatternProduction)
- let_pattern_error_ = inner->let_pattern_error_;
- if (errors & CoverInitializedNameProduction)
- cover_initialized_name_error_ = inner->cover_initialized_name_error_;
- if (errors & TailCallExpressionProduction)
- tail_call_expression_error_ = inner->tail_call_expression_error_;
- if (errors & AsyncArrowFormalParametersProduction)
- async_arrow_formal_parameters_error_ =
- inner->async_arrow_formal_parameters_error_;
- if (errors & AsyncBindingPatternProduction)
- async_binding_pattern_error_ = inner->async_binding_pattern_error_;
- }
-
- // As an exception to the above, the result continues to be a valid arrow
- // formal parameters if the inner expression is a valid binding pattern.
- if (productions & ArrowFormalParametersProduction &&
- is_valid_arrow_formal_parameters()) {
- // Also copy function properties if expecting an arrow function
- // parameter.
- function_properties_ |= inner->function_properties_;
-
- if (!inner->is_valid_binding_pattern()) {
- invalid_productions_ |= ArrowFormalParametersProduction;
- arrow_formal_parameters_error_ = inner->binding_pattern_error_;
+ if (non_arrow_inner_invalid_productions) {
+ unsigned errors = non_arrow_inner_invalid_productions & productions &
+ ~invalid_productions_;
+ // The result will continue to be a valid arrow formal parameters if the
+ // inner expression is a valid binding pattern.
+ bool copy_BP_to_AFP = false;
+ if (productions & ArrowFormalParametersProduction &&
+ is_valid_arrow_formal_parameters()) {
+ // Also copy function properties if expecting an arrow function
+ // parameter.
+ function_properties_ |= inner->function_properties_;
+ if (!inner->is_valid_binding_pattern()) {
+ copy_BP_to_AFP = true;
+ invalid_productions_ |= ArrowFormalParametersProduction;
+ }
+ }
+ // Traverse the list of errors reported by the inner classifier
+ // to copy what's necessary.
+ if (errors != 0 || copy_BP_to_AFP) {
+ invalid_productions_ |= errors;
+ int binding_pattern_index = inner->reported_errors_end_;
+ for (int i = inner->reported_errors_begin_;
+ i < inner->reported_errors_end_; i++) {
+ int k = reported_errors_->at(i).kind;
+ if (errors & (1 << k)) Copy(i);
+ // Check if it's a BP error that has to be copied to an AFP error.
+ if (k == kBindingPatternProduction && copy_BP_to_AFP) {
+ if (reported_errors_end_ <= i) {
+ // If the BP error itself has not already been copied,
+ // copy it now and change it to an AFP error.
+ Copy(i);
+ reported_errors_->at(reported_errors_end_-1).kind =
+ kArrowFormalParametersProduction;
+ } else {
+ // Otherwise, if the BP error was already copied, keep its
+ // position and wait until the end of the traversal.
+ DCHECK_EQ(reported_errors_end_, i+1);
+ binding_pattern_index = i;
+ }
+ }
+ }
+ // Do we still have to copy the BP error to an AFP error?
+ if (binding_pattern_index < inner->reported_errors_end_) {
+ // If there's still unused space in the list of the inner
+ // classifier, copy it there, otherwise add it to the end
+ // of the list.
+ if (reported_errors_end_ < inner->reported_errors_end_)
+ Copy(binding_pattern_index);
+ else
+ Add(reported_errors_->at(binding_pattern_index));
+ reported_errors_->at(reported_errors_end_-1).kind =
+ kArrowFormalParametersProduction;
+ }
}
}
+ reported_errors_->Rewind(reported_errors_end_);
+ inner->reported_errors_begin_ = inner->reported_errors_end_ =
+ reported_errors_end_;
}
V8_INLINE int GetNonPatternBegin() const { return non_pattern_begin_; }
V8_INLINE void Discard() {
+ if (reported_errors_end_ == reported_errors_->length()) {
+ reported_errors_->Rewind(reported_errors_begin_);
+ reported_errors_end_ = reported_errors_begin_;
+ }
+ DCHECK_EQ(reported_errors_begin_, reported_errors_end_);
DCHECK_LE(non_pattern_begin_, non_patterns_to_rewrite_->length());
non_patterns_to_rewrite_->Rewind(non_pattern_begin_);
}
@@ -400,29 +434,69 @@
}
private:
+ V8_INLINE Error& reported_error(ErrorKind kind) const {
+ if (invalid_productions_ & (1 << kind)) {
+ for (int i = reported_errors_begin_; i < reported_errors_end_; i++) {
+ if (reported_errors_->at(i).kind == kind)
+ return reported_errors_->at(i);
+ }
+ UNREACHABLE();
+ }
+ // We should only be looking for an error when we know that one has
+ // been reported. But we're not... So this is to make sure we have
+ // the same behaviour.
+ static Error none;
+ return none;
+ }
+
+ // Adds e to the end of the list of reported errors for this classifier.
+ // It is expected that this classifier is the last one in the stack.
+ V8_INLINE void Add(const Error& e) {
+ DCHECK_EQ(reported_errors_end_, reported_errors_->length());
+ reported_errors_->Add(e, zone_);
+ reported_errors_end_++;
+ }
+
+ // Copies the error at position i of the list of reported errors, so that
+ // it becomes the last error reported for this classifier. Position i
+ // could be either after the existing errors of this classifier (i.e.,
+ // in an inner classifier) or it could be an existing error (in case a
+ // copy is needed).
+ V8_INLINE void Copy(int i) {
+ DCHECK_LT(i, reported_errors_->length());
+ if (reported_errors_end_ != i)
+ reported_errors_->at(reported_errors_end_) = reported_errors_->at(i);
+ reported_errors_end_++;
+ }
+
Zone* zone_;
ZoneList<typename Traits::Type::Expression>* non_patterns_to_rewrite_;
- int non_pattern_begin_;
- unsigned invalid_productions_;
- unsigned function_properties_;
- // TODO(ishell): consider using Zone[Hash]Map<TargetProduction, Error>
- // here to consume less stack space during parsing.
- Error expression_error_;
- Error formal_parameter_initializer_error_;
- Error binding_pattern_error_;
- Error assignment_pattern_error_;
- Error arrow_formal_parameters_error_;
- Error duplicate_formal_parameter_error_;
- Error strict_mode_formal_parameter_error_;
- Error let_pattern_error_;
- Error cover_initialized_name_error_;
- Error tail_call_expression_error_;
- Error async_arrow_formal_parameters_error_;
- Error async_binding_pattern_error_;
+ ZoneList<Error>* reported_errors_;
DuplicateFinder* duplicate_finder_;
+ // The uint16_t for non_pattern_begin_ will not be enough in the case,
+ // e.g., of an array literal containing more than 64K inner array
+ // literals with spreads, as in:
+ // var N=65536; eval("var x=[];" + "[" + "[...x],".repeat(N) + "].length");
+ // An implementation limit error in ParserBase::AddNonPatternForRewriting
+ // will be triggered in this case.
+ uint16_t non_pattern_begin_;
+ unsigned invalid_productions_ : 14;
+ unsigned function_properties_ : 2;
+ // The uint16_t for reported_errors_begin_ and reported_errors_end_ will
+ // not be enough in the case of a long series of expressions using nested
+ // classifiers, e.g., a long sequence of assignments, as in:
+ // literals with spreads, as in:
+ // var N=65536; eval("var x;" + "x=".repeat(N) + "42");
+ // This should not be a problem, as such things currently fail with a
+ // stack overflow while parsing.
+ uint16_t reported_errors_begin_;
+ uint16_t reported_errors_end_;
};
+#undef ERROR_CODES
+
+
} // namespace internal
} // namespace v8
diff --git a/src/parsing/parameter-initializer-rewriter.cc b/src/parsing/parameter-initializer-rewriter.cc
index 6362c63..4bb367d 100644
--- a/src/parsing/parameter-initializer-rewriter.cc
+++ b/src/parsing/parameter-initializer-rewriter.cc
@@ -24,7 +24,9 @@
Scope* new_scope)
: AstExpressionVisitor(stack_limit, initializer),
old_scope_(old_scope),
- new_scope_(new_scope) {}
+ new_scope_(new_scope),
+ old_scope_closure_(old_scope->ClosureScope()),
+ new_scope_closure_(new_scope->ClosureScope()) {}
~Rewriter();
private:
@@ -40,6 +42,8 @@
Scope* old_scope_;
Scope* new_scope_;
+ Scope* old_scope_closure_;
+ Scope* new_scope_closure_;
std::vector<std::pair<Variable*, int>> temps_;
};
@@ -55,8 +59,8 @@
// Ensure that we add temporaries in the order they appeared in old_scope_.
std::sort(temps_.begin(), temps_.end(), LessThanSecond());
for (auto var_and_index : temps_) {
- var_and_index.first->set_scope(new_scope_);
- new_scope_->AddTemporary(var_and_index.first);
+ var_and_index.first->set_scope(new_scope_closure_);
+ new_scope_closure_->AddTemporary(var_and_index.first);
}
}
}
@@ -90,11 +94,11 @@
if (proxy->is_resolved()) {
Variable* var = proxy->var();
if (var->mode() != TEMPORARY) return;
- // For rewriting inside the same ClosureScope (e.g., putting default
- // parameter values in their own inner scope in certain cases), refrain
- // from invalidly moving temporaries to a block scope.
- if (var->scope()->ClosureScope() == new_scope_->ClosureScope()) return;
- int index = old_scope_->RemoveTemporary(var);
+ // Temporaries are only placed in ClosureScopes.
+ DCHECK_EQ(var->scope(), var->scope()->ClosureScope());
+ // If the temporary is already where it should be, return quickly.
+ if (var->scope() == new_scope_closure_) return;
+ int index = old_scope_closure_->RemoveTemporary(var);
if (index >= 0) {
temps_.push_back(std::make_pair(var, index));
}
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index 6086f7a..669defa 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -7,7 +7,7 @@
#include "src/ast/scopes.h"
#include "src/bailout-reason.h"
-#include "src/hashmap.h"
+#include "src/base/hashmap.h"
#include "src/messages.h"
#include "src/parsing/expression-classifier.h"
#include "src/parsing/func-name-inferrer.h"
@@ -196,9 +196,9 @@
allow_harmony_restrictive_declarations_(false),
allow_harmony_do_expressions_(false),
allow_harmony_for_in_(false),
- allow_harmony_function_name_(false),
allow_harmony_function_sent_(false),
- allow_harmony_async_await_(false) {}
+ allow_harmony_async_await_(false),
+ allow_harmony_restrictive_generators_(false) {}
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
@@ -216,9 +216,9 @@
ALLOW_ACCESSORS(harmony_restrictive_declarations);
ALLOW_ACCESSORS(harmony_do_expressions);
ALLOW_ACCESSORS(harmony_for_in);
- ALLOW_ACCESSORS(harmony_function_name);
ALLOW_ACCESSORS(harmony_function_sent);
ALLOW_ACCESSORS(harmony_async_await);
+ ALLOW_ACCESSORS(harmony_restrictive_generators);
SCANNER_ACCESSORS(harmony_exponentiation_operator);
#undef SCANNER_ACCESSORS
@@ -385,8 +385,8 @@
typename Traits::Type::Factory* factory() { return factory_; }
- const List<DestructuringAssignment>& destructuring_assignments_to_rewrite()
- const {
+ const ZoneList<DestructuringAssignment>&
+ destructuring_assignments_to_rewrite() const {
return destructuring_assignments_to_rewrite_;
}
@@ -408,6 +408,10 @@
}
}
+ ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() {
+ return &reported_errors_;
+ }
+
ReturnExprContext return_expr_context() const {
return return_expr_context_;
}
@@ -429,13 +433,16 @@
private:
void AddDestructuringAssignment(DestructuringAssignment pair) {
- destructuring_assignments_to_rewrite_.Add(pair);
+ destructuring_assignments_to_rewrite_.Add(pair, (*scope_stack_)->zone());
}
V8_INLINE Scope* scope() { return *scope_stack_; }
- void AddNonPatternForRewriting(ExpressionT expr) {
+ void AddNonPatternForRewriting(ExpressionT expr, bool* ok) {
non_patterns_to_rewrite_.Add(expr, (*scope_stack_)->zone());
+ if (non_patterns_to_rewrite_.length() >=
+ std::numeric_limits<uint16_t>::max())
+ *ok = false;
}
// Used to assign an index to each literal that needs materialization in
@@ -466,11 +473,13 @@
Scope** scope_stack_;
Scope* outer_scope_;
- List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
+ ZoneList<DestructuringAssignment> destructuring_assignments_to_rewrite_;
TailCallExpressionList tail_call_expressions_;
ReturnExprContext return_expr_context_;
ZoneList<ExpressionT> non_patterns_to_rewrite_;
+ ZoneList<typename ExpressionClassifier::Error> reported_errors_;
+
typename Traits::Type::Factory* factory_;
// If true, the next (and immediately following) function literal is
@@ -658,13 +667,13 @@
Expect(Token::SEMICOLON, ok);
}
- bool peek_any_identifier() {
- Token::Value next = peek();
- return next == Token::IDENTIFIER || next == Token::ENUM ||
- next == Token::AWAIT || next == Token::ASYNC ||
- next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
- next == Token::STATIC || next == Token::YIELD;
+ bool is_any_identifier(Token::Value token) {
+ return token == Token::IDENTIFIER || token == Token::ENUM ||
+ token == Token::AWAIT || token == Token::ASYNC ||
+ 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 CheckContextualKeyword(Vector<const char> keyword) {
if (PeekContextualKeyword(keyword)) {
@@ -877,6 +886,10 @@
}
}
+ bool IsValidArrowFormalParametersStart(Token::Value token) {
+ return is_any_identifier(token) || token == Token::LPAREN;
+ }
+
void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
ExpressionT expr,
bool parenthesized_formals, bool is_async,
@@ -1173,9 +1186,9 @@
bool allow_harmony_restrictive_declarations_;
bool allow_harmony_do_expressions_;
bool allow_harmony_for_in_;
- bool allow_harmony_function_name_;
bool allow_harmony_function_sent_;
bool allow_harmony_async_await_;
+ bool allow_harmony_restrictive_generators_;
};
template <class Traits>
@@ -1193,9 +1206,11 @@
outer_function_state_(*function_state_stack),
scope_stack_(scope_stack),
outer_scope_(*scope_stack),
+ destructuring_assignments_to_rewrite_(16, scope->zone()),
tail_call_expressions_(scope->zone()),
return_expr_context_(ReturnExprContext::kInsideValidBlock),
non_patterns_to_rewrite_(0, scope->zone()),
+ reported_errors_(16, scope->zone()),
factory_(factory),
next_function_is_parenthesized_(false),
this_function_is_parenthesized_(false) {
@@ -1552,12 +1567,11 @@
// Parentheses are not valid on the LHS of a BindingPattern, so we use the
// is_valid_binding_pattern() check to detect multiple levels of
// parenthesization.
- if (!classifier->is_valid_binding_pattern()) {
- ArrowFormalParametersUnexpectedToken(classifier);
- }
+ bool pattern_error = !classifier->is_valid_binding_pattern();
classifier->RecordPatternError(scanner()->peek_location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::LPAREN));
+ if (pattern_error) ArrowFormalParametersUnexpectedToken(classifier);
Consume(Token::LPAREN);
if (Check(Token::RPAREN)) {
// ()=>x. The continuation that looks for the => is in
@@ -1575,8 +1589,11 @@
MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
classifier->RecordNonSimpleParameter();
- ExpressionT expr =
- this->ParseAssignmentExpression(true, classifier, CHECK_OK);
+ ExpressionClassifier binding_classifier(this);
+ ExpressionT expr = this->ParseAssignmentExpression(
+ true, &binding_classifier, CHECK_OK);
+ classifier->Accumulate(&binding_classifier,
+ ExpressionClassifier::AllProductions);
if (!this->IsIdentifier(expr) && !IsValidPattern(expr)) {
classifier->RecordArrowFormalParametersError(
Scanner::Location(ellipsis_pos, scanner()->location().end_pos),
@@ -1663,11 +1680,14 @@
// AssignmentExpression
// Expression ',' AssignmentExpression
- ExpressionClassifier binding_classifier(this);
- ExpressionT result =
- this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
- classifier->Accumulate(&binding_classifier,
- ExpressionClassifier::AllProductions);
+ ExpressionT result = this->EmptyExpression();
+ {
+ ExpressionClassifier binding_classifier(this);
+ result = this->ParseAssignmentExpression(accept_IN, &binding_classifier,
+ CHECK_OK);
+ classifier->Accumulate(&binding_classifier,
+ ExpressionClassifier::AllProductions);
+ }
bool is_simple_parameter_list = this->IsIdentifier(result);
bool seen_rest = false;
while (peek() == Token::COMMA) {
@@ -1690,6 +1710,7 @@
seen_rest = is_rest = true;
}
int pos = position(), expr_pos = peek_position();
+ ExpressionClassifier binding_classifier(this);
ExpressionT right = this->ParseAssignmentExpression(
accept_IN, &binding_classifier, CHECK_OK);
classifier->Accumulate(&binding_classifier,
@@ -1777,7 +1798,15 @@
literal_index, pos);
if (first_spread_index >= 0) {
result = factory()->NewRewritableExpression(result);
- Traits::QueueNonPatternForRewriting(result);
+ Traits::QueueNonPatternForRewriting(result, ok);
+ if (!*ok) {
+ // If the non-pattern rewriting mechanism is used in the future for
+ // rewriting other things than spreads, this error message will have
+ // to change. Also, this error message will never appear while pre-
+ // parsing (this is OK, as it is an implementation limitation).
+ ReportMessage(MessageTemplate::kTooManySpreads);
+ return this->EmptyExpression();
+ }
}
return result;
}
@@ -1917,10 +1946,16 @@
classifier->RecordLetPatternError(
scanner()->location(), MessageTemplate::kLetInLexicalBinding);
}
- if (is_await && is_async_function()) {
- classifier->RecordPatternError(
- Scanner::Location(next_beg_pos, next_end_pos),
- MessageTemplate::kAwaitBindingIdentifier);
+ if (is_await) {
+ if (is_async_function()) {
+ classifier->RecordPatternError(
+ Scanner::Location(next_beg_pos, next_end_pos),
+ MessageTemplate::kAwaitBindingIdentifier);
+ } else {
+ classifier->RecordAsyncArrowFormalParametersError(
+ Scanner::Location(next_beg_pos, next_end_pos),
+ MessageTemplate::kAwaitBindingIdentifier);
+ }
}
ExpressionT lhs = this->ExpressionFromIdentifier(
*name, next_beg_pos, next_end_pos, scope_, factory());
@@ -1941,9 +1976,7 @@
Scanner::Location(next_beg_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidCoverInitializedName);
- if (allow_harmony_function_name()) {
- Traits::SetFunctionNameFromIdentifierRef(rhs, lhs);
- }
+ Traits::SetFunctionNameFromIdentifierRef(rhs, lhs);
} else {
value = lhs;
}
@@ -2098,9 +2131,7 @@
if (fni_ != nullptr) fni_->Infer();
- if (allow_harmony_function_name()) {
- Traits::SetFunctionNameFromPropertyName(property, name);
- }
+ Traits::SetFunctionNameFromPropertyName(property, name);
}
Expect(Token::RBRACE, CHECK_OK);
@@ -2135,7 +2166,10 @@
ExpressionT argument = this->ParseAssignmentExpression(
true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
CheckNoTailCallExpressions(classifier, CHECK_OK_CUSTOM(NullExpressionList));
- Traits::RewriteNonPattern(classifier, CHECK_OK_CUSTOM(NullExpressionList));
+ if (!maybe_arrow) {
+ Traits::RewriteNonPattern(classifier,
+ CHECK_OK_CUSTOM(NullExpressionList));
+ }
if (is_spread) {
if (!spread_arg.IsValid()) {
spread_arg.beg_pos = start_pos;
@@ -2172,11 +2206,17 @@
}
*first_spread_arg_loc = spread_arg;
- if ((!maybe_arrow || peek() != Token::ARROW) && spread_arg.IsValid()) {
- // Unspread parameter sequences are translated into array literals in the
- // parser. Ensure that the number of materialized literals matches between
- // the parser and preparser
- Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
+ if (!maybe_arrow || peek() != Token::ARROW) {
+ if (maybe_arrow) {
+ Traits::RewriteNonPattern(classifier,
+ CHECK_OK_CUSTOM(NullExpressionList));
+ }
+ if (spread_arg.IsValid()) {
+ // Unspread parameter sequences are translated into array literals in the
+ // parser. Ensure that the number of materialized literals matches between
+ // the parser and preparser
+ Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
+ }
}
return result;
@@ -2206,7 +2246,8 @@
classifier->duplicate_finder());
bool is_async = allow_harmony_async_await() && peek() == Token::ASYNC &&
- !scanner()->HasAnyLineTerminatorAfterNext();
+ !scanner()->HasAnyLineTerminatorAfterNext() &&
+ IsValidArrowFormalParametersStart(PeekAhead());
bool parenthesized_formals = peek() == Token::LPAREN;
if (!is_async && !parenthesized_formals) {
@@ -2224,9 +2265,7 @@
}
if (peek() == Token::ARROW) {
- classifier->RecordPatternError(scanner()->peek_location(),
- MessageTemplate::kUnexpectedToken,
- Token::String(Token::ARROW));
+ Scanner::Location arrow_loc = scanner()->peek_location();
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
parenthesized_formals, is_async, CHECK_OK);
// This reads strangely, but is correct: it checks whether any
@@ -2263,6 +2302,10 @@
}
expression = this->ParseArrowFunctionLiteral(
accept_IN, parameters, is_async, arrow_formals_classifier, CHECK_OK);
+ arrow_formals_classifier.Discard();
+ classifier->RecordPatternError(arrow_loc,
+ MessageTemplate::kUnexpectedToken,
+ Token::String(Token::ARROW));
if (fni_ != nullptr) fni_->Infer();
@@ -2352,7 +2395,7 @@
}
}
- if (op == Token::ASSIGN && allow_harmony_function_name()) {
+ if (op == Token::ASSIGN) {
Traits::SetFunctionNameFromIdentifierRef(right, expression);
}
@@ -2457,6 +2500,12 @@
*ok = false;
return Traits::EmptyExpression();
}
+ if (is_resumable()) {
+ Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
+ ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCall);
+ *ok = false;
+ return Traits::EmptyExpression();
+ }
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
@@ -2502,8 +2551,8 @@
if (peek() != Token::CONDITIONAL) return expression;
CheckNoTailCallExpressions(classifier, CHECK_OK);
Traits::RewriteNonPattern(classifier, CHECK_OK);
- ArrowFormalParametersUnexpectedToken(classifier);
BindingPatternUnexpectedToken(classifier);
+ ArrowFormalParametersUnexpectedToken(classifier);
Consume(Token::CONDITIONAL);
// In parsing the first assignment expression in conditional
// expressions we always accept the 'in' keyword; see ECMA-262,
@@ -2667,6 +2716,8 @@
default:
break;
}
+
+ int await_pos = peek_position();
Consume(Token::AWAIT);
ExpressionT value = ParseUnaryExpression(classifier, CHECK_OK);
@@ -2674,7 +2725,7 @@
classifier->RecordFormalParameterInitializerError(
Scanner::Location(beg_pos, scanner()->location().end_pos),
MessageTemplate::kAwaitExpressionFormalParameter);
- return Traits::RewriteAwaitExpression(value, beg_pos);
+ return Traits::RewriteAwaitExpression(value, await_pos);
} else {
return this->ParsePostfixExpression(classifier, ok);
}
@@ -3148,9 +3199,7 @@
init_classifier.Discard();
classifier->RecordNonSimpleParameter();
- if (allow_harmony_function_name()) {
- Traits::SetFunctionNameFromIdentifierRef(initializer, pattern);
- }
+ Traits::SetFunctionNameFromIdentifierRef(initializer, pattern);
}
Traits::AddFormalParameter(parameters, pattern, initializer,
@@ -3317,7 +3366,6 @@
} else {
// Single-expression body
int pos = position();
- ExpressionClassifier classifier(this);
DCHECK(ReturnExprContext::kInsideValidBlock ==
function_state_->return_expr_context());
ReturnExprScope allow_tail_calls(
@@ -3325,6 +3373,7 @@
body = this->NewStatementList(1, zone());
this->AddParameterInitializationBlock(formal_parameters, body, is_async,
CHECK_OK);
+ ExpressionClassifier classifier(this);
if (is_async) {
this->ParseAsyncArrowSingleExpressionBody(body, accept_IN, &classifier,
pos, CHECK_OK);
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index 822c49e..a39d0ee 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -205,7 +205,16 @@
body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone());
if (call_super) {
// $super_constructor = %_GetSuperConstructor(<this-function>)
- // %reflect_construct($super_constructor, arguments, new.target)
+ // %reflect_construct(
+ // $super_constructor, InternalArray(...args), new.target)
+ auto constructor_args_name = ast_value_factory()->empty_string();
+ bool is_duplicate;
+ bool is_rest = true;
+ bool is_optional = false;
+ Variable* constructor_args =
+ function_scope->DeclareParameter(constructor_args_name, TEMPORARY,
+ is_optional, is_rest, &is_duplicate);
+
ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(2, zone());
VariableProxy* this_function_proxy = scope_->NewUnresolved(
@@ -217,10 +226,12 @@
Expression* super_constructor = factory()->NewCallRuntime(
Runtime::kInlineGetSuperConstructor, tmp, pos);
args->Add(super_constructor, zone());
- VariableProxy* arguments_proxy = scope_->NewUnresolved(
- factory(), ast_value_factory()->arguments_string(), Variable::NORMAL,
- pos);
- args->Add(arguments_proxy, zone());
+ Spread* spread_args = factory()->NewSpread(
+ factory()->NewVariableProxy(constructor_args), pos, pos);
+ ZoneList<Expression*>* spread_args_expr =
+ new (zone()) ZoneList<Expression*>(1, zone());
+ spread_args_expr->Add(spread_args, zone());
+ args->AddAll(*PrepareSpreadArguments(spread_args_expr), zone());
VariableProxy* new_target_proxy = scope_->NewUnresolved(
factory(), ast_value_factory()->new_target_string(), Variable::NORMAL,
pos);
@@ -669,13 +680,14 @@
Expression* ParserTraits::FunctionSentExpression(Scope* scope,
AstNodeFactory* factory,
int pos) {
- // We desugar function.sent into %GeneratorGetInput(generator).
+ // We desugar function.sent into %_GeneratorGetInputOrDebugPos(generator).
Zone* zone = parser_->zone();
ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(1, zone);
VariableProxy* generator = factory->NewVariableProxy(
parser_->function_state_->generator_object_variable());
args->Add(generator, zone);
- return factory->NewCallRuntime(Runtime::kGeneratorGetInput, args, pos);
+ return factory->NewCallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos,
+ args, pos);
}
@@ -796,13 +808,13 @@
info->isolate()->is_tail_call_elimination_enabled());
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
set_allow_harmony_for_in(FLAG_harmony_for_in);
- set_allow_harmony_function_name(FLAG_harmony_function_name);
set_allow_harmony_function_sent(FLAG_harmony_function_sent);
set_allow_harmony_restrictive_declarations(
FLAG_harmony_restrictive_declarations);
set_allow_harmony_exponentiation_operator(
FLAG_harmony_exponentiation_operator);
set_allow_harmony_async_await(FLAG_harmony_async_await);
+ set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
use_counts_[feature] = 0;
@@ -1971,10 +1983,24 @@
} else if (IsLexicalVariableMode(mode) ||
IsLexicalVariableMode(var->mode())) {
// Allow duplicate function decls for web compat, see bug 4693.
+ bool duplicate_allowed = false;
if (is_sloppy(language_mode()) && is_function_declaration &&
var->is_function()) {
DCHECK(IsLexicalVariableMode(mode) &&
IsLexicalVariableMode(var->mode()));
+ // If the duplication is allowed, then the var will show up
+ // in the SloppyBlockFunctionMap and the new FunctionKind
+ // will be a permitted duplicate.
+ FunctionKind function_kind =
+ declaration->AsFunctionDeclaration()->fun()->kind();
+ duplicate_allowed =
+ scope->DeclarationScope()->sloppy_block_function_map()->Lookup(
+ const_cast<AstRawString*>(name), name->hash()) != nullptr &&
+ !IsAsyncFunction(function_kind) &&
+ !(allow_harmony_restrictive_generators() &&
+ IsGeneratorFunction(function_kind));
+ }
+ if (duplicate_allowed) {
++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
} else {
// The name was declared in this scope before; check for conflicting
@@ -2010,13 +2036,12 @@
// In a var binding in a sloppy direct eval, pollute the enclosing scope
// with this new binding by doing the following:
// The proxy is bound to a lookup variable to force a dynamic declaration
- // using the DeclareLookupSlot runtime function.
+ // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
Variable::Kind kind = Variable::NORMAL;
// TODO(sigurds) figure out if kNotAssigned is OK here
var = new (zone()) Variable(declaration_scope, name, mode, kind,
declaration->initialization(), kNotAssigned);
var->AllocateTo(VariableLocation::LOOKUP, -1);
- var->SetFromEval();
resolve = true;
}
@@ -2036,7 +2061,7 @@
// same variable if it is declared several times. This is not a
// semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated
- // RuntimeHidden_DeclareLookupSlot calls.
+ // DeclareEvalVar or DeclareEvalFunction calls.
declaration_scope->AddDeclaration(declaration);
// If requested and we have a local variable, bind the proxy to the variable
@@ -2188,7 +2213,13 @@
Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
if (names) names->Add(name, zone());
EmptyStatement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
- if (is_sloppy(language_mode()) && !scope_->is_declaration_scope()) {
+ // Async functions don't undergo sloppy mode block scoped hoisting, and don't
+ // allow duplicates in a block. Both are represented by the
+ // sloppy_block_function_map. Don't add them to the map for async functions.
+ // Generators are also supposed to be prohibited; currently doing this behind
+ // a flag and UseCounting violations to assess web compatibility.
+ if (is_sloppy(language_mode()) && !scope_->is_declaration_scope() &&
+ !is_async && !(allow_harmony_restrictive_generators() && is_generator)) {
SloppyBlockFunctionStatement* delegate =
factory()->NewSloppyBlockFunctionStatement(empty, scope_);
scope_->DeclarationScope()->sloppy_block_function_map()->Declare(name,
@@ -2412,9 +2443,7 @@
}
}
- if (allow_harmony_function_name()) {
- ParserTraits::SetFunctionNameFromIdentifierRef(value, pattern);
- }
+ ParserTraits::SetFunctionNameFromIdentifierRef(value, pattern);
// End position of the initializer is after the assignment expression.
initializer_position = scanner()->location().end_pos;
@@ -2518,7 +2547,6 @@
ReportUnexpectedToken(Next());
*ok = false;
return nullptr;
-
default:
break;
}
@@ -2725,7 +2753,7 @@
Expression* is_spec_object_call = factory()->NewCallRuntime(
Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
- // %_IsJSReceiver(temp) ? temp : throw_expression
+ // %_IsJSReceiver(temp) ? temp : 1;
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
factory()->NewSmiLiteral(1, pos), pos);
@@ -2744,7 +2772,7 @@
function_state_, ReturnExprContext::kInsideValidReturnStatement);
return_value = ParseExpression(true, CHECK_OK);
- if (allow_tailcalls() && !is_sloppy(language_mode())) {
+ if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
function_state_->AddImplicitTailCallExpression(return_value);
}
@@ -2970,40 +2998,40 @@
catch_scope = NewScope(scope_, CATCH_SCOPE);
catch_scope->set_start_position(scanner()->location().beg_pos);
- ExpressionClassifier pattern_classifier(this);
- Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
- ValidateBindingPattern(&pattern_classifier, CHECK_OK);
-
- const AstRawString* name = ast_value_factory()->dot_catch_string();
- bool is_simple = pattern->IsVariableProxy();
- if (is_simple) {
- auto proxy = pattern->AsVariableProxy();
- scope_->RemoveUnresolved(proxy);
- name = proxy->raw_name();
- }
-
- catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
- Variable::NORMAL);
-
- Expect(Token::RPAREN, CHECK_OK);
-
{
CollectExpressionsInTailPositionToListScope
collect_tail_call_expressions_scope(
function_state_, &tail_call_expressions_in_catch_block);
BlockState block_state(&scope_, catch_scope);
- // TODO(adamk): Make a version of ParseBlock that takes a scope and
- // a block.
catch_block =
factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
- Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
+ // Create a block scope to hold any lexical declarations created
+ // as part of destructuring the catch parameter.
+ Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
block_scope->set_start_position(scanner()->location().beg_pos);
{
BlockState block_state(&scope_, block_scope);
Target target(&this->target_stack_, catch_block);
+ ExpressionClassifier pattern_classifier(this);
+ Expression* pattern =
+ ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+ ValidateBindingPattern(&pattern_classifier, CHECK_OK);
+
+ const AstRawString* name = ast_value_factory()->dot_catch_string();
+ bool is_simple = pattern->IsVariableProxy();
+ if (is_simple) {
+ auto proxy = pattern->AsVariableProxy();
+ scope_->RemoveUnresolved(proxy);
+ name = proxy->raw_name();
+ }
+ catch_variable = catch_scope->DeclareLocal(
+ name, VAR, kCreatedInitialized, Variable::NORMAL);
+
+ Expect(Token::RPAREN, CHECK_OK);
+
if (!is_simple) {
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
@@ -3028,6 +3056,8 @@
catch_block->statements()->Add(init_block, zone());
}
+ // TODO(adamk): This should call ParseBlock in order to properly
+ // add an additional block scope for the catch body.
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
Statement* stat = ParseStatementListItem(CHECK_OK);
@@ -4705,7 +4735,7 @@
// We produce:
//
// try { InitialYield; ...body...; return {value: undefined, done: true} }
- // finally { %GeneratorClose(generator) }
+ // finally { %_GeneratorClose(generator) }
//
// - InitialYield yields the actual generator object.
// - Any return statement inside the body will have its argument wrapped
@@ -4724,8 +4754,11 @@
Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
VariableProxy* get_proxy = factory()->NewVariableProxy(
function_state_->generator_object_variable());
- Yield* yield =
- factory()->NewYield(get_proxy, assignment, RelocInfo::kNoPosition);
+ // The position of the yield is important for reporting the exception
+ // caused by calling the .throw method on a generator suspended at the
+ // initial yield (i.e. right after generator instantiation).
+ Yield* yield = factory()->NewYield(get_proxy, assignment,
+ scope_->start_position());
try_block->statements()->Add(
factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
zone());
@@ -4745,7 +4778,7 @@
function_state_->generator_object_variable());
args->Add(call_proxy, zone());
Expression* call = factory()->NewCallRuntime(
- Runtime::kGeneratorClose, args, RelocInfo::kNoPosition);
+ Runtime::kInlineGeneratorClose, args, RelocInfo::kNoPosition);
finally_block->statements()->Add(
factory()->NewExpressionStatement(call, RelocInfo::kNoPosition),
zone());
@@ -4844,7 +4877,6 @@
SET_ALLOW(natives);
SET_ALLOW(harmony_do_expressions);
SET_ALLOW(harmony_for_in);
- SET_ALLOW(harmony_function_name);
SET_ALLOW(harmony_function_sent);
SET_ALLOW(harmony_exponentiation_operator);
SET_ALLOW(harmony_restrictive_declarations);
@@ -4943,8 +4975,7 @@
if (fni_ != NULL) fni_->Infer();
- if (allow_harmony_function_name() &&
- property_name != ast_value_factory()->constructor_string()) {
+ if (property_name != ast_value_factory()->constructor_string()) {
SetFunctionNameFromPropertyName(property, property_name);
}
}
@@ -4953,7 +4984,7 @@
int end_pos = scanner()->location().end_pos;
if (constructor == NULL) {
- constructor = DefaultConstructor(name, extends != NULL, block_scope, pos,
+ constructor = DefaultConstructor(name, has_extends, block_scope, pos,
end_pos, block_scope->language_mode());
}
@@ -5189,7 +5220,7 @@
// Move statistics to Isolate.
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) {
- for (int i = 0; i < use_counts_[feature]; ++i) {
+ if (use_counts_[feature] > 0) {
isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
}
}
@@ -5586,7 +5617,8 @@
parser_->RewriteNonPattern(classifier, ok);
}
-Expression* ParserTraits::RewriteAwaitExpression(Expression* value, int pos) {
+Expression* ParserTraits::RewriteAwaitExpression(Expression* value,
+ int await_pos) {
// yield %AsyncFunctionAwait(.generator_object, <operand>)
Variable* generator_object_variable =
parser_->function_state_->generator_object_variable();
@@ -5594,33 +5626,56 @@
// If generator_object_variable is null,
if (!generator_object_variable) return value;
- Expression* generator_object =
- parser_->factory()->NewVariableProxy(generator_object_variable);
+ auto factory = parser_->factory();
+ const int nopos = RelocInfo::kNoPosition;
+
+ Variable* temp_var = parser_->scope_->NewTemporary(
+ parser_->ast_value_factory()->empty_string());
+ VariableProxy* temp_proxy = factory->NewVariableProxy(temp_var);
+ Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
+
+ // Wrap value evaluation to provide a break location.
+ Expression* value_assignment =
+ factory->NewAssignment(Token::ASSIGN, temp_proxy, value, nopos);
+ do_block->statements()->Add(
+ factory->NewExpressionStatement(value_assignment, value->position()),
+ zone());
ZoneList<Expression*>* async_function_await_args =
new (zone()) ZoneList<Expression*>(2, zone());
+ Expression* generator_object =
+ factory->NewVariableProxy(generator_object_variable);
async_function_await_args->Add(generator_object, zone());
- async_function_await_args->Add(value, zone());
+ async_function_await_args->Add(temp_proxy, zone());
Expression* async_function_await = parser_->factory()->NewCallRuntime(
- Context::ASYNC_FUNCTION_AWAIT_INDEX, async_function_await_args,
- RelocInfo::kNoPosition);
+ Context::ASYNC_FUNCTION_AWAIT_INDEX, async_function_await_args, nopos);
+ // Wrap await to provide a break location between value evaluation and yield.
+ Expression* await_assignment = factory->NewAssignment(
+ Token::ASSIGN, temp_proxy, async_function_await, nopos);
+ do_block->statements()->Add(
+ factory->NewExpressionStatement(await_assignment, await_pos), zone());
+ Expression* do_expr = factory->NewDoExpression(do_block, temp_var, nopos);
- generator_object =
- parser_->factory()->NewVariableProxy(generator_object_variable);
- return parser_->factory()->NewYield(generator_object, async_function_await,
- pos);
+ generator_object = factory->NewVariableProxy(generator_object_variable);
+ return factory->NewYield(generator_object, do_expr, nopos);
}
-Zone* ParserTraits::zone() const {
- return parser_->function_state_->scope()->zone();
-}
-
-
ZoneList<Expression*>* ParserTraits::GetNonPatternList() const {
return parser_->function_state_->non_patterns_to_rewrite();
}
+ZoneList<typename ParserTraits::Type::ExpressionClassifier::Error>*
+ParserTraits::GetReportedErrorList() const {
+ return parser_->function_state_->GetReportedErrorList();
+}
+
+
+Zone* ParserTraits::zone() const {
+ return parser_->function_state_->scope()->zone();
+}
+
+
class NonPatternRewriter : public AstExpressionRewriter {
public:
NonPatternRewriter(uintptr_t stack_limit, Parser* parser)
@@ -5834,9 +5889,9 @@
}
-void ParserTraits::QueueNonPatternForRewriting(Expression* expr) {
+void ParserTraits::QueueNonPatternForRewriting(Expression* expr, bool* ok) {
DCHECK(expr->IsRewritableExpression());
- parser_->function_state_->AddNonPatternForRewriting(expr);
+ parser_->function_state_->AddNonPatternForRewriting(expr, ok);
}
@@ -6529,8 +6584,6 @@
void ParserTraits::FinalizeIteratorUse(Variable* completion,
Expression* condition, Variable* iter,
Block* iterator_use, Block* target) {
- if (!FLAG_harmony_iterator_close) return;
-
//
// This function adds two statements to [target], corresponding to the
// following code:
@@ -6813,8 +6866,6 @@
Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
- if (!FLAG_harmony_iterator_close) return loop;
-
//
// This function replaces the loop with the following wrapping:
//
diff --git a/src/parsing/parser.h b/src/parsing/parser.h
index 174b983..472dab9 100644
--- a/src/parsing/parser.h
+++ b/src/parsing/parser.h
@@ -658,7 +658,7 @@
V8_INLINE void QueueDestructuringAssignmentForRewriting(
Expression* assignment);
- V8_INLINE void QueueNonPatternForRewriting(Expression* expr);
+ V8_INLINE void QueueNonPatternForRewriting(Expression* expr, bool* ok);
void SetFunctionNameFromPropertyName(ObjectLiteralProperty* property,
const AstRawString* name);
@@ -670,6 +670,8 @@
V8_INLINE void RewriteNonPattern(Type::ExpressionClassifier* classifier,
bool* ok);
+ V8_INLINE ZoneList<typename Type::ExpressionClassifier::Error>*
+ GetReportedErrorList() const;
V8_INLINE Zone* zone() const;
V8_INLINE ZoneList<Expression*>* GetNonPatternList() const;
diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc
index 3dcff98..970231b 100644
--- a/src/parsing/pattern-rewriter.cc
+++ b/src/parsing/pattern-rewriter.cc
@@ -461,9 +461,7 @@
// wrap this new block in a try-finally statement, restore block_ to its
// original value, and add the try-finally statement to block_.
auto target = block_;
- if (FLAG_harmony_iterator_close) {
- block_ = factory()->NewBlock(nullptr, 8, true, nopos);
- }
+ block_ = factory()->NewBlock(nullptr, 8, true, nopos);
Spread* spread = nullptr;
for (Expression* value : *node->values()) {
@@ -551,7 +549,7 @@
block_->statements()->Add(if_not_done, zone());
if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
- if (FLAG_harmony_iterator_close) {
+ {
// completion = kAbruptCompletion;
Expression* proxy = factory()->NewVariableProxy(completion);
Expression* assignment = factory()->NewAssignment(
@@ -563,7 +561,7 @@
RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
- if (FLAG_harmony_iterator_close) {
+ {
// completion = kNormalCompletion;
Expression* proxy = factory()->NewVariableProxy(completion);
Expression* assignment = factory()->NewAssignment(
@@ -676,13 +674,11 @@
factory()->NewVariableProxy(array));
}
- if (FLAG_harmony_iterator_close) {
- Expression* closing_condition = factory()->NewUnaryOperation(
- Token::NOT, factory()->NewVariableProxy(done), nopos);
- parser_->FinalizeIteratorUse(completion, closing_condition, iterator,
- block_, target);
- block_ = target;
- }
+ Expression* closing_condition = factory()->NewUnaryOperation(
+ Token::NOT, factory()->NewVariableProxy(done), nopos);
+ parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
+ target);
+ block_ = target;
}
diff --git a/src/parsing/preparse-data.cc b/src/parsing/preparse-data.cc
index d02cd63..e1ef74c 100644
--- a/src/parsing/preparse-data.cc
+++ b/src/parsing/preparse-data.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/parsing/preparse-data.h"
+#include "src/base/hashmap.h"
#include "src/base/logging.h"
#include "src/globals.h"
-#include "src/hashmap.h"
#include "src/parsing/parser.h"
-#include "src/parsing/preparse-data.h"
#include "src/parsing/preparse-data-format.h"
namespace v8 {
diff --git a/src/parsing/preparse-data.h b/src/parsing/preparse-data.h
index 1c99450..ddc4d03 100644
--- a/src/parsing/preparse-data.h
+++ b/src/parsing/preparse-data.h
@@ -6,8 +6,8 @@
#define V8_PARSING_PREPARSE_DATA_H_
#include "src/allocation.h"
+#include "src/base/hashmap.h"
#include "src/collector.h"
-#include "src/hashmap.h"
#include "src/messages.h"
#include "src/parsing/preparse-data-format.h"
diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc
index 0a091c6..08d5eaf 100644
--- a/src/parsing/preparser.cc
+++ b/src/parsing/preparser.cc
@@ -9,7 +9,6 @@
#include "src/conversions-inl.h"
#include "src/conversions.h"
#include "src/globals.h"
-#include "src/hashmap.h"
#include "src/list.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/preparse-data-format.h"
diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
index 16eeab4..8eb95e7 100644
--- a/src/parsing/preparser.h
+++ b/src/parsing/preparser.h
@@ -7,7 +7,7 @@
#include "src/ast/scopes.h"
#include "src/bailout-reason.h"
-#include "src/hashmap.h"
+#include "src/base/hashmap.h"
#include "src/messages.h"
#include "src/parsing/expression-classifier.h"
#include "src/parsing/func-name-inferrer.h"
@@ -974,7 +974,7 @@
}
inline void QueueDestructuringAssignmentForRewriting(PreParserExpression) {}
- inline void QueueNonPatternForRewriting(PreParserExpression) {}
+ inline void QueueNonPatternForRewriting(PreParserExpression, bool* ok) {}
void SetFunctionNameFromPropertyName(PreParserExpression,
PreParserIdentifier) {}
@@ -987,6 +987,8 @@
inline PreParserExpression RewriteAwaitExpression(PreParserExpression value,
int pos);
+ V8_INLINE ZoneList<typename Type::ExpressionClassifier::Error>*
+ GetReportedErrorList() const;
V8_INLINE Zone* zone() const;
V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const;
@@ -1214,13 +1216,19 @@
return value;
}
-Zone* PreParserTraits::zone() const {
- return pre_parser_->function_state_->scope()->zone();
+ZoneList<PreParserExpression>* PreParserTraits::GetNonPatternList() const {
+ return pre_parser_->function_state_->non_patterns_to_rewrite();
}
-ZoneList<PreParserExpression>* PreParserTraits::GetNonPatternList() const {
- return pre_parser_->function_state_->non_patterns_to_rewrite();
+ZoneList<typename PreParserTraits::Type::ExpressionClassifier::Error>*
+PreParserTraits::GetReportedErrorList() const {
+ return pre_parser_->function_state_->GetReportedErrorList();
+}
+
+
+Zone* PreParserTraits::zone() const {
+ return pre_parser_->function_state_->scope()->zone();
}
diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc
index 6a9b32e..5fc848f 100644
--- a/src/parsing/scanner.cc
+++ b/src/parsing/scanner.cc
@@ -839,9 +839,6 @@
}
-const int kMaxAscii = 127;
-
-
Token::Value Scanner::ScanString() {
uc32 quote = c0_;
Advance<false, false>(); // consume quote
@@ -858,7 +855,7 @@
Advance<false, false>();
return Token::STRING;
}
- uc32 c = c0_;
+ char c = static_cast<char>(c0_);
if (c == '\\') break;
Advance<false, false>();
AddLiteralChar(c);
@@ -1283,7 +1280,7 @@
LiteralScope literal(this);
if (IsInRange(c0_, 'a', 'z')) {
do {
- uc32 first_char = c0_;
+ char first_char = static_cast<char>(c0_);
Advance<false, false>();
AddLiteralChar(first_char);
} while (IsInRange(c0_, 'a', 'z'));
@@ -1291,11 +1288,11 @@
if (IsDecimalDigit(c0_) || IsInRange(c0_, 'A', 'Z') || c0_ == '_' ||
c0_ == '$') {
// Identifier starting with lowercase.
- uc32 first_char = c0_;
+ char first_char = static_cast<char>(c0_);
Advance<false, false>();
AddLiteralChar(first_char);
while (IsAsciiIdentifier(c0_)) {
- uc32 first_char = c0_;
+ char first_char = static_cast<char>(c0_);
Advance<false, false>();
AddLiteralChar(first_char);
}
@@ -1313,7 +1310,7 @@
HandleLeadSurrogate();
} else if (IsInRange(c0_, 'A', 'Z') || c0_ == '_' || c0_ == '$') {
do {
- uc32 first_char = c0_;
+ char first_char = static_cast<char>(c0_);
Advance<false, false>();
AddLiteralChar(first_char);
} while (IsAsciiIdentifier(c0_));
@@ -1456,7 +1453,6 @@
flag = RegExp::kMultiline;
break;
case 'u':
- if (!FLAG_harmony_unicode_regexps) return Nothing<RegExp::Flags>();
flag = RegExp::kUnicode;
break;
case 'y':
@@ -1590,7 +1586,7 @@
int value) {
uint32_t hash = Hash(key, is_one_byte);
byte* encoding = BackupKey(key, is_one_byte);
- HashMap::Entry* entry = map_.LookupOrInsert(encoding, hash);
+ base::HashMap::Entry* entry = map_.LookupOrInsert(encoding, hash);
int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
entry->value =
reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
diff --git a/src/parsing/scanner.h b/src/parsing/scanner.h
index 0acc7ab..610091c 100644
--- a/src/parsing/scanner.h
+++ b/src/parsing/scanner.h
@@ -8,16 +8,16 @@
#define V8_PARSING_SCANNER_H_
#include "src/allocation.h"
+#include "src/base/hashmap.h"
#include "src/base/logging.h"
#include "src/char-predicates.h"
#include "src/collector.h"
#include "src/globals.h"
-#include "src/hashmap.h"
#include "src/list.h"
#include "src/messages.h"
#include "src/parsing/token.h"
-#include "src/unicode.h"
#include "src/unicode-decoder.h"
+#include "src/unicode.h"
namespace v8 {
namespace internal {
@@ -143,22 +143,32 @@
UnicodeCache* unicode_constants_;
// Backing store used to store strings used as hashmap keys.
SequenceCollector<unsigned char> backing_store_;
- HashMap map_;
+ base::HashMap map_;
// Buffer used for string->number->canonical string conversions.
char number_buffer_[kBufferSize];
};
-
// ----------------------------------------------------------------------------
// LiteralBuffer - Collector of chars of literals.
+const int kMaxAscii = 127;
+
class LiteralBuffer {
public:
LiteralBuffer() : is_one_byte_(true), position_(0), backing_store_() { }
~LiteralBuffer() { backing_store_.Dispose(); }
- INLINE(void AddChar(uint32_t code_unit)) {
+ INLINE(void AddChar(char code_unit)) {
+ if (position_ >= backing_store_.length()) ExpandBuffer();
+ DCHECK(is_one_byte_);
+ DCHECK(0 <= code_unit && code_unit <= kMaxAscii);
+ backing_store_[position_] = static_cast<byte>(code_unit);
+ position_ += kOneByteSize;
+ return;
+ }
+
+ INLINE(void AddChar(uc32 code_unit)) {
if (position_ >= backing_store_.length()) ExpandBuffer();
if (is_one_byte_) {
if (code_unit <= unibrow::Latin1::kMaxChar) {
@@ -557,6 +567,11 @@
next_.literal_chars->AddChar(c);
}
+ INLINE(void AddLiteralChar(char c)) {
+ DCHECK_NOT_NULL(next_.literal_chars);
+ next_.literal_chars->AddChar(c);
+ }
+
INLINE(void AddRawLiteralChar(uc32 c)) {
DCHECK_NOT_NULL(next_.raw_literal_chars);
next_.raw_literal_chars->AddChar(c);