[parser] Iterate declarations to set initializer positions

This allows us to remove the PatternRewriter.

Change-Id: I54ec74ed3bd31e76e38c69f9b0b2a78f8620cd89
Reviewed-on: https://chromium-review.googlesource.com/c/1429863
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59028}
This commit is contained in:
Toon Verwaest 2019-01-23 13:49:23 +01:00 committed by Commit Bot
parent 172277f4bd
commit 0b69b05a08
10 changed files with 128 additions and 318 deletions

View File

@ -2326,7 +2326,6 @@ v8_source_set("v8_base") {
"src/parsing/parser.h",
"src/parsing/parsing.cc",
"src/parsing/parsing.h",
"src/parsing/pattern-rewriter.cc",
"src/parsing/preparse-data-impl.h",
"src/parsing/preparse-data.cc",
"src/parsing/preparse-data.h",

View File

@ -678,6 +678,11 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
MessageTemplate::kParamDupe);
}
}
int initializer_position = this->parser()->end_position();
for (auto declaration : *result->declarations()) {
declaration->var()->set_initializer_position(initializer_position);
}
return result;
}

View File

@ -480,16 +480,12 @@ class ParserBase {
struct DeclarationParsingResult {
struct Declaration {
Declaration(ExpressionT pattern, int initializer_position,
ExpressionT initializer)
: pattern(pattern),
initializer_position(initializer_position),
initializer(initializer) {}
Declaration(ExpressionT pattern, ExpressionT initializer)
: pattern(pattern), initializer(initializer) {}
ExpressionT pattern;
int initializer_position;
int value_beg_position = kNoSourcePosition;
ExpressionT initializer;
int value_beg_pos = kNoSourcePosition;
};
DeclarationParsingResult()
@ -3363,6 +3359,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) {
// BindingElement[?Yield, ?GeneratorParameter]
FuncNameInferrerState fni_state(&fni_);
int pos = peek_position();
auto declaration_it = scope()->declarations()->end();
ExpressionT pattern = ParseBindingPattern();
if (impl()->IsIdentifier(pattern)) {
ClassifyParameter(impl()->AsIdentifier(pattern), pos, end_position());
@ -3379,11 +3376,17 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) {
return;
}
AcceptINScope scope(this, true);
AcceptINScope accept_in_scope(this, true);
initializer = ParseAssignmentExpression();
impl()->SetFunctionNameFromIdentifierRef(initializer, pattern);
}
auto declaration_end = scope()->declarations()->end();
int initializer_end = end_position();
for (; declaration_it != declaration_end; ++declaration_it) {
declaration_it->var()->set_initializer_position(initializer_end);
}
impl()->AddFormalParameter(parameters, pattern, initializer, end_position(),
parameters->has_rest);
}
@ -3473,6 +3476,11 @@ void ParserBase<Impl>::ParseVariableDeclarations(
VariableDeclarationParsingScope declaration(
impl(), parsing_result->descriptor.mode, names);
Scope* target_scope = IsLexicalVariableMode(parsing_result->descriptor.mode)
? scope()
: scope()->GetDeclarationScope();
auto declaration_it = target_scope->declarations()->end();
int bindings_start = peek_position();
do {
@ -3485,12 +3493,10 @@ void ParserBase<Impl>::ParseVariableDeclarations(
Scanner::Location variable_loc = scanner()->location();
ExpressionT value = impl()->NullExpression();
int initializer_position = kNoSourcePosition;
int value_beg_position = kNoSourcePosition;
int value_beg_pos = kNoSourcePosition;
if (Check(Token::ASSIGN)) {
value_beg_position = peek_position();
{
value_beg_pos = peek_position();
AcceptINScope scope(this, var_context != kForStatement);
value = ParseAssignmentExpression();
}
@ -3510,9 +3516,6 @@ void ParserBase<Impl>::ParseVariableDeclarations(
}
impl()->SetFunctionNameFromIdentifierRef(value, pattern);
// End position of the initializer is after the assignment expression.
initializer_position = end_position();
} else {
if (var_context != kForStatement || !PeekInOrOf()) {
// ES6 'const' and binding patterns require initializers.
@ -3529,14 +3532,16 @@ void ParserBase<Impl>::ParseVariableDeclarations(
value = factory()->NewUndefinedLiteral(position());
}
}
// End position of the initializer is after the variable.
initializer_position = position();
}
typename DeclarationParsingResult::Declaration decl(
pattern, initializer_position, value);
decl.value_beg_position = value_beg_position;
int initializer_position = end_position();
auto declaration_end = target_scope->declarations()->end();
for (; declaration_it != declaration_end; ++declaration_it) {
declaration_it->var()->set_initializer_position(initializer_position);
}
typename DeclarationParsingResult::Declaration decl(pattern, value);
decl.value_beg_pos = value_beg_pos;
parsing_result->declarations.push_back(decl);
} while (Check(Token::COMMA));
@ -5179,9 +5184,20 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement() {
} else {
catch_info.variable = catch_info.scope->DeclareCatchVariableName(
ast_value_factory()->dot_catch_string());
auto declaration_it = scope()->declarations()->end();
VariableDeclarationParsingScope destructuring(
impl(), VariableMode::kLet, nullptr);
catch_info.pattern = ParseBindingPattern();
int initializer_position = end_position();
auto declaration_end = scope()->declarations()->end();
for (; declaration_it != declaration_end; ++declaration_it) {
declaration_it->var()->set_initializer_position(
initializer_position);
}
RETURN_IF_PARSE_ERROR;
catch_statements.Add(impl()->RewriteCatchPattern(&catch_info));
}

View File

@ -1413,6 +1413,7 @@ Statement* Parser::BuildInitializationBlock(
DeclarationParsingResult* parsing_result) {
ScopedPtrList<Statement> statements(pointer_buffer());
for (const auto& declaration : parsing_result->declarations) {
if (!declaration.initializer) continue;
InitializeVariables(&statements, parsing_result->descriptor.kind,
&declaration);
}
@ -1594,15 +1595,27 @@ Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement,
return switch_block;
}
void Parser::InitializeVariables(
ScopedPtrList<Statement>* statements, VariableKind kind,
const DeclarationParsingResult::Declaration* declaration) {
if (has_error()) return;
DCHECK_NOT_NULL(declaration->initializer);
int pos = declaration->value_beg_pos;
if (pos == kNoSourcePosition) {
pos = declaration->initializer->position();
}
Assignment* assignment = factory()->NewAssignment(
Token::INIT, declaration->pattern, declaration->initializer, pos);
statements->Add(factory()->NewExpressionStatement(assignment, pos));
}
Block* Parser::RewriteCatchPattern(CatchInfo* catch_info) {
DCHECK_NOT_NULL(catch_info->pattern);
// Initializer position for variables declared by the pattern.
const int initializer_position = position();
DeclarationParsingResult::Declaration decl(
catch_info->pattern, initializer_position,
factory()->NewVariableProxy(catch_info->variable));
catch_info->pattern, factory()->NewVariableProxy(catch_info->variable));
ScopedPtrList<Statement> init_statements(pointer_buffer());
InitializeVariables(&init_statements, NORMAL_VARIABLE, &decl);
@ -1797,7 +1810,7 @@ Block* Parser::RewriteForVarInLegacy(const ForInfo& for_info) {
init_block->statements()->Add(
factory()->NewExpressionStatement(
factory()->NewAssignment(Token::ASSIGN, single_var,
decl.initializer, kNoSourcePosition),
decl.initializer, decl.value_beg_pos),
kNoSourcePosition),
zone());
return init_block;
@ -1827,7 +1840,7 @@ void Parser::DesugarBindingInForEachStatement(ForInfo* for_info,
for_info->parsing_result.declarations[0];
Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
ScopedPtrList<Statement> each_initialization_statements(pointer_buffer());
decl.initializer = factory()->NewVariableProxy(temp);
decl.initializer = factory()->NewVariableProxy(temp, for_info->position);
InitializeVariables(&each_initialization_statements, NORMAL_VARIABLE, &decl);
*body_block = factory()->NewBlock(3, false);
@ -2617,12 +2630,13 @@ Block* Parser::BuildParameterInitializationBlock(
non_simple_param_init_statements.emplace(pointer_buffer());
param_init_statements = &non_simple_param_init_statements.value();
// Rewrite the outer initializer to point to param_scope
ReparentExpressionScope(stack_limit(), parameter->pattern, param_scope);
ReparentExpressionScope(stack_limit(), initial_value, param_scope);
}
BlockState block_state(&scope_, param_scope);
DeclarationParsingResult::Declaration decl(
parameter->pattern, parameter->initializer_end_position, initial_value);
DeclarationParsingResult::Declaration decl(parameter->pattern,
initial_value);
InitializeVariables(param_init_statements, PARAMETER_VARIABLE, &decl);

View File

@ -1,218 +0,0 @@
// Copyright 2015 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.
#include "src/ast/ast.h"
#include "src/message-template.h"
#include "src/objects-inl.h"
#include "src/parsing/expression-scope-reparenter.h"
#include "src/parsing/parser.h"
namespace v8 {
namespace internal {
// An AST visitor which performs declaration and assignment related tasks,
// particularly for destructuring patterns:
//
// 1. Declares variables from variable proxies (particularly for destructuring
// declarations),
// 2. Marks destructuring-assigned variable proxies as assigned, and
// 3. Rewrites scopes for parameters containing a sloppy eval.
//
// Historically this also rewrote destructuring assignments/declarations as a
// block of multiple assignments, hence the named, however this is now done
// during bytecode generation.
//
// TODO(leszeks): Rename or remove this class
class PatternRewriter final : public AstVisitor<PatternRewriter> {
public:
typedef Parser::DeclarationDescriptor DeclarationDescriptor;
static void InitializeVariables(
Parser* parser, VariableKind kind,
const Parser::DeclarationParsingResult::Declaration* declaration);
private:
PatternRewriter(Parser* parser, VariableKind kind, int initializer_position,
bool declares_parameter_containing_sloppy_eval)
: parser_(parser),
initializer_position_(initializer_position),
declares_parameter_containing_sloppy_eval_(
declares_parameter_containing_sloppy_eval) {}
#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
// Visiting functions for AST nodes make this an AstVisitor.
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
Expression* Visit(Assignment* assign) {
if (parser_->has_error()) return parser_->FailureExpression();
DCHECK_EQ(Token::ASSIGN, assign->op());
Expression* pattern = assign->target();
if (pattern->IsObjectLiteral()) {
VisitObjectLiteral(pattern->AsObjectLiteral());
} else {
DCHECK(pattern->IsArrayLiteral());
VisitArrayLiteral(pattern->AsArrayLiteral());
}
return assign;
}
void RewriteParameterScopes(Expression* expr);
Scope* scope() const { return parser_->scope(); }
Parser* const parser_;
const int initializer_position_;
const bool declares_parameter_containing_sloppy_eval_;
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
void Parser::InitializeVariables(
ScopedPtrList<Statement>* statements, VariableKind kind,
const DeclarationParsingResult::Declaration* declaration) {
if (has_error()) return;
if (!declaration->initializer) {
// The parameter scope is only a block scope if the initializer calls sloppy
// eval. Since there is no initializer, we can't be calling sloppy eval.
DCHECK_IMPLIES(kind == PARAMETER_VARIABLE, scope()->is_function_scope());
return;
}
PatternRewriter::InitializeVariables(this, kind, declaration);
int pos = declaration->value_beg_position;
if (pos == kNoSourcePosition) {
pos = declaration->initializer_position;
}
Assignment* assignment = factory()->NewAssignment(
Token::INIT, declaration->pattern, declaration->initializer, pos);
statements->Add(factory()->NewExpressionStatement(assignment, pos));
}
void PatternRewriter::InitializeVariables(
Parser* parser, VariableKind kind,
const Parser::DeclarationParsingResult::Declaration* declaration) {
PatternRewriter rewriter(
parser, kind, declaration->initializer_position,
kind == PARAMETER_VARIABLE && parser->scope()->is_block_scope());
rewriter.Visit(declaration->pattern);
}
void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
DCHECK(!parser_->has_error());
Variable* var =
proxy->is_resolved()
? proxy->var()
: scope()->GetDeclarationScope()->LookupLocal(proxy->raw_name());
DCHECK_NOT_NULL(var);
DCHECK_NE(initializer_position_, kNoSourcePosition);
var->set_initializer_position(initializer_position_);
}
// When an extra declaration scope needs to be inserted to account for
// a sloppy eval in a default parameter or function body, the expressions
// needs to be in that new inner scope which was added after initial
// parsing.
void PatternRewriter::RewriteParameterScopes(Expression* expr) {
if (declares_parameter_containing_sloppy_eval_) {
ReparentExpressionScope(parser_->stack_limit(), expr, scope());
}
}
void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
for (ObjectLiteralProperty* property : *pattern->properties()) {
Expression* key = property->key();
if (!key->IsLiteral()) {
// Computed property names contain expressions which might require
// scope rewriting.
RewriteParameterScopes(key);
}
Visit(property->value());
}
}
void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
for (Expression* value : *node->values()) {
if (value->IsTheHoleLiteral()) continue;
Visit(value);
}
}
void PatternRewriter::VisitAssignment(Assignment* node) {
DCHECK_EQ(Token::ASSIGN, node->op());
// Initializer may have been parsed in the wrong scope.
RewriteParameterScopes(node->value());
Visit(node->target());
}
void PatternRewriter::VisitSpread(Spread* node) { Visit(node->expression()); }
// =============== UNREACHABLE =============================
#define NOT_A_PATTERN(Node) \
void PatternRewriter::Visit##Node(v8::internal::Node*) { UNREACHABLE(); }
NOT_A_PATTERN(BinaryOperation)
NOT_A_PATTERN(NaryOperation)
NOT_A_PATTERN(Block)
NOT_A_PATTERN(BreakStatement)
NOT_A_PATTERN(Call)
NOT_A_PATTERN(CallNew)
NOT_A_PATTERN(CallRuntime)
NOT_A_PATTERN(ClassLiteral)
NOT_A_PATTERN(CompareOperation)
NOT_A_PATTERN(CompoundAssignment)
NOT_A_PATTERN(Conditional)
NOT_A_PATTERN(ContinueStatement)
NOT_A_PATTERN(CountOperation)
NOT_A_PATTERN(DebuggerStatement)
NOT_A_PATTERN(DoExpression)
NOT_A_PATTERN(DoWhileStatement)
NOT_A_PATTERN(EmptyStatement)
NOT_A_PATTERN(EmptyParentheses)
NOT_A_PATTERN(ExpressionStatement)
NOT_A_PATTERN(ForInStatement)
NOT_A_PATTERN(ForOfStatement)
NOT_A_PATTERN(ForStatement)
NOT_A_PATTERN(FunctionDeclaration)
NOT_A_PATTERN(FunctionLiteral)
NOT_A_PATTERN(GetTemplateObject)
NOT_A_PATTERN(IfStatement)
NOT_A_PATTERN(ImportCallExpression)
NOT_A_PATTERN(Literal)
NOT_A_PATTERN(NativeFunctionLiteral)
NOT_A_PATTERN(Property)
NOT_A_PATTERN(RegExpLiteral)
NOT_A_PATTERN(ResolvedProperty)
NOT_A_PATTERN(ReturnStatement)
NOT_A_PATTERN(SloppyBlockFunctionStatement)
NOT_A_PATTERN(StoreInArrayLiteral)
NOT_A_PATTERN(SuperPropertyReference)
NOT_A_PATTERN(SuperCallReference)
NOT_A_PATTERN(SwitchStatement)
NOT_A_PATTERN(TemplateLiteral)
NOT_A_PATTERN(ThisFunction)
NOT_A_PATTERN(Throw)
NOT_A_PATTERN(TryCatchStatement)
NOT_A_PATTERN(TryFinallyStatement)
NOT_A_PATTERN(UnaryOperation)
NOT_A_PATTERN(VariableDeclaration)
NOT_A_PATTERN(WhileStatement)
NOT_A_PATTERN(WithStatement)
NOT_A_PATTERN(Yield)
NOT_A_PATTERN(YieldStar)
NOT_A_PATTERN(Await)
NOT_A_PATTERN(InitializeClassMembersStatement)
#undef NOT_A_PATTERN
} // namespace internal
} // namespace v8

View File

@ -18,7 +18,7 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(1),
/* 10 E> */ B(StackCheck),
/* 22 S> */ B(Star), R(0),
B(Star), R(0),
/* 42 S> */ B(Return),
]
constant pool: [
@ -38,8 +38,8 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
/* 10 E> */ B(StackCheck),
/* 12 S> */ B(Mov), R(arg0), R(0),
/* 25 S> */ B(Mov), R(2), R(1),
B(Mov), R(arg0), R(0),
B(Mov), R(2), R(1),
/* 29 S> */ B(Ldar), R(1),
/* 45 S> */ B(Return),
]
@ -60,8 +60,8 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
/* 10 E> */ B(StackCheck),
/* 12 S> */ B(Mov), R(arg0), R(0),
/* 25 S> */ B(Mov), R(2), R(1),
B(Mov), R(arg0), R(0),
B(Mov), R(2), R(1),
/* 29 S> */ B(LdaZero),
/* 44 E> */ B(LdaKeyedProperty), R(1), U8(0),
/* 48 S> */ B(Return),
@ -85,8 +85,8 @@ bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
/* 10 E> */ B(StackCheck),
/* 12 S> */ B(Mov), R(arg0), R(0),
/* 25 S> */ B(Mov), R(2), R(1),
B(Mov), R(arg0), R(0),
B(Mov), R(2), R(1),
/* 29 S> */ B(LdaZero),
/* 44 E> */ B(LdaKeyedProperty), R(1), U8(1),
B(Star), R(4),

View File

@ -57,7 +57,7 @@ bytecodes: [
B(Star), R(3),
B(Mov), R(closure), R(1),
/* 128 E> */ B(StackCheck),
/* 136 S> */ B(Mov), R(3), R(2),
B(Mov), R(3), R(2),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(LdaSmi), I8(1),
@ -99,7 +99,7 @@ bytecodes: [
B(Star), R(3),
B(Mov), R(closure), R(1),
/* 128 E> */ B(StackCheck),
/* 136 S> */ B(Mov), R(3), R(2),
B(Mov), R(3), R(2),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(CreateEmptyArrayLiteral), U8(0),

View File

@ -26,84 +26,84 @@ function listener(event, exec_state, event_data, data) {
Debug.setListener(listener);
var id = x => x; // B11 B12 B42 B43
var id = x => x; // B9 B10 B36 B37
function test() {
debugger; // B0
function fx1([
a, // B3
b // B4
]) { // B2
assertEquals([1, 2], [a, b]); // B5
} // B6
a, // B2
b // B3
]) {
assertEquals([1, 2], [a, b]); // B4
} // B5
fx1([1, 2, 3]); // B1
function f2([
a, // B9
b = id(3) // B10
]) { // B8
assertEquals([4, 3], [a, b]); // B13
} // B14
f2([4]); // B7
a, // B7
b = id(3) // B8
]) {
assertEquals([4, 3], [a, b]); // B11
} // B12
f2([4]); // B6
function f3({
x: a, // B17
y: b // B18
}) { // B16
assertEquals([5, 6], [a, b]); // B19
} // B20
f3({y: 6, x: 5}); // B15
x: a, // B14
y: b // B15
}) {
assertEquals([5, 6], [a, b]); // B16
} // B17
f3({y: 6, x: 5}); // B13
function f4([
a, // B23
a, // B19
{
b, // B24
c, // B25
b, // B20
c, // B21
}
]) { // B22
assertEquals([2, 4, 6], [a, b, c]); // B26
} // B27
f4([2, {c: 6, b: 4}]); // B21
]) { // B19
assertEquals([2, 4, 6], [a, b, c]); // B22
} // B23
f4([2, {c: 6, b: 4}]); // B18
function f5([
{
a, // B30
b = 7 // B31
a, // B25
b = 7 // B26
},
c = 3 // B32
] = [{a:1}]) { // B29
assertEquals([1, 7, 3], [a, b, c]); // B33
} // B34
f5(); // B28
c = 3 // B27
] = [{a:1}]) {
assertEquals([1, 7, 3], [a, b, c]); // B28
} // B29
f5(); // B24
var name = "x"; // B35
var name = "x"; // B30
function f6({
[id(name)]: a, // B40 B41
b = a // B44
}) { // B39
assertEquals([9, 9], [a, b]); // B45
} // B46
var o6 = {}; // B36
o6[name] = 9; // B37
f6(o6); // B38
[id(name)]: a, // B34 B35
b = a // B38
}) {
assertEquals([9, 9], [a, b]); // B39
} // B40
var o6 = {}; // B31
o6[name] = 9; // B32
f6(o6); // B33
try {
throw [3, 4]; // B47
throw [3, 4]; // B41
} catch ([
a, // B49
b, // B50
c = 6 // B51
]) { // B48
assertEquals([3, 4, 6], [a, b, c]); // B52
a, // B42
b, // B43
c = 6 // B44
]) {
assertEquals([3, 4, 6], [a, b, c]); // B45
}
var {
x: a, // B54
y: b = 9 // B55
} = { x: 4 }; // B53
assertEquals([4, 9], [a, b]); // B56
} // B57
x: a, // B47
y: b = 9 // B48
} = { x: 4 }; // B46
assertEquals([4, 9], [a, b]); // B49
} // B50
test();
Debug.setListener(null); // B58
Debug.setListener(null); // B51
assertNull(exception);

View File

@ -41,5 +41,5 @@ Debug.setListener(null); // c
assertNull(exception);
assertEquals("default", result);
assertEquals(["a0","b13","f31b13","f18b13","d2f18b13","d19f18b13","g14b13","c0"],
assertEquals(["a0","b13","f18b13","d2f18b13","d19f18b13","g14b13","c0"],
log);

View File

@ -10,12 +10,6 @@ paused
#c(f, 2);
}
paused
function c(f#, ...args) { return f(...args); }
paused
function c(f, ...args#) { return f(...args); }
paused
function c(f, ...args) { #return f(...args); }