Commit b8128279 authored by Michael Achenbach's avatar Michael Achenbach Committed by Commit Bot

Revert "[esnext] re-implement template strings"

This reverts commit 8ae19e08.

Reason for revert:
Speculative revert for layout test:
https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/22215

See:
https://github.com/v8/v8/wiki/Blink-layout-tests

Original change's description:
> [esnext] re-implement template strings
> 
> - Add a new bytecode for the ToString operation, replacing the old
> intrinsic call (currently does not collect type feedback).
> - Add a new AST node to represent TemplateLiterals, and avoid
> generating unnecessary ToString operations in some simple cases.
> - Use a single feedback slot for each string addition, because the
> type feedback should always be the same for each addition
> 
> This seems to produce a very slight improvement on JSTests benchmarks
> and bench-ruben.js from v8:7415, and it's possible that type feedback
> for the ToString bytecode could provide more opportunities to eliminate
> the runtime call in TurboFan.
> 
> Doesn't touch tagged templates
> 
> BUG=v8:7415
> R=​rmcilroy@chromium.org, ishell@chromium.org, bmeurer@chromium.org
> 
> Change-Id: If5a8c68558431f058db894d65776324abf54218e
> Reviewed-on: https://chromium-review.googlesource.com/945408
> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> Commit-Queue: Caitlin Potter <caitp@igalia.com>
> Cr-Commit-Position: refs/heads/master@{#51853}

TBR=rmcilroy@chromium.org,caitp@igalia.com,ishell@chromium.org,bmeurer@chromium.org

Change-Id: Id0529b065493ffc20c8f2b1abacc4c1484c3c046
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7415
Reviewed-on: https://chromium-review.googlesource.com/958163Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51862}
parent 89204e90
......@@ -535,15 +535,6 @@ void AstTraversalVisitor<Subclass>::VisitGetTemplateObject(
PROCESS_EXPRESSION(expr);
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitTemplateLiteral(
TemplateLiteral* expr) {
PROCESS_EXPRESSION(expr);
for (Expression* sub : *expr->substitutions()) {
RECURSE_EXPRESSION(Visit(sub));
}
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitImportCallExpression(
ImportCallExpression* expr) {
......
......@@ -99,7 +99,6 @@ namespace internal {
V(Spread) \
V(SuperCallReference) \
V(SuperPropertyReference) \
V(TemplateLiteral) \
V(ThisFunction) \
V(Throw) \
V(UnaryOperation) \
......@@ -2654,26 +2653,6 @@ class GetTemplateObject final : public Expression {
const ZoneList<const AstRawString*>* raw_strings_;
};
class TemplateLiteral final : public Expression {
public:
using StringList = ZoneList<const AstRawString*>;
using ExpressionList = ZoneList<Expression*>;
const StringList* string_parts() const { return string_parts_; }
const ExpressionList* substitutions() const { return substitutions_; }
private:
friend class AstNodeFactory;
TemplateLiteral(const StringList* parts, const ExpressionList* substitutions,
int pos)
: Expression(pos, kTemplateLiteral),
string_parts_(parts),
substitutions_(substitutions) {}
const StringList* string_parts_;
const ExpressionList* substitutions_;
};
// ----------------------------------------------------------------------------
// Basic visitor
// Sub-class should parametrize AstVisitor with itself, e.g.:
......@@ -3250,12 +3229,6 @@ class AstNodeFactory final BASE_EMBEDDED {
return new (zone_) GetTemplateObject(cooked_strings, raw_strings, pos);
}
TemplateLiteral* NewTemplateLiteral(
const ZoneList<const AstRawString*>* string_parts,
const ZoneList<Expression*>* substitutions, int pos) {
return new (zone_) TemplateLiteral(string_parts, substitutions, pos);
}
ImportCallExpression* NewImportCallExpression(Expression* args, int pos) {
return new (zone_) ImportCallExpression(args, pos);
}
......
......@@ -466,26 +466,6 @@ void CallPrinter::VisitGetIterator(GetIterator* node) {
void CallPrinter::VisitGetTemplateObject(GetTemplateObject* node) {}
void CallPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
if (node->substitutions()->length() && node->position() < position_ &&
node->substitutions()->last()->position() <= position_) {
found_ = true;
Print("`...${");
for (Expression* sub : *node->substitutions()) {
if (sub->position() < position_) continue;
Find(sub, true);
}
Print("}...`");
done_ = true;
} else if (node->string_parts()->length() == 1) {
Print("`");
PrintLiteral(node->string_parts()->first(), false);
Print("`");
} else {
Print("`...`");
}
}
void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
Print("ImportCall(");
Find(node->argument(), true);
......@@ -1352,17 +1332,6 @@ void AstPrinter::VisitGetTemplateObject(GetTemplateObject* node) {
IndentedScope indent(this, "GET-TEMPLATE-OBJECT", node->position());
}
void AstPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
IndentedScope indent(this, "TEMPLATE-LITERAL", node->position());
const AstRawString* string = node->string_parts()->first();
if (!string->IsEmpty()) PrintLiteralIndented("SPAN", string, true);
for (int i = 0; i < node->string_parts()->length();) {
PrintIndentedVisit("EXPR", node->substitutions()->at(i++));
string = node->string_parts()->at(i);
if (!string->IsEmpty()) PrintLiteralIndented("SPAN", string, true);
}
}
void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
IndentedScope indent(this, "IMPORT-CALL", node->position());
Visit(node->argument());
......
......@@ -2528,12 +2528,6 @@ void BytecodeGraphBuilder::VisitToObject() {
BuildCastOperator(javascript()->ToObject());
}
void BytecodeGraphBuilder::VisitToString() {
Node* value =
NewNode(javascript()->ToString(), environment()->LookupAccumulator());
environment()->BindAccumulator(value, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitToNumber() {
PrepareEagerCheckpoint();
Node* object = environment()->LookupAccumulator();
......
......@@ -507,7 +507,6 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
case Bytecode::kToObject:
case Bytecode::kToNumber:
case Bytecode::kToName:
case Bytecode::kToString:
// Misc.
case Bytecode::kForInEnumerate:
case Bytecode::kForInPrepare:
......
......@@ -1004,11 +1004,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ToName(Register out) {
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::ToString() {
OutputToString();
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumber(int feedback_slot) {
OutputToNumber(feedback_slot);
return *this;
......
......@@ -376,7 +376,6 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
// Converts accumulator and stores result in register |out|.
BytecodeArrayBuilder& ToObject(Register out);
BytecodeArrayBuilder& ToName(Register out);
BytecodeArrayBuilder& ToString();
// Converts accumulator and stores result back in accumulator.
BytecodeArrayBuilder& ToNumber(int feedback_slot);
......
......@@ -593,11 +593,6 @@ class BytecodeGenerator::ExpressionResultScope {
type_hint_ = TypeHint::kBoolean;
}
void SetResultIsString() {
DCHECK_EQ(type_hint_, TypeHint::kAny);
type_hint_ = TypeHint::kString;
}
TypeHint type_hint() const { return type_hint_; }
private:
......@@ -2062,7 +2057,6 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
break;
case Literal::kString:
builder()->LoadLiteral(expr->AsRawString());
execution_result()->SetResultIsString();
break;
case Literal::kSymbol:
builder()->LoadLiteral(expr->AsSymbol());
......@@ -3988,23 +3982,13 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
Expression* subexpr;
Smi* literal;
if (expr->IsSmiLiteralOperation(&subexpr, &literal)) {
TypeHint type_hint = VisitForAccumulatorValue(subexpr);
VisitForAccumulatorValue(subexpr);
builder()->SetExpressionPosition(expr);
builder()->BinaryOperationSmiLiteral(expr->op(), literal,
feedback_index(slot));
if (expr->op() == Token::ADD && type_hint == TypeHint::kString) {
execution_result()->SetResultIsString();
}
} else {
TypeHint lhs_type = VisitForAccumulatorValue(expr->left());
Register lhs = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(lhs);
TypeHint rhs_type = VisitForAccumulatorValue(expr->right());
if (expr->op() == Token::ADD &&
(lhs_type == TypeHint::kString || rhs_type == TypeHint::kString)) {
execution_result()->SetResultIsString();
}
Register lhs = VisitForRegisterValue(expr->left());
VisitForAccumulatorValue(expr->right());
builder()->SetExpressionPosition(expr);
builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot));
}
......@@ -4012,7 +3996,7 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
void BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) {
// TODO(leszeks): Add support for lhs smi in commutative ops.
TypeHint type_hint = VisitForAccumulatorValue(expr->first());
VisitForAccumulatorValue(expr->first());
for (size_t i = 0; i < expr->subsequent_length(); ++i) {
RegisterAllocationScope register_scope(this);
......@@ -4024,19 +4008,13 @@ void BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) {
} else {
Register lhs = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(lhs);
TypeHint rhs_hint = VisitForAccumulatorValue(expr->subsequent(i));
if (rhs_hint == TypeHint::kString) type_hint = TypeHint::kString;
VisitForAccumulatorValue(expr->subsequent(i));
builder()->SetExpressionPosition(expr->subsequent_op_position(i));
builder()->BinaryOperation(
expr->op(), lhs,
feedback_index(feedback_spec()->AddBinaryOpICSlot()));
}
}
if (type_hint == TypeHint::kString && expr->op() == Token::ADD) {
// If any operand of an ADD is a String, a String is produced.
execution_result()->SetResultIsString();
}
}
void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); }
......@@ -4217,53 +4195,6 @@ void BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) {
builder()->GetTemplateObject(entry, feedback_index(literal_slot));
}
void BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) {
const TemplateLiteral::StringList& parts = *expr->string_parts();
const TemplateLiteral::ExpressionList& substitutions = *expr->substitutions();
// Template strings with no substitutions are turned into StringLiterals.
DCHECK_GT(substitutions.length(), 0);
DCHECK_EQ(parts.length(), substitutions.length() + 1);
// Generate string concatenation
// TODO(caitp): Don't generate feedback slot if it's not used --- introduce
// a simple, concise, reusable mechanism to lazily create reusable slots.
FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
Register last_part = register_allocator()->NewRegister();
bool last_part_valid = false;
builder()->SetExpressionPosition(expr);
for (int i = 0; i < substitutions.length(); ++i) {
if (i != 0) {
builder()->StoreAccumulatorInRegister(last_part);
last_part_valid = true;
}
if (!parts[i]->IsEmpty()) {
builder()->LoadLiteral(parts[i]);
if (last_part_valid) {
builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
}
builder()->StoreAccumulatorInRegister(last_part);
last_part_valid = true;
}
TypeHint type_hint = VisitForAccumulatorValue(substitutions[i]);
if (type_hint != TypeHint::kString) {
builder()->ToString();
}
if (last_part_valid) {
builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
}
last_part_valid = false;
}
if (!parts.last()->IsEmpty()) {
builder()->StoreAccumulatorInRegister(last_part);
builder()->LoadLiteral(parts.last());
builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
}
}
void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
builder()->LoadAccumulatorWithRegister(Register::function_closure());
}
......
......@@ -66,7 +66,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
enum class TestFallthrough { kThen, kElse, kNone };
enum class TypeHint { kAny, kBoolean, kString };
enum class TypeHint { kAny, kBoolean };
void GenerateBytecodeBody();
void AllocateDeferredConstants(Isolate* isolate, Handle<Script> script);
......
......@@ -223,7 +223,6 @@ namespace interpreter {
V(ToNumber, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(ToNumeric, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(ToObject, AccumulatorUse::kRead, OperandType::kRegOut) \
V(ToString, AccumulatorUse::kReadWrite) \
\
/* Literals */ \
V(CreateRegExpLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \
......
......@@ -1304,14 +1304,6 @@ IGNITION_HANDLER(ToObject, InterpreterAssembler) {
Dispatch();
}
// ToString
//
// Convert the accumulator to a String.
IGNITION_HANDLER(ToString, InterpreterAssembler) {
SetAccumulator(ToString_Inline(GetContext(), GetAccumulator()));
Dispatch();
}
class IncDecAssembler : public UnaryNumericOpAssembler {
public:
explicit IncDecAssembler(CodeAssemblerState* state, Bytecode bytecode,
......
......@@ -3492,10 +3492,52 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
DCHECK_EQ(cooked_strings->length(), expressions->length() + 1);
if (!tag) {
if (cooked_strings->length() == 1) {
return factory()->NewStringLiteral(cooked_strings->first(), pos);
const AstRawString* first_string = cooked_strings->at(0);
if (expressions->length() == 0) {
return factory()->NewStringLiteral(first_string, kNoSourcePosition);
}
return factory()->NewTemplateLiteral(cooked_strings, expressions, pos);
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.
// TODO(leszeks): Could we just store this expression in the
// TemplateLiteralState and build it as we go?
NaryOperation* expr = factory()->NewNaryOperation(
Token::ADD, first, 2 * expressions->length() - num_empty);
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()) {
Expression* sub = expressions->at(i++);
const AstRawString* cooked_str = cooked_strings->at(i);
DCHECK_NOT_NULL(cooked_str);
// Let middle be ToString(sub).
expr->AddSubsequent(ToString(sub), sub->position());
if (!cooked_str->IsEmpty()) {
expr->AddSubsequent(
factory()->NewStringLiteral(cooked_str, kNoSourcePosition),
sub->position());
}
}
return expr;
} else {
// GetTemplateObject
Expression* template_object =
......
......@@ -772,7 +772,6 @@ NOT_A_PATTERN(Spread)
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)
......
......@@ -13,22 +13,20 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 28
bytecode array length: 30
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
/* 53 S> */ B(LdaSmi), I8(2),
B(Star), R(1),
/* 56 S> */ B(Ldar), R(0),
B(ToString),
/* 56 S> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(0), U8(1),
B(Star), R(2),
B(Ldar), R(1),
/* 70 E> */ B(ToString),
B(Add), R(2), U8(0),
/* 70 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(1), U8(1),
/* 70 E> */ B(Add), R(2), U8(0),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Add), R(2), U8(0),
/* 70 E> */ B(Add), R(2), U8(1),
/* 80 S> */ B(Return),
]
constant pool: [
......@@ -45,7 +43,7 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 28
bytecode array length: 30
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(1),
......@@ -54,13 +52,11 @@ bytecodes: [
B(Star), R(1),
/* 56 S> */ B(LdaConstant), U8(0),
B(Star), R(2),
B(Ldar), R(0),
/* 72 E> */ B(ToString),
B(Add), R(2), U8(0),
/* 72 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(0), U8(1),
/* 72 E> */ B(Add), R(2), U8(0),
B(Star), R(2),
B(Ldar), R(1),
/* 76 E> */ B(ToString),
B(Add), R(2), U8(0),
/* 76 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(1), U8(1),
/* 76 E> */ B(Add), R(2), U8(1),
/* 80 S> */ B(Return),
]
constant pool: [
......@@ -77,22 +73,20 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 28
bytecode array length: 30
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
/* 53 S> */ B(LdaSmi), I8(2),
B(Star), R(1),
/* 56 S> */ B(Ldar), R(0),
B(ToString),
/* 56 S> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(0), U8(1),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Add), R(2), U8(0),
/* 66 E> */ B(Add), R(2), U8(0),
B(Star), R(2),
B(Ldar), R(1),
/* 76 E> */ B(ToString),
B(Add), R(2), U8(0),
/* 76 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(1), U8(1),
/* 76 E> */ B(Add), R(2), U8(1),
/* 80 S> */ B(Return),
]
constant pool: [
......@@ -107,9 +101,9 @@ snippet: "
var b = 2;
return `foo${a}bar${b}baz${1}`;
"
frame size: 3
frame size: 4
parameter count: 1
bytecode array length: 50
bytecode array length: 57
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(1),
......@@ -118,23 +112,22 @@ bytecodes: [
B(Star), R(1),
/* 56 S> */ B(LdaConstant), U8(0),
B(Star), R(2),
B(Ldar), R(0),
/* 69 E> */ B(ToString),
B(Add), R(2), U8(0),
/* 69 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(0), U8(1),
/* 69 E> */ B(Add), R(2), U8(0),
B(Star), R(2),
B(LdaConstant), U8(1),
B(Add), R(2), U8(0),
/* 69 E> */ B(Add), R(2), U8(1),
B(Star), R(2),
B(Ldar), R(1),
/* 76 E> */ B(ToString),
B(Add), R(2), U8(0),
/* 76 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(1), U8(1),
/* 76 E> */ B(Add), R(2), U8(2),
B(Star), R(2),
B(LdaConstant), U8(2),
B(Add), R(2), U8(0),
/* 76 E> */ B(Add), R(2), U8(3),
B(Star), R(2),
B(LdaSmi), I8(1),
B(ToString),
B(Add), R(2), U8(0),
B(Star), R(3),
B(InvokeIntrinsic), U8(Runtime::k_ToString), R(3), U8(1),
/* 83 E> */ B(Add), R(2), U8(4),
/* 87 S> */ B(Return),
]
constant pool: [
......@@ -153,25 +146,23 @@ snippet: "
"
frame size: 4
parameter count: 1
bytecode array length: 35
bytecode array length: 37
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
/* 53 S> */ B(LdaSmi), I8(2),
B(Star), R(1),
/* 56 S> */ B(Ldar), R(0),
B(ToString),
/* 56 S> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(0), U8(1),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Add), R(2), U8(1),
/* 66 E> */ B(Add), R(2), U8(0),
B(Star), R(2),
B(LdaConstant), U8(0),
B(Star), R(3),
B(Ldar), R(1),
/* 87 E> */ B(ToString),
B(Add), R(3), U8(2),
/* 76 E> */ B(Add), R(2), U8(0),
/* 87 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(1), U8(1),
/* 87 E> */ B(Add), R(3), U8(1),
/* 76 E> */ B(Add), R(2), U8(2),
/* 91 S> */ B(Return),
]
constant pool: [
......@@ -187,9 +178,9 @@ snippet: "
function foo(a, b) { };
return `string${foo(a, b)}${a}${b}`;
"
frame size: 4
frame size: 5
parameter count: 1
bytecode array length: 45
bytecode array length: 52
bytecodes: [
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
......@@ -200,17 +191,16 @@ bytecodes: [
B(Star), R(1),
/* 80 S> */ B(LdaConstant), U8(1),
B(Star), R(3),
/* 96 E> */ B(CallUndefinedReceiver2), R(2), R(0), R(1), U8(2),
B(ToString),
B(Add), R(3), U8(1),
/* 96 E> */ B(CallUndefinedReceiver2), R(2), R(0), R(1), U8(1),
B(Star), R(4),
B(InvokeIntrinsic), U8(Runtime::k_ToString), R(4), U8(1),
/* 96 E> */ B(Add), R(3), U8(3),
B(Star), R(3),
B(Ldar), R(0),
/* 108 E> */ B(ToString),
B(Add), R(3), U8(1),
/* 108 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(0), U8(1),
/* 108 E> */ B(Add), R(3), U8(4),
B(Star), R(3),
B(Ldar), R(1),
/* 112 E> */ B(ToString),
B(Add), R(3), U8(1),
/* 112 E> */ B(InvokeIntrinsic), U8(Runtime::k_ToString), R(1), U8(1),
/* 112 E> */ B(Add), R(3), U8(5),
/* 116 S> */ B(Return),
]
constant pool: [
......
......@@ -262,7 +262,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CompareNull();
// Emit conversion operator invocations.
builder.ToNumber(1).ToNumeric(1).ToObject(reg).ToName(reg).ToString();
builder.ToNumber(1).ToNumeric(1).ToObject(reg).ToName(reg);
// Emit GetSuperConstructor.
builder.GetSuperConstructor(reg);
......
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