Commit 531af2f4 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[parser] Use n-ary addition for template strings

When closing untagged template string literals, create a single n-ary
addition operation, instead of a tree of binary operations.

As a clean-up, this also entirely removes the "second" field from n-ary
operations. This was proving to be too confusing an API when building
an n-ary operation incrementally from a single expression (rather than
converting a binary operation).

Bug: v8:6964
Change-Id: I8f2a395d413cf345bab0a1a347b47f412cde83b1
Reviewed-on: https://chromium-review.googlesource.com/739821Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49054}
parent bcf9771b
...@@ -1822,18 +1822,15 @@ class NaryOperation final : public Expression { ...@@ -1822,18 +1822,15 @@ class NaryOperation final : public Expression {
Expression* first() const { return first_; } Expression* first() const { return first_; }
void set_first(Expression* e) { first_ = e; } void set_first(Expression* e) { first_ = e; }
Expression* subsequent(size_t index) const { Expression* subsequent(size_t index) const {
if (index == 0) return second_; return subsequent_[index].expression;
return subsequent_[index - 1].expression;
} }
Expression* set_subsequent(size_t index, Expression* e) { Expression* set_subsequent(size_t index, Expression* e) {
if (index == 0) return second_ = e; return subsequent_[index].expression = e;
return subsequent_[index - 1].expression = e;
} }
size_t subsequent_length() const { return 1 + subsequent_.size(); } size_t subsequent_length() const { return subsequent_.size(); }
int subsequent_op_position(size_t index) const { int subsequent_op_position(size_t index) const {
if (index == 0) return position(); return subsequent_[index].op_position;
return subsequent_[index - 1].op_position;
} }
void AddSubsequent(Expression* expr, int pos) { void AddSubsequent(Expression* expr, int pos) {
...@@ -1844,33 +1841,32 @@ class NaryOperation final : public Expression { ...@@ -1844,33 +1841,32 @@ class NaryOperation final : public Expression {
friend class AstNodeFactory; friend class AstNodeFactory;
NaryOperation(Zone* zone, Token::Value op, Expression* first, NaryOperation(Zone* zone, Token::Value op, Expression* first,
Expression* second, int pos) size_t initial_subsequent_size)
: Expression(pos, kNaryOperation), : Expression(kNoSourcePosition, kNaryOperation),
first_(first), first_(first),
second_(second),
subsequent_(zone) { subsequent_(zone) {
bit_field_ |= OperatorField::encode(op); bit_field_ |= OperatorField::encode(op);
DCHECK(Token::IsBinaryOp(op)); DCHECK(Token::IsBinaryOp(op));
DCHECK_NE(op, Token::EXP); DCHECK_NE(op, Token::EXP);
subsequent_.reserve(initial_subsequent_size);
} }
// Nary operations store the first operation (and so first two child // Nary operations store the first (lhs) child expression inline, and the
// expressions) inline, where the position of the first operation is the // child expressions (rhs of each op) are stored out-of-line, along with
// position of this expression. Subsequent child expressions are stored // their operation's position. Note that the Nary operation expression's
// out-of-line, along with with their operation's position and feedback slot. // position has no meaning.
// //
// So an nary add: // So an nary add:
// //
// expr + expr + expr + expr + ... // expr + expr + expr + ...
// //
// is stored as: // is stored as:
// //
// (expr + expr) [(+ expr), (+ expr), ...] // (expr) [(+ expr), (+ expr), ...]
// '-----.-----' '-----------.-----------' // '-.--' '-----------.-----------'
// this subsequent entry list // first subsequent entry list
Expression* first_; Expression* first_;
Expression* second_;
struct NaryOperationEntry { struct NaryOperationEntry {
Expression* expression; Expression* expression;
...@@ -3148,8 +3144,8 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3148,8 +3144,8 @@ class AstNodeFactory final BASE_EMBEDDED {
} }
NaryOperation* NewNaryOperation(Token::Value op, Expression* first, NaryOperation* NewNaryOperation(Token::Value op, Expression* first,
Expression* second, int pos) { size_t initial_subsequent_size) {
return new (zone_) NaryOperation(zone_, op, first, second, pos); return new (zone_) NaryOperation(zone_, op, first, initial_subsequent_size);
} }
CountOperation* NewCountOperation(Token::Value op, CountOperation* NewCountOperation(Token::Value op,
......
...@@ -319,8 +319,8 @@ bool Parser::CollapseNaryExpression(Expression** x, Expression* y, ...@@ -319,8 +319,8 @@ bool Parser::CollapseNaryExpression(Expression** x, Expression* y,
BinaryOperation* binop = (*x)->AsBinaryOperation(); BinaryOperation* binop = (*x)->AsBinaryOperation();
if (binop->op() != op) return false; if (binop->op() != op) return false;
nary = factory()->NewNaryOperation(op, binop->left(), binop->right(), nary = factory()->NewNaryOperation(op, binop->left(), 2);
binop->position()); nary->AddSubsequent(binop->right(), binop->position());
*x = nary; *x = nary;
} else if ((*x)->IsNaryOperation()) { } else if ((*x)->IsNaryOperation()) {
nary = (*x)->AsNaryOperation(); nary = (*x)->AsNaryOperation();
...@@ -3488,9 +3488,16 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, ...@@ -3488,9 +3488,16 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
DCHECK_EQ(cooked_strings->length(), expressions->length() + 1); DCHECK_EQ(cooked_strings->length(), expressions->length() + 1);
if (!tag) { if (!tag) {
// Build tree of BinaryOps to simplify code-generation Expression* first_string =
Expression* expr =
factory()->NewStringLiteral(cooked_strings->at(0), kNoSourcePosition); factory()->NewStringLiteral(cooked_strings->at(0), kNoSourcePosition);
if (expressions->length() == 0) return first_string;
// Build N-ary addition op to simplify code-generation.
// TODO(leszeks): Could we just store this expression in the
// TemplateLiteralState and build it as we go?
NaryOperation* expr = factory()->NewNaryOperation(
Token::ADD, first_string, 2 * expressions->length());
int i = 0; int i = 0;
while (i < expressions->length()) { while (i < expressions->length()) {
Expression* sub = expressions->at(i++); Expression* sub = expressions->at(i++);
...@@ -3501,13 +3508,11 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, ...@@ -3501,13 +3508,11 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
ZoneList<Expression*>* args = ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(1, zone()); new (zone()) ZoneList<Expression*>(1, zone());
args->Add(sub, zone()); args->Add(sub, zone());
Expression* middle = factory()->NewCallRuntime(Runtime::kInlineToString, Expression* sub_to_string = factory()->NewCallRuntime(
args, sub->position()); Runtime::kInlineToString, args, sub->position());
expr = factory()->NewBinaryOperation( expr->AddSubsequent(sub_to_string, sub->position());
Token::ADD, expr->AddSubsequent(
factory()->NewBinaryOperation(Token::ADD, expr, middle,
expr->position()),
factory()->NewStringLiteral(cooked_str, kNoSourcePosition), factory()->NewStringLiteral(cooked_str, kNoSourcePosition),
sub->position()); sub->position());
} }
......
...@@ -24,6 +24,7 @@ AddTest('Add', '+'); ...@@ -24,6 +24,7 @@ AddTest('Add', '+');
AddTest('Sub', '-'); AddTest('Sub', '-');
AddTest('BitwiseOr', '|'); AddTest('BitwiseOr', '|');
AddTestCustomPrologue('StringConcat', '+', '"string" +'); AddTestCustomPrologue('StringConcat', '+', '"string" +');
AddTestCustomPrologue('TemplateString', '} ${', '`${', '}`');
function TestExpressionDepth(depth, expression, prologue, epilogue) { function TestExpressionDepth(depth, expression, prologue, epilogue) {
var func = '(function f(a) {\n' + prologue; var func = '(function f(a) {\n' + prologue;
...@@ -84,6 +85,6 @@ function AddTest(name, expression, in_test) { ...@@ -84,6 +85,6 @@ function AddTest(name, expression, in_test) {
RunTest(name, expression, prologue, epilogue); RunTest(name, expression, prologue, epilogue);
} }
function AddTestCustomPrologue(name, expression, prologue) { function AddTestCustomPrologue(name, expression, prologue, epilogue='') {
RunTest(name, expression, prologue, ''); RunTest(name, expression, prologue, epilogue);
} }
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