[parser] Create arrow function scopes while parsing the head

This simplifies NextArrowFunctionInfo, allows us to Scope::Snapshot::Reparent
directly rather than moving it, and allows us to skip reparenting in the simple
parameter arrow function cases.

This is a reland of https://chromium-review.googlesource.com/c/v8/v8/+/1397664,
simply splitting out the arrow-function-name-inferring part.

Change-Id: I640d911a9607edc3bbb0e5ff3bf992094e4159e4
Reviewed-on: https://chromium-review.googlesource.com/c/1397701
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58570}
This commit is contained in:
Toon Verwaest 2019-01-07 11:38:47 +01:00 committed by Commit Bot
parent b962c07107
commit 76f8893699
3 changed files with 48 additions and 64 deletions

View File

@ -888,11 +888,15 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
outer_closure->locals_.Rewind(top_local_);
// Move eval calls since Snapshot's creation into new_parent.
if (outer_scope_and_calls_eval_.GetPayload()) {
if (outer_scope_and_calls_eval_->scope_calls_eval_) {
new_parent->scope_calls_eval_ = true;
new_parent->inner_scope_calls_eval_ = true;
}
// We are in the arrow function case. The calls eval we may have recorded
// is intended for the inner scope and we should simply restore the
// original "calls eval" flag of the outer scope.
RestoreEvalFlag();
Clear();
}

View File

@ -147,24 +147,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
outer_scope_and_calls_eval_.GetPayload();
}
Snapshot& operator=(Snapshot&& source) V8_NOEXCEPT {
outer_scope_and_calls_eval_.SetPointer(
source.outer_scope_and_calls_eval_.GetPointer());
outer_scope_and_calls_eval_.SetPayload(
outer_scope_and_calls_eval_->scope_calls_eval_);
top_inner_scope_ = source.top_inner_scope_;
top_unresolved_ = source.top_unresolved_;
top_local_ = source.top_local_;
// We are in the arrow function case. The calls eval we may have recorded
// is intended for the inner scope and we should simply restore the
// original "calls eval" flag of the outer scope.
source.RestoreEvalFlag();
source.Clear();
return *this;
}
void Reparent(DeclarationScope* new_parent);
bool IsCleared() const {
return outer_scope_and_calls_eval_.GetPointer() == nullptr;

View File

@ -271,8 +271,6 @@ class ParserBase {
pointer_buffer_.reserve(128);
}
~ParserBase() { next_arrow_function_info_.scope_snapshot.Clear(); }
#define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \
void set_allow_##name(bool allow) { allow_##name##_ = allow; }
@ -1369,7 +1367,6 @@ class ParserBase {
// Preallocating the struct as part of the parser minimizes the cost of
// supporting arrow functions on non-arrow expressions.
struct NextArrowFunctionInfo {
Scope::Snapshot scope_snapshot;
// `rewritable_length`: length of the destructuring_assignments_to_rewrite()
// queue in the parent function state, prior to parsing of formal
// parameters. If the arrow function is lazy, any items added during formal
@ -1378,19 +1375,15 @@ class ParserBase {
Scanner::Location strict_parameter_error_location =
Scanner::Location::invalid();
MessageTemplate strict_parameter_error_message = MessageTemplate::kNone;
FunctionKind kind = FunctionKind::kArrowFunction;
bool has_simple_parameter_list = true;
DeclarationScope* scope = nullptr;
bool HasInitialState() const {
return rewritable_length == -1 && scope_snapshot.IsCleared() &&
kind == FunctionKind::kArrowFunction && has_simple_parameter_list;
return rewritable_length == -1 && scope == nullptr;
}
void Reset() {
rewritable_length = -1;
scope_snapshot.Clear();
kind = FunctionKind::kArrowFunction;
has_simple_parameter_list = true;
scope = nullptr;
ClearStrictParameterError();
DCHECK(HasInitialState());
}
@ -1646,8 +1639,7 @@ ParserBase<Impl>::ParsePrimaryExpression() {
if (Token::IsAnyIdentifier(token)) {
Consume(token);
IdentifierT name;
InferName infer = InferName::kYes;
FunctionKind kind = FunctionKind::kArrowFunction;
if (V8_UNLIKELY(token == Token::ASYNC &&
!scanner()->HasLineTerminatorBeforeNext())) {
@ -1658,28 +1650,30 @@ ParserBase<Impl>::ParsePrimaryExpression() {
if (peek_any_identifier() && PeekAhead() == Token::ARROW) {
token = Next();
beg_pos = position();
next_arrow_function_info_.kind = FunctionKind::kAsyncArrowFunction;
infer = InferName::kNo;
kind = FunctionKind::kAsyncArrowFunction;
}
}
if (V8_UNLIKELY(peek() == Token::ARROW)) {
next_arrow_function_info_.scope = NewFunctionScope(kind);
ArrowHeadParsingScope parsing_scope(
impl(), next_arrow_function_info_.kind == FunctionKind::kArrowFunction
impl(), kind == FunctionKind::kArrowFunction
? ExpressionScope::kMaybeArrowParameterDeclaration
: ExpressionScope::kMaybeAsyncArrowParameterDeclaration);
next_arrow_function_info_.scope_snapshot =
std::move(Scope::Snapshot(scope()));
next_arrow_function_info_.rewritable_length = static_cast<int>(
function_state_->destructuring_assignments_to_rewrite().size());
name = ParseAndClassifyIdentifier(token);
IdentifierT name = ParseAndClassifyIdentifier(token);
ClassifyParameter(name, beg_pos, end_position());
parsing_scope.ValidateDeclaration();
} else {
name = ParseAndClassifyIdentifier(token);
FunctionState function_state(&function_state_, &scope_,
next_arrow_function_info_.scope);
InferName infer = kind == FunctionKind::kArrowFunction ? InferName::kYes
: InferName::kNo;
return impl()->ExpressionFromIdentifier(name, beg_pos, infer);
}
return impl()->ExpressionFromIdentifier(name, beg_pos, infer);
IdentifierT name = ParseAndClassifyIdentifier(token);
return impl()->ExpressionFromIdentifier(name, beg_pos);
}
if (Token::IsLiteral(token)) {
@ -1704,17 +1698,18 @@ ParserBase<Impl>::ParsePrimaryExpression() {
case Token::LPAREN: {
Consume(Token::LPAREN);
Scope::Snapshot scope_snapshot(scope());
int rewritable_length = static_cast<int>(
function_state_->destructuring_assignments_to_rewrite().size());
if (Check(Token::RPAREN)) {
// ()=>x. The continuation that consumes the => is in
// ParseAssignmentExpressionCoverGrammar.
if (peek() != Token::ARROW) ReportUnexpectedToken(Token::RPAREN);
next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot);
next_arrow_function_info_.scope =
NewFunctionScope(FunctionKind::kArrowFunction);
next_arrow_function_info_.rewritable_length = rewritable_length;
return factory()->NewEmptyParentheses(beg_pos);
}
Scope::Snapshot scope_snapshot(scope());
ArrowHeadParsingScope maybe_arrow(
impl(), ExpressionScope::kMaybeArrowParameterDeclaration);
// Heuristically try to detect immediately called functions before
@ -1729,9 +1724,12 @@ ParserBase<Impl>::ParsePrimaryExpression() {
Expect(Token::RPAREN);
if (peek() == Token::ARROW) {
next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot);
next_arrow_function_info_.has_simple_parameter_list =
maybe_arrow.has_simple_parameter_list();
next_arrow_function_info_.scope =
NewFunctionScope(FunctionKind::kArrowFunction);
scope_snapshot.Reparent(next_arrow_function_info_.scope);
if (!maybe_arrow.has_simple_parameter_list()) {
next_arrow_function_info_.scope->SetHasNonSimpleParameters();
}
next_arrow_function_info_.rewritable_length = rewritable_length;
maybe_arrow.ValidateDeclaration();
} else {
@ -2602,7 +2600,6 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() {
// Arrow functions.
if (V8_UNLIKELY(op == Token::ARROW)) {
Scanner::Location loc(lhs_beg_pos, end_position());
DeclarationScope* scope = NewFunctionScope(next_arrow_function_info_.kind);
if (!impl()->IsIdentifier(expression) && !expression->is_parenthesized()) {
impl()->ReportMessageAt(
@ -2611,20 +2608,15 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() {
return impl()->FailureExpression();
}
// Because the arrow's parameters were parsed in the outer scope,
// we need to fix up the scope chain appropriately.
next_arrow_function_info_.scope_snapshot.Reparent(scope);
DeclarationScope* scope = next_arrow_function_info_.scope;
scope->set_start_position(lhs_beg_pos);
FormalParametersT parameters(scope);
parameters.set_strict_parameter_error(
next_arrow_function_info_.strict_parameter_error_location,
next_arrow_function_info_.strict_parameter_error_message);
if (!next_arrow_function_info_.has_simple_parameter_list) {
scope->SetHasNonSimpleParameters();
parameters.is_simple = false;
}
parameters.is_simple = scope->has_simple_parameters();
scope->set_start_position(lhs_beg_pos);
impl()->DeclareArrowFunctionFormalParameters(&parameters, expression, loc);
expression = ParseArrowFunctionLiteral(parameters);
@ -2907,12 +2899,13 @@ ParserBase<Impl>::ParseUnaryOrPrefixExpression() {
DCHECK(Token::IsCountOp(op));
if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) {
if (V8_LIKELY(IsValidReferenceExpression(expression))) {
if (peek() != Token::ARROW) impl()->MarkExpressionAsAssigned(expression);
} else {
expression = RewriteInvalidReferenceExpression(
expression, expression_position, end_position(),
MessageTemplate::kInvalidLhsInPrefixOp);
}
impl()->MarkExpressionAsAssigned(expression);
return factory()->NewCountOperation(op, true /* prefix */, expression,
position());
@ -3021,15 +3014,17 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
if (V8_LIKELY(peek() == Token::ARROW)) {
maybe_arrow.ValidateDeclaration();
fni_.RemoveAsyncKeywordFromEnd();
next_arrow_function_info_.kind = FunctionKind::kAsyncArrowFunction;
next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot);
next_arrow_function_info_.scope =
NewFunctionScope(FunctionKind::kAsyncArrowFunction);
scope_snapshot.Reparent(next_arrow_function_info_.scope);
next_arrow_function_info_.rewritable_length = rewritable_length;
// async () => ...
if (!args.length()) return factory()->NewEmptyParentheses(pos);
// async ( Arguments ) => ...
ExpressionT result = impl()->ExpressionListToExpression(args);
next_arrow_function_info_.has_simple_parameter_list =
maybe_arrow.has_simple_parameter_list();
if (!maybe_arrow.has_simple_parameter_list()) {
next_arrow_function_info_.scope->SetHasNonSimpleParameters();
}
result->mark_parenthesized();
return result;
}
@ -4061,10 +4056,13 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
// In case we did not sucessfully preparse the function because of an
// unidentified error we do a full reparse to return the error.
ExpressionT expression = ParseConditionalExpression();
Scanner::Location loc(scope()->start_position(), end_position());
FormalParametersT parameters(formal_parameters.scope);
parameters.is_simple =
next_arrow_function_info_.has_simple_parameter_list;
DeclarationScope* function_scope = next_arrow_function_info_.scope;
FunctionState function_state(&function_state_, &scope_,
function_scope);
Scanner::Location loc(function_scope->start_position(),
end_position());
FormalParametersT parameters(function_scope);
parameters.is_simple = function_scope->has_simple_parameters();
impl()->DeclareArrowFunctionFormalParameters(&parameters, expression,
loc);
next_arrow_function_info_.Reset();