Commit b4f49586 authored by dslomov's avatar dslomov Committed by Commit bot

[destructuring] Re-index materialized literals in arrow function parameters.

R=wingo@igalia.com
BUG=v8:811
LOG=N

Review URL: https://codereview.chromium.org/1212473002

Cr-Commit-Position: refs/heads/master@{#29337}
parent 353b40e9
......@@ -562,6 +562,8 @@ source_set("v8_base") {
"src/assembler.h",
"src/assert-scope.h",
"src/assert-scope.cc",
"src/ast-literal-reindexer.cc",
"src/ast-literal-reindexer.h",
"src/ast-numbering.cc",
"src/ast-numbering.h",
"src/ast-value-factory.cc",
......
// 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/v8.h"
#include "src/ast.h"
#include "src/ast-literal-reindexer.h"
#include "src/scopes.h"
namespace v8 {
namespace internal {
void AstLiteralReindexer::VisitVariableDeclaration(VariableDeclaration* node) {
VisitVariableProxy(node->proxy());
}
void AstLiteralReindexer::VisitExportDeclaration(ExportDeclaration* node) {
VisitVariableProxy(node->proxy());
}
void AstLiteralReindexer::VisitEmptyStatement(EmptyStatement* node) {}
void AstLiteralReindexer::VisitContinueStatement(ContinueStatement* node) {}
void AstLiteralReindexer::VisitBreakStatement(BreakStatement* node) {}
void AstLiteralReindexer::VisitDebuggerStatement(DebuggerStatement* node) {}
void AstLiteralReindexer::VisitNativeFunctionLiteral(
NativeFunctionLiteral* node) {}
void AstLiteralReindexer::VisitLiteral(Literal* node) {}
void AstLiteralReindexer::VisitRegExpLiteral(RegExpLiteral* node) {
UpdateIndex(node);
}
void AstLiteralReindexer::VisitVariableProxy(VariableProxy* node) {}
void AstLiteralReindexer::VisitThisFunction(ThisFunction* node) {}
void AstLiteralReindexer::VisitSuperPropertyReference(
SuperPropertyReference* node) {
Visit(node->this_var());
Visit(node->home_object());
}
void AstLiteralReindexer::VisitSuperCallReference(SuperCallReference* node) {
Visit(node->this_var());
Visit(node->new_target_var());
Visit(node->this_function_var());
}
void AstLiteralReindexer::VisitImportDeclaration(ImportDeclaration* node) {
VisitVariableProxy(node->proxy());
}
void AstLiteralReindexer::VisitExpressionStatement(ExpressionStatement* node) {
Visit(node->expression());
}
void AstLiteralReindexer::VisitReturnStatement(ReturnStatement* node) {
Visit(node->expression());
}
void AstLiteralReindexer::VisitYield(Yield* node) {
Visit(node->generator_object());
Visit(node->expression());
}
void AstLiteralReindexer::VisitThrow(Throw* node) { Visit(node->exception()); }
void AstLiteralReindexer::VisitUnaryOperation(UnaryOperation* node) {
Visit(node->expression());
}
void AstLiteralReindexer::VisitCountOperation(CountOperation* node) {
Visit(node->expression());
}
void AstLiteralReindexer::VisitBlock(Block* node) {
VisitStatements(node->statements());
}
void AstLiteralReindexer::VisitFunctionDeclaration(FunctionDeclaration* node) {
VisitVariableProxy(node->proxy());
VisitFunctionLiteral(node->fun());
}
void AstLiteralReindexer::VisitCallRuntime(CallRuntime* node) {
VisitArguments(node->arguments());
}
void AstLiteralReindexer::VisitWithStatement(WithStatement* node) {
Visit(node->expression());
Visit(node->statement());
}
void AstLiteralReindexer::VisitDoWhileStatement(DoWhileStatement* node) {
Visit(node->body());
Visit(node->cond());
}
void AstLiteralReindexer::VisitWhileStatement(WhileStatement* node) {
Visit(node->cond());
Visit(node->body());
}
void AstLiteralReindexer::VisitTryCatchStatement(TryCatchStatement* node) {
Visit(node->try_block());
Visit(node->catch_block());
}
void AstLiteralReindexer::VisitTryFinallyStatement(TryFinallyStatement* node) {
Visit(node->try_block());
Visit(node->finally_block());
}
void AstLiteralReindexer::VisitProperty(Property* node) {
Visit(node->key());
Visit(node->obj());
}
void AstLiteralReindexer::VisitAssignment(Assignment* node) {
Visit(node->target());
Visit(node->value());
}
void AstLiteralReindexer::VisitBinaryOperation(BinaryOperation* node) {
Visit(node->left());
Visit(node->right());
}
void AstLiteralReindexer::VisitCompareOperation(CompareOperation* node) {
Visit(node->left());
Visit(node->right());
}
void AstLiteralReindexer::VisitSpread(Spread* node) {
Visit(node->expression());
}
void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) {
Visit(node->each());
Visit(node->enumerable());
Visit(node->body());
}
void AstLiteralReindexer::VisitForOfStatement(ForOfStatement* node) {
Visit(node->assign_iterator());
Visit(node->next_result());
Visit(node->result_done());
Visit(node->assign_each());
Visit(node->body());
}
void AstLiteralReindexer::VisitConditional(Conditional* node) {
Visit(node->condition());
Visit(node->then_expression());
Visit(node->else_expression());
}
void AstLiteralReindexer::VisitIfStatement(IfStatement* node) {
Visit(node->condition());
Visit(node->then_statement());
if (node->HasElseStatement()) {
Visit(node->else_statement());
}
}
void AstLiteralReindexer::VisitSwitchStatement(SwitchStatement* node) {
Visit(node->tag());
ZoneList<CaseClause*>* cases = node->cases();
for (int i = 0; i < cases->length(); i++) {
VisitCaseClause(cases->at(i));
}
}
void AstLiteralReindexer::VisitCaseClause(CaseClause* node) {
if (!node->is_default()) Visit(node->label());
VisitStatements(node->statements());
}
void AstLiteralReindexer::VisitForStatement(ForStatement* node) {
if (node->init() != NULL) Visit(node->init());
if (node->cond() != NULL) Visit(node->cond());
if (node->next() != NULL) Visit(node->next());
Visit(node->body());
}
void AstLiteralReindexer::VisitClassLiteral(ClassLiteral* node) {
if (node->extends()) Visit(node->extends());
if (node->constructor()) Visit(node->constructor());
if (node->class_variable_proxy()) {
VisitVariableProxy(node->class_variable_proxy());
}
for (int i = 0; i < node->properties()->length(); i++) {
VisitObjectLiteralProperty(node->properties()->at(i));
}
}
void AstLiteralReindexer::VisitObjectLiteral(ObjectLiteral* node) {
UpdateIndex(node);
for (int i = 0; i < node->properties()->length(); i++) {
VisitObjectLiteralProperty(node->properties()->at(i));
}
}
void AstLiteralReindexer::VisitObjectLiteralProperty(
ObjectLiteralProperty* node) {
Visit(node->key());
Visit(node->value());
}
void AstLiteralReindexer::VisitArrayLiteral(ArrayLiteral* node) {
UpdateIndex(node);
for (int i = 0; i < node->values()->length(); i++) {
Visit(node->values()->at(i));
}
}
void AstLiteralReindexer::VisitCall(Call* node) {
Visit(node->expression());
VisitArguments(node->arguments());
}
void AstLiteralReindexer::VisitCallNew(CallNew* node) {
Visit(node->expression());
VisitArguments(node->arguments());
}
void AstLiteralReindexer::VisitStatements(ZoneList<Statement*>* statements) {
if (statements == NULL) return;
for (int i = 0; i < statements->length(); i++) {
Visit(statements->at(i));
}
}
void AstLiteralReindexer::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
for (int i = 0; i < declarations->length(); i++) {
Visit(declarations->at(i));
}
}
void AstLiteralReindexer::VisitArguments(ZoneList<Expression*>* arguments) {
for (int i = 0; i < arguments->length(); i++) {
Visit(arguments->at(i));
}
}
void AstLiteralReindexer::VisitFunctionLiteral(FunctionLiteral* node) {
// We don't recurse into the declarations or body of the function literal:
}
void AstLiteralReindexer::Reindex(Expression* pattern) {
pattern->Accept(this);
}
}
} // namespace v8::internal
// 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.
#ifndef V8_AST_LITERAL_REINDEXER
#define V8_AST_LITERAL_REINDEXER
#include "src/v8.h"
#include "src/ast.h"
#include "src/scopes.h"
namespace v8 {
namespace internal {
class AstLiteralReindexer final : public AstVisitor {
public:
AstLiteralReindexer() : AstVisitor(), next_index_(0) {}
int count() const { return next_index_; }
void Reindex(Expression* pattern);
private:
#define DEFINE_VISIT(type) virtual void Visit##type(type* node) override;
AST_NODE_LIST(DEFINE_VISIT)
#undef DEFINE_VISIT
void VisitStatements(ZoneList<Statement*>* statements) override;
void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
void VisitArguments(ZoneList<Expression*>* arguments);
void VisitObjectLiteralProperty(ObjectLiteralProperty* property);
void UpdateIndex(MaterializedLiteral* literal) {
literal->literal_index_ = next_index_++;
}
void Visit(AstNode* node) override { node->Accept(this); }
int next_index_;
DISALLOW_COPY_AND_ASSIGN(AstLiteralReindexer);
};
}
} // namespace v8::internal
#endif // V8_AST_LITERAL_REINDEXER
......@@ -1298,6 +1298,8 @@ class Literal final : public Expression {
};
class AstLiteralReindexer;
// Base class for literals that needs space in the corresponding JSFunction.
class MaterializedLiteral : public Expression {
public:
......@@ -1349,6 +1351,8 @@ class MaterializedLiteral : public Expression {
bool is_simple_;
bool is_strong_;
int depth_;
friend class AstLiteralReindexer;
};
......
......@@ -6,6 +6,7 @@
#include "src/api.h"
#include "src/ast.h"
#include "src/ast-literal-reindexer.h"
#include "src/bailout-reason.h"
#include "src/base/platform/platform.h"
#include "src/bootstrapper.h"
......@@ -1179,6 +1180,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
scope->set_start_position(shared_info->start_position());
ExpressionClassifier formals_classifier;
ParserFormalParameterParsingState parsing_state(scope);
Checkpoint checkpoint(this);
{
// Parsing patterns as variable reference expression creates
// NewUnresolved references in current scope. Entrer arrow function
......@@ -1197,6 +1199,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
}
if (ok) {
checkpoint.Restore(&parsing_state.materialized_literals_count);
Expression* expression =
ParseArrowFunctionLiteral(parsing_state, formals_classifier, &ok);
if (ok) {
......@@ -3853,6 +3856,20 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
}
void ParserTraits::ReindexLiterals(
const ParserFormalParameterParsingState& parsing_state) {
if (parser_->function_state_->materialized_literal_count() > 0) {
AstLiteralReindexer reindexer;
for (const auto p : parsing_state.params) {
if (p.pattern != nullptr) reindexer.Reindex(p.pattern);
}
DCHECK(reindexer.count() <=
parser_->function_state_->materialized_literal_count());
}
}
FunctionLiteral* Parser::ParseFunctionLiteral(
const AstRawString* function_name, Scanner::Location function_name_location,
bool name_is_strict_reserved, FunctionKind kind, int function_token_pos,
......
......@@ -788,6 +788,8 @@ class ParserTraits {
const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
bool* ok);
void ReindexLiterals(const ParserFormalParameterParsingState& parsing_state);
// Temporary glue; these functions will move to ParserBase.
Expression* ParseV8Intrinsic(bool* ok);
FunctionLiteral* ParseFunctionLiteral(
......
......@@ -177,6 +177,10 @@ class ParserBase : public Traits {
return next_materialized_literal_index_;
}
void SkipMaterializedLiterals(int count) {
next_materialized_literal_index_ += count;
}
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
......@@ -258,7 +262,10 @@ class ParserBase : public Traits {
expected_property_count_ = function_state_->expected_property_count_;
}
void Restore() {
void Restore(int* materialized_literal_index_delta) {
*materialized_literal_index_delta =
function_state_->next_materialized_literal_index_ -
next_materialized_literal_index_;
function_state_->next_materialized_literal_index_ =
next_materialized_literal_index_;
function_state_->expected_property_count_ = expected_property_count_;
......@@ -1271,10 +1278,14 @@ class PreParserFactory {
struct PreParserFormalParameterParsingState {
explicit PreParserFormalParameterParsingState(Scope* scope)
: scope(scope), has_rest(false), is_simple_parameter_list(true) {}
: scope(scope),
has_rest(false),
is_simple_parameter_list(true),
materialized_literals_count(0) {}
Scope* scope;
bool has_rest;
bool is_simple_parameter_list;
int materialized_literals_count;
};
......@@ -1562,6 +1573,9 @@ class PreParserTraits {
PreParserExpression expression, const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok);
void ReindexLiterals(
const PreParserFormalParameterParsingState& parsing_state) {}
struct TemplateLiteralState {};
TemplateLiteralState OpenTemplateLiteral(int pos) {
......@@ -2772,16 +2786,17 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
accept_IN, &arrow_formals_classifier, CHECK_OK);
if (allow_harmony_arrow_functions() && peek() == Token::ARROW) {
checkpoint.Restore();
BindingPatternUnexpectedToken(classifier);
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
parenthesized_formals, CHECK_OK);
Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos);
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
FormalParameterParsingStateT parsing_state(scope);
checkpoint.Restore(&parsing_state.materialized_literals_count);
scope->set_start_position(lhs_location.beg_pos);
Scanner::Location duplicate_loc = Scanner::Location::invalid();
FormalParameterParsingStateT parsing_state(scope);
this->ParseArrowFunctionFormalParameters(&parsing_state, expression, loc,
&duplicate_loc, CHECK_OK);
if (duplicate_loc.IsValid()) {
......@@ -3685,6 +3700,11 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
formal_parameters.scope, kArrowFunction,
&function_factory);
function_state.SkipMaterializedLiterals(
formal_parameters.materialized_literals_count);
this->ReindexLiterals(formal_parameters);
Expect(Token::ARROW, CHECK_OK);
if (peek() == Token::LBRACE) {
......
......@@ -719,6 +719,7 @@ void PrettyPrinter::PrintObjectLiteralProperty(
void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
Print("[ ");
Print(" literal_index = %d", node->literal_index());
for (int i = 0; i < node->values()->length(); i++) {
if (i != 0) Print(",");
Visit(node->values()->at(i));
......@@ -1397,6 +1398,9 @@ void AstPrinter::VisitLiteral(Literal* node) {
void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
IndentedScope indent(this, "REGEXP LITERAL");
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "literal_index = %d\n", node->literal_index());
PrintIndented(buf.start());
PrintLiteralIndented("PATTERN", node->pattern(), false);
PrintLiteralIndented("FLAGS", node->flags(), false);
}
......@@ -1404,12 +1408,19 @@ void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
IndentedScope indent(this, "OBJ LITERAL");
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "literal_index = %d\n", node->literal_index());
PrintIndented(buf.start());
PrintProperties(node->properties());
}
void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
IndentedScope indent(this, "ARRAY LITERAL");
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "literal_index = %d\n", node->literal_index());
PrintIndented(buf.start());
if (node->values()->length() > 0) {
IndentedScope indent(this, "VALUES");
for (int i = 0; i < node->values()->length(); i++) {
......
// 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.
//
// Flags: --harmony-destructuring --harmony-computed-property-names
// Flags: --harmony-arrow-functions --no-lazy --allow-natives-syntax
var t1 = [1];
var t2 = [2];
var t3 = [3];
var t4 = [4];
var t5 = [5];
function g({x = {a:10,b:20}},
{y = [1,2,3],
n = [],
p = /abc/}) {
assertSame(10, x.a);
assertSame(20, x.b);
assertSame(2, y[1]);
assertSame(0, n.length);
assertTrue(p.test("abc"));
}
g({},{});
%OptimizeFunctionOnNextCall(g);
g({},{});
var h = ({x = {a:10,b:20}},
{y = [1,2,3],
n = [],
p = /abc/ }) => {
assertSame(10, x.a);
assertSame(20, x.b);
assertSame(2, y[1]);
assertSame(0, n.length);
assertTrue(p.test("abc"));
};
h({},{});
%OptimizeFunctionOnNextCall(h);
h({},{});
// 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.
//
// Flags: --harmony-destructuring --harmony-computed-property-names
// Flags: --harmony-arrow-functions --allow-natives-syntax
var t1 = [1];
var t2 = [2];
var t3 = [3];
var t4 = [4];
var t5 = [5];
function g({x = {a:10,b:20}},
{y = [1,2,3],
n = [],
p = /abc/}) {
assertSame(10, x.a);
assertSame(20, x.b);
assertSame(2, y[1]);
assertSame(0, n.length);
assertTrue(p.test("abc"));
}
g({},{});
%OptimizeFunctionOnNextCall(g);
g({},{});
var h = ({x = {a:10,b:20}},
{y = [1,2,3],
n = [],
p = /abc/ }) => {
assertSame(10, x.a);
assertSame(20, x.b);
assertSame(2, y[1]);
assertSame(0, n.length);
assertTrue(p.test("abc"));
};
h({},{});
%OptimizeFunctionOnNextCall(h);
h({},{});
......@@ -397,6 +397,8 @@
'../../src/assert-scope.cc',
'../../src/ast-value-factory.cc',
'../../src/ast-value-factory.h',
'../../src/ast-literal-reindexer.cc',
'../../src/ast-literal-reindexer.h',
'../../src/ast-numbering.cc',
'../../src/ast-numbering.h',
'../../src/ast.cc',
......
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