Commit 65ffd616 authored by jameslahm's avatar jameslahm Committed by V8 LUCI CQ

[interpreter] create array literal boilerplates for spread calls

when BuildCreateArrayLiteral

In spread calls, create array literal boilerplates for
BuildCreateArrayLiteral rather than emit array literals
without any boilerplates

Bug: v8:11582
Change-Id: Ia0538bd043eab040c3059440e982c7f0037d1a3f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3507126Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79447}
parent 09090299
This diff is collapsed.
This diff is collapsed.
......@@ -1312,13 +1312,14 @@ void BytecodeGenerator::AllocateDeferredConstants(IsolateT* isolate,
}
// Build object literal constant properties
for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) {
ObjectLiteral* object_literal = literal.first;
if (object_literal->properties_count() > 0) {
for (std::pair<ObjectLiteralBoilerplateBuilder*, size_t> literal :
object_literals_) {
ObjectLiteralBoilerplateBuilder* object_literal_builder = literal.first;
if (object_literal_builder->properties_count() > 0) {
// If constant properties is an empty fixed array, we've already added it
// to the constant pool when visiting the object literal.
Handle<ObjectBoilerplateDescription> constant_properties =
object_literal->GetOrBuildBoilerplateDescription(isolate);
object_literal_builder->GetOrBuildBoilerplateDescription(isolate);
builder()->SetDeferredConstantPoolEntry(literal.second,
constant_properties);
......@@ -1326,10 +1327,11 @@ void BytecodeGenerator::AllocateDeferredConstants(IsolateT* isolate,
}
// Build array literal constant elements
for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) {
ArrayLiteral* array_literal = literal.first;
for (std::pair<ArrayLiteralBoilerplateBuilder*, size_t> literal :
array_literals_) {
ArrayLiteralBoilerplateBuilder* array_literal_builder = literal.first;
Handle<ArrayBoilerplateDescription> constant_elements =
array_literal->GetOrBuildBoilerplateDescription(isolate);
array_literal_builder->GetOrBuildBoilerplateDescription(isolate);
builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
}
......@@ -3032,12 +3034,12 @@ void BytecodeGenerator::BuildCreateObjectLiteral(Register literal,
}
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
expr->InitDepthAndFlags();
expr->builder()->InitDepthAndFlags();
// Fast path for the empty object literal which doesn't need an
// AllocationSite.
if (expr->IsEmptyObjectLiteral()) {
DCHECK(expr->IsFastCloningSupported());
if (expr->builder()->IsEmptyObjectLiteral()) {
DCHECK(expr->builder()->IsFastCloningSupported());
builder()->CreateEmptyObjectLiteral();
return;
}
......@@ -3052,7 +3054,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// Deep-copy the literal boilerplate.
uint8_t flags = CreateObjectLiteralFlags::Encode(
expr->ComputeFlags(), expr->IsFastCloningSupported());
expr->builder()->ComputeFlags(),
expr->builder()->IsFastCloningSupported());
Register literal = register_allocator()->NewRegister();
......@@ -3076,11 +3079,11 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
size_t entry;
// If constant properties is an empty fixed array, use a cached empty fixed
// array to ensure it's only added to the constant pool once.
if (expr->properties_count() == 0) {
if (expr->builder()->properties_count() == 0) {
entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry();
} else {
entry = builder()->AllocateDeferredConstantPoolEntry();
object_literals_.push_back(std::make_pair(expr, entry));
object_literals_.push_back(std::make_pair(expr->builder(), entry));
}
BuildCreateObjectLiteral(literal, flags, entry);
}
......@@ -3373,7 +3376,7 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
->LoadNamedProperty(array, length, length_load_slot)
.StoreAccumulatorInRegister(index);
}
} else if (expr != nullptr) {
} else {
// There are some elements before the first (if any) spread, and we can
// use a boilerplate when creating the initial array from those elements.
......@@ -3381,29 +3384,54 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
// be created during finalization, and will contain all the constant
// elements before the first spread. This also handle the empty array case
// and one-shot optimization.
ArrayLiteralBoilerplateBuilder* array_literal_builder = nullptr;
if (expr != nullptr) {
array_literal_builder = expr->builder();
} else {
DCHECK(!elements->is_empty());
// get first_spread_index
int first_spread_index = -1;
for (auto iter = elements->begin(); iter != elements->end(); iter++) {
if ((*iter)->IsSpread()) {
first_spread_index = static_cast<int>(iter - elements->begin());
break;
}
}
array_literal_builder = zone()->New<ArrayLiteralBoilerplateBuilder>(
elements, first_spread_index);
array_literal_builder->InitDepthAndFlags();
}
DCHECK(array_literal_builder != nullptr);
uint8_t flags = CreateArrayLiteralFlags::Encode(
expr->IsFastCloningSupported(), expr->ComputeFlags());
array_literal_builder->IsFastCloningSupported(),
array_literal_builder->ComputeFlags());
if (is_empty) {
// Empty array literal fast-path.
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
DCHECK(expr->IsFastCloningSupported());
DCHECK(array_literal_builder->IsFastCloningSupported());
builder()->CreateEmptyArrayLiteral(literal_index);
} else {
// Create array literal from boilerplate.
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
array_literals_.push_back(std::make_pair(expr, entry));
array_literals_.push_back(std::make_pair(array_literal_builder, entry));
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
builder()->CreateArrayLiteral(entry, literal_index, flags);
}
builder()->StoreAccumulatorInRegister(array);
ZonePtrList<Expression>::const_iterator first_spread_or_end =
array_literal_builder->first_spread_index() >= 0
? current + array_literal_builder->first_spread_index()
: end;
// Insert the missing non-constant elements, up until the first spread
// index, into the initial array (the remaining elements will be inserted
// below).
DCHECK_EQ(current, elements->begin());
ZonePtrList<Expression>::const_iterator first_spread_or_end =
expr->first_spread_index() >= 0 ? current + expr->first_spread_index()
: end;
int array_index = 0;
for (; current != first_spread_or_end; ++current, array_index++) {
Expression* subexpr = *current;
......@@ -3426,17 +3454,6 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index);
}
} else {
// TODO(v8:11582): Support allocating boilerplates here.
// In other cases, we prepare an empty array to be filled in below.
DCHECK(!elements->is_empty());
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
builder()
->CreateEmptyArrayLiteral(literal_index)
.StoreAccumulatorInRegister(array);
// Prepare the index for the first element.
builder()->LoadLiteral(Smi::FromInt(0)).StoreAccumulatorInRegister(index);
}
// Now build insertions for the remaining elements from current to end.
......@@ -3491,7 +3508,7 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
}
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
expr->InitDepthAndFlags();
expr->builder()->InitDepthAndFlags();
BuildCreateArrayLiteral(expr->values(), expr);
}
......@@ -4314,7 +4331,7 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
// Store the assignment value in a register.
Register value;
RegisterList rest_runtime_callargs;
if (pattern->has_rest_property()) {
if (pattern->builder()->has_rest_property()) {
rest_runtime_callargs =
register_allocator()->NewRegisterList(pattern->properties()->length());
value = rest_runtime_callargs[0];
......@@ -4378,8 +4395,8 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
if (pattern_key->IsPropertyName()) {
value_name = pattern_key->AsLiteral()->AsRawPropertyName();
}
if (pattern->has_rest_property() || !value_name) {
if (pattern->has_rest_property()) {
if (pattern->builder()->has_rest_property() || !value_name) {
if (pattern->builder()->has_rest_property()) {
value_key = rest_runtime_callargs[i + 1];
} else {
value_key = register_allocator()->NewRegister();
......@@ -4396,9 +4413,9 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
} else {
// We only need the key for non-computed properties when it is numeric
// or is being saved for the rest_runtime_callargs.
DCHECK(
pattern_key->IsNumberLiteral() ||
(pattern->has_rest_property() && pattern_key->IsPropertyName()));
DCHECK(pattern_key->IsNumberLiteral() ||
(pattern->builder()->has_rest_property() &&
pattern_key->IsPropertyName()));
VisitForRegisterValue(pattern_key, value_key);
}
}
......
......@@ -519,8 +519,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
native_function_literals_;
ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
ZoneVector<std::pair<ObjectLiteralBoilerplateBuilder*, size_t>>
object_literals_;
ZoneVector<std::pair<ArrayLiteralBoilerplateBuilder*, size_t>>
array_literals_;
ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
......
......@@ -65,43 +65,38 @@ snippet: "
"
frame size: 7
parameter count: 1
bytecode array length: 95
bytecode array length: 88
bytecodes: [
/* 34 S> */ B(LdaGlobal), U8(0), U8(0),
B(Star1),
/* 39 E> */ B(GetNamedProperty), R(1), U8(1), U8(2),
B(Star0),
B(CreateEmptyArrayLiteral), U8(4),
B(CreateArrayLiteral), U8(2), U8(4), U8(37),
B(Star3),
B(LdaZero),
B(Star2),
B(LdaZero),
B(StaInArrayLiteral), R(3), R(2), U8(5),
B(Ldar), R(2),
B(Inc), U8(7),
B(LdaSmi), I8(1),
B(Star2),
/* 49 S> */ B(CreateArrayLiteral), U8(2), U8(8), U8(37),
/* 49 S> */ B(CreateArrayLiteral), U8(3), U8(5), U8(37),
B(Star6),
/* 49 E> */ B(GetIterator), R(6), U8(9), U8(11),
/* 49 E> */ B(GetIterator), R(6), U8(6), U8(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star5),
B(GetNamedProperty), R(5), U8(3), U8(13),
B(GetNamedProperty), R(5), U8(4), U8(10),
B(Star4),
B(CallProperty0), R(4), R(5), U8(19),
B(Star6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(GetNamedProperty), R(6), U8(4), U8(21),
B(GetNamedProperty), R(6), U8(5), U8(21),
B(JumpIfToBooleanTrue), U8(18),
B(GetNamedProperty), R(6), U8(5), U8(15),
B(StaInArrayLiteral), R(3), R(2), U8(5),
B(GetNamedProperty), R(6), U8(6), U8(12),
B(StaInArrayLiteral), R(3), R(2), U8(17),
B(Ldar), R(2),
B(Inc), U8(7),
B(Inc), U8(16),
B(Star2),
B(JumpLoop), U8(31), I8(0),
B(LdaSmi), I8(4),
B(StaInArrayLiteral), R(3), R(2), U8(5),
B(StaInArrayLiteral), R(3), R(2), U8(17),
B(Mov), R(3), R(2),
/* 39 E> */ B(CallJSRuntime), U8(%reflect_apply), R(0), U8(3),
B(LdaUndefined),
......@@ -111,6 +106,7 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["Math"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["max"],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
......
......@@ -90,7 +90,7 @@ snippet: "
"
frame size: 7
parameter count: 1
bytecode array length: 117
bytecode array length: 110
bytecodes: [
B(CreateBlockContext), U8(0),
B(PushContext), R(1),
......@@ -105,38 +105,33 @@ bytecodes: [
B(Star3),
B(PopContext), R(1),
B(Mov), R(4), R(0),
/* 89 S> */ B(CreateEmptyArrayLiteral), U8(0),
/* 89 S> */ B(CreateArrayLiteral), U8(3), U8(0), U8(37),
B(Star3),
B(LdaZero),
B(Star2),
B(LdaZero),
B(StaInArrayLiteral), R(3), R(2), U8(1),
B(Ldar), R(2),
B(Inc), U8(3),
B(LdaSmi), I8(1),
B(Star2),
/* 101 S> */ B(CreateArrayLiteral), U8(3), U8(4), U8(37),
/* 101 S> */ B(CreateArrayLiteral), U8(4), U8(1), U8(37),
B(Star6),
/* 101 E> */ B(GetIterator), R(6), U8(5), U8(7),
/* 101 E> */ B(GetIterator), R(6), U8(2), U8(4),
B(Mov), R(4), R(1),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star5),
B(GetNamedProperty), R(5), U8(4), U8(9),
B(GetNamedProperty), R(5), U8(5), U8(6),
B(Star4),
B(CallProperty0), R(4), R(5), U8(15),
B(Star6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(GetNamedProperty), R(6), U8(5), U8(17),
B(GetNamedProperty), R(6), U8(6), U8(17),
B(JumpIfToBooleanTrue), U8(18),
B(GetNamedProperty), R(6), U8(6), U8(11),
B(StaInArrayLiteral), R(3), R(2), U8(1),
B(GetNamedProperty), R(6), U8(7), U8(8),
B(StaInArrayLiteral), R(3), R(2), U8(13),
B(Ldar), R(2),
B(Inc), U8(3),
B(Inc), U8(12),
B(Star2),
B(JumpLoop), U8(31), I8(0),
B(LdaSmi), I8(4),
B(StaInArrayLiteral), R(3), R(2), U8(1),
B(StaInArrayLiteral), R(3), R(2), U8(13),
B(Mov), R(3), R(2),
/* 89 E> */ B(CallJSRuntime), U8(%reflect_construct), R(1), U8(2),
B(LdaUndefined),
......@@ -147,6 +142,7 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
......
......@@ -93,7 +93,7 @@ snippet: "
"
frame size: 11
parameter count: 1
bytecode array length: 111
bytecode array length: 103
bytecodes: [
/* 128 E> */ B(CreateRestParameter),
B(Star3),
......@@ -101,36 +101,31 @@ bytecodes: [
B(Mov), R(3), R(2),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(CreateEmptyArrayLiteral), U8(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star7),
B(LdaZero),
B(Star6),
B(LdaSmi), I8(1),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(Ldar), R(6),
B(Inc), U8(3),
/* 152 S> */ B(Star6),
/* 152 E> */ B(GetIterator), R(3), U8(4), U8(6),
/* 152 E> */ B(GetIterator), R(3), U8(1), U8(3),
B(Mov), R(1), R(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star9),
B(GetNamedProperty), R(9), U8(0), U8(8),
B(GetNamedProperty), R(9), U8(1), U8(5),
B(Star8),
B(CallProperty0), R(8), R(9), U8(14),
B(Star10),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
B(GetNamedProperty), R(10), U8(1), U8(16),
B(GetNamedProperty), R(10), U8(2), U8(16),
B(JumpIfToBooleanTrue), U8(18),
B(GetNamedProperty), R(10), U8(2), U8(10),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(GetNamedProperty), R(10), U8(3), U8(7),
B(StaInArrayLiteral), R(7), R(6), U8(12),
B(Ldar), R(6),
B(Inc), U8(3),
B(Inc), U8(11),
B(Star6),
B(JumpLoop), U8(31), I8(0),
B(LdaSmi), I8(1),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(StaInArrayLiteral), R(7), R(6), U8(12),
B(ThrowIfNotSuperConstructor), R(5),
B(Mov), R(5), R(6),
B(Mov), R(0), R(8),
......@@ -144,6 +139,7 @@ bytecodes: [
/* 162 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["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