Commit 5f782db9 authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[parser] don't rewrite destructuring assignments in params for lazy top level arrow functions

Remove destructuring assignments (parsed during arrow function formal
parameters) from queue for rewriting if parsing a lazy top-level arrow function.

Built ontop of https://chromium-review.googlesource.com/c/464769/

BUG=chromium:706234, chromium:706761, v8:6182
R=marja@chromium.org, adamk@chromium.org, vogelheim@chromium.org

Change-Id: Ib35196b907350d1d78e4c3fcbf4cc971bf200948
Reviewed-on: https://chromium-review.googlesource.com/465415
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44393}
parent d6a92013
...@@ -1496,7 +1496,11 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, ...@@ -1496,7 +1496,11 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
DCHECK(is_function_scope()); DCHECK(is_function_scope());
// Reset all non-trivial members. // Reset all non-trivial members.
if (!aborted || !IsArrowFunction(function_kind_)) {
// Do not remove parameters when lazy parsing an Arrow Function has failed,
// as the formal parameters are not re-parsed.
params_.Clear(); params_.Clear();
}
decls_.Clear(); decls_.Clear();
locals_.Clear(); locals_.Clear();
inner_scope_ = nullptr; inner_scope_ = nullptr;
......
...@@ -395,6 +395,17 @@ class ParserBase { ...@@ -395,6 +395,17 @@ class ParserBase {
return scope()->promise_var(); return scope()->promise_var();
} }
void RewindDestructuringAssignments(int pos) {
destructuring_assignments_to_rewrite_.Rewind(pos);
}
void SetDestructuringAssignmentsScope(int pos, Scope* scope) {
for (int i = pos; i < destructuring_assignments_to_rewrite_.length();
++i) {
destructuring_assignments_to_rewrite_[i].scope = scope;
}
}
const ZoneList<DestructuringAssignment>& const ZoneList<DestructuringAssignment>&
destructuring_assignments_to_rewrite() const { destructuring_assignments_to_rewrite() const {
return destructuring_assignments_to_rewrite_; return destructuring_assignments_to_rewrite_;
...@@ -1108,9 +1119,14 @@ class ParserBase { ...@@ -1108,9 +1119,14 @@ class ParserBase {
ExpressionT ParseMemberExpression(bool* is_async, bool* ok); ExpressionT ParseMemberExpression(bool* is_async, bool* ok);
ExpressionT ParseMemberExpressionContinuation(ExpressionT expression, ExpressionT ParseMemberExpressionContinuation(ExpressionT expression,
bool* is_async, bool* ok); bool* is_async, bool* ok);
// `rewritable_length`: length of the destructuring_assignments_to_rewrite()
// queue in the parent function state, prior to parsing of formal parameters.
// If the arrow function is lazy, any items added during formal parameter
// parsing are removed from the queue.
ExpressionT ParseArrowFunctionLiteral(bool accept_IN, ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
const FormalParametersT& parameters, const FormalParametersT& parameters,
bool* ok); int rewritable_length, bool* ok);
void ParseAsyncFunctionBody(Scope* scope, StatementListT body, void ParseAsyncFunctionBody(Scope* scope, StatementListT body,
FunctionKind kind, FunctionBodyType type, FunctionKind kind, FunctionBodyType type,
bool accept_IN, int pos, bool* ok); bool accept_IN, int pos, bool* ok);
...@@ -2711,6 +2727,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { ...@@ -2711,6 +2727,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
this, classifier()->duplicate_finder()); this, classifier()->duplicate_finder());
Scope::Snapshot scope_snapshot(scope()); Scope::Snapshot scope_snapshot(scope());
int rewritable_length =
function_state_->destructuring_assignments_to_rewrite().length();
bool is_async = peek() == Token::ASYNC && bool is_async = peek() == Token::ASYNC &&
!scanner()->HasAnyLineTerminatorAfterNext() && !scanner()->HasAnyLineTerminatorAfterNext() &&
...@@ -2762,6 +2780,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { ...@@ -2762,6 +2780,7 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// Because the arrow's parameters were parsed in the outer scope, // Because the arrow's parameters were parsed in the outer scope,
// we need to fix up the scope chain appropriately. // we need to fix up the scope chain appropriately.
scope_snapshot.Reparent(scope); scope_snapshot.Reparent(scope);
function_state_->SetDestructuringAssignmentsScope(rewritable_length, scope);
FormalParametersT parameters(scope); FormalParametersT parameters(scope);
if (!classifier()->is_simple_parameter_list()) { if (!classifier()->is_simple_parameter_list()) {
...@@ -2776,7 +2795,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) { ...@@ -2776,7 +2795,8 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
if (duplicate_loc.IsValid()) { if (duplicate_loc.IsValid()) {
classifier()->RecordDuplicateFormalParameterError(duplicate_loc); classifier()->RecordDuplicateFormalParameterError(duplicate_loc);
} }
expression = ParseArrowFunctionLiteral(accept_IN, parameters, CHECK_OK); expression = ParseArrowFunctionLiteral(accept_IN, parameters,
rewritable_length, CHECK_OK);
DiscardExpressionClassifier(); DiscardExpressionClassifier();
classifier()->RecordPatternError(arrow_loc, classifier()->RecordPatternError(arrow_loc,
MessageTemplate::kUnexpectedToken, MessageTemplate::kUnexpectedToken,
...@@ -4146,7 +4166,8 @@ bool ParserBase<Impl>::IsTrivialExpression() { ...@@ -4146,7 +4166,8 @@ bool ParserBase<Impl>::IsTrivialExpression() {
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::ExpressionT typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseArrowFunctionLiteral( ParserBase<Impl>::ParseArrowFunctionLiteral(
bool accept_IN, const FormalParametersT& formal_parameters, bool* ok) { bool accept_IN, const FormalParametersT& formal_parameters,
int rewritable_length, bool* ok) {
const RuntimeCallStats::CounterId counters[2][2] = { const RuntimeCallStats::CounterId counters[2][2] = {
{&RuntimeCallStats::ParseBackgroundArrowFunctionLiteral, {&RuntimeCallStats::ParseBackgroundArrowFunctionLiteral,
&RuntimeCallStats::ParseArrowFunctionLiteral}, &RuntimeCallStats::ParseArrowFunctionLiteral},
...@@ -4276,6 +4297,14 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( ...@@ -4276,6 +4297,14 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
} }
impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); impl()->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
if (is_lazy_top_level_function) {
FunctionState* parent_state = function_state.outer();
DCHECK_NOT_NULL(parent_state);
DCHECK_GE(parent_state->destructuring_assignments_to_rewrite().length(),
rewritable_length);
parent_state->RewindDestructuringAssignments(rewritable_length);
}
impl()->RewriteDestructuringAssignments(); impl()->RewriteDestructuringAssignments();
} }
......
...@@ -891,6 +891,8 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, ...@@ -891,6 +891,8 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
scope->set_start_position(info->start_position()); scope->set_start_position(info->start_position());
ExpressionClassifier formals_classifier(this); ExpressionClassifier formals_classifier(this);
ParserFormalParameters formals(scope); ParserFormalParameters formals(scope);
int rewritable_length =
function_state.destructuring_assignments_to_rewrite().length();
{ {
// Parsing patterns as variable reference expression creates // Parsing patterns as variable reference expression creates
// NewUnresolved references in current scope. Enter arrow function // NewUnresolved references in current scope. Enter arrow function
...@@ -925,7 +927,8 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info, ...@@ -925,7 +927,8 @@ FunctionLiteral* Parser::DoParseFunction(ParseInfo* info,
// Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should // Pass `accept_IN=true` to ParseArrowFunctionLiteral --- This should
// not be observable, or else the preparser would have failed. // not be observable, or else the preparser would have failed.
Expression* expression = ParseArrowFunctionLiteral(true, formals, &ok); Expression* expression =
ParseArrowFunctionLiteral(true, formals, rewritable_length, &ok);
if (ok) { if (ok) {
// Scanning must end at the same position that was recorded // Scanning must end at the same position that was recorded
// previously. If not, parsing has been interrupted due to a stack // previously. If not, parsing has been interrupted due to a stack
......
// Copyright 2017 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.
// Lazy top-level arrow function which must be re-parsed and eagerly compiled.
var f = ({ x } = { x: 1 }) => {
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;
};
f();
// Copyright 2017 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.
var fn = ({foo = {} = {}}) => { return foo; }
if (true) {
fn({});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment