Commit b53189e8 authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[parser] don't generate unnecessary ADDs for template strings

Avoid generating ADDs when concatenating the empty string with other
template parts. This prevents the creation of useless feedback slots,
and reduces the number of extra dispatches.

The impact on performance is negligible.

BUG=v8:7415

Change-Id: I7ef3806b53f7252f3a86f7007ae7050ac697c1e3
Reviewed-on: https://chromium-review.googlesource.com/938145Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#51669}
parent 3d7ad2e7
...@@ -3491,33 +3491,50 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, ...@@ -3491,33 +3491,50 @@ 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) {
Expression* first_string = const AstRawString* first_string = cooked_strings->at(0);
factory()->NewStringLiteral(cooked_strings->at(0), kNoSourcePosition); if (expressions->length() == 0) {
if (expressions->length() == 0) return first_string; return factory()->NewStringLiteral(first_string, kNoSourcePosition);
}
size_t num_empty =
std::count_if(cooked_strings->begin(), cooked_strings->end(),
[=](const AstRawString* lit) { return lit->IsEmpty(); });
const bool kFirstIsEmpty = first_string->IsEmpty();
Expression* first = kFirstIsEmpty ? ToString(expressions->at(0))
: factory()->NewStringLiteral(
first_string, kNoSourcePosition);
// Build N-ary addition op to simplify code-generation. // Build N-ary addition op to simplify code-generation.
// TODO(leszeks): Could we just store this expression in the // TODO(leszeks): Could we just store this expression in the
// TemplateLiteralState and build it as we go? // TemplateLiteralState and build it as we go?
NaryOperation* expr = factory()->NewNaryOperation( NaryOperation* expr = factory()->NewNaryOperation(
Token::ADD, first_string, 2 * expressions->length()); Token::ADD, first, 2 * expressions->length() - num_empty);
int i = 0; int i = 0;
if (kFirstIsEmpty) {
// If the first string is empty, possibly add the next template span
// outside of the loop, to keep the loop logic simple.
i = 1;
const AstRawString* str = cooked_strings->at(1);
if (!str->IsEmpty()) {
expr->AddSubsequent(factory()->NewStringLiteral(str, kNoSourcePosition),
first->position());
}
}
while (i < expressions->length()) { while (i < expressions->length()) {
Expression* sub = expressions->at(i++); Expression* sub = expressions->at(i++);
const AstRawString* cooked_str = cooked_strings->at(i); const AstRawString* cooked_str = cooked_strings->at(i);
DCHECK_NOT_NULL(cooked_str); DCHECK_NOT_NULL(cooked_str);
// Let middle be ToString(sub). // Let middle be ToString(sub).
ZoneList<Expression*>* args = expr->AddSubsequent(ToString(sub), sub->position());
new (zone()) ZoneList<Expression*>(1, zone()); if (!cooked_str->IsEmpty()) {
args->Add(sub, zone()); expr->AddSubsequent(
Expression* sub_to_string = factory()->NewCallRuntime( factory()->NewStringLiteral(cooked_str, kNoSourcePosition),
Runtime::kInlineToString, args, sub->position()); sub->position());
}
expr->AddSubsequent(sub_to_string, sub->position());
expr->AddSubsequent(
factory()->NewStringLiteral(cooked_str, kNoSourcePosition),
sub->position());
} }
return expr; return expr;
} else { } else {
......
...@@ -696,6 +696,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -696,6 +696,15 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
} }
} }
// A shortcut for performing a ToString operation
V8_INLINE Expression* ToString(Expression* expr) {
if (expr->IsStringLiteral()) return expr;
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(expr, zone());
return factory()->NewCallRuntime(Runtime::kInlineToString, args,
expr->position());
}
// Returns true if we have a binary expression between two numeric // Returns true if we have a binary expression between two numeric
// literals. In that case, *x will be changed to an expression which is the // literals. In that case, *x will be changed to an expression which is the
// computed value. // computed value.
......
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