[Interpreter] Avoid allocating handles in bytecode-array-writer

Don't allocate handles in the bytecode array writer, to allow off-thread
bytecode generation.

BUG=v8:5203

Review-Url: https://codereview.chromium.org/2226333002
Cr-Commit-Position: refs/heads/master@{#38550}
This commit is contained in:
rmcilroy 2016-08-10 09:41:43 -07:00 committed by Commit bot
parent b558894ac4
commit d1ab9f126c
4 changed files with 164 additions and 135 deletions

View File

@ -254,13 +254,11 @@ void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
} else {
// TODO(5203): Remove this temporary exception.
AllowHandleAllocation allow_handles;
// The jump does not fit within the range of an Imm operand, so
// commit reservation putting the offset into the constant pool,
// and update the jump instruction and operand.
size_t entry = constant_array_builder()->CommitReservedEntry(
OperandSize::kByte, handle(Smi::FromInt(delta), isolate()));
OperandSize::kByte, Smi::FromInt(delta));
DCHECK_LE(entry, kMaxUInt32);
DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
OperandSize::kByte);
@ -280,12 +278,10 @@ void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta));
} else {
// TODO(5203): Remove this temporary exception.
AllowHandleAllocation allow_handles;
jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
size_t entry = constant_array_builder()->CommitReservedEntry(
OperandSize::kShort, handle(Smi::FromInt(delta), isolate()));
OperandSize::kShort, Smi::FromInt(delta));
WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry));
}
DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&

View File

@ -71,7 +71,10 @@ STATIC_CONST_MEMBER_DEFINITION const size_t
ConstantArrayBuilder::k32BitCapacity;
ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone)
: isolate_(isolate), constants_map_(zone) {
: isolate_(isolate),
constants_map_(zone),
smi_map_(zone),
smi_pairs_(zone) {
idx_slice_[0] =
new (zone) ConstantArraySlice(zone, 0, k8BitCapacity, OperandSize::kByte);
idx_slice_[1] = new (zone) ConstantArraySlice(
@ -113,6 +116,12 @@ Handle<Object> ConstantArrayBuilder::At(size_t index) const {
}
Handle<FixedArray> ConstantArrayBuilder::ToFixedArray() {
// First insert reserved SMI values.
for (auto reserved_smi : smi_pairs_) {
InsertAllocatedEntry(reserved_smi.second,
handle(reserved_smi.first, isolate_));
}
Handle<FixedArray> fixed_array = isolate_->factory()->NewFixedArray(
static_cast<int>(size()), PretenureFlag::TENURED);
int array_index = 0;
@ -209,13 +218,21 @@ OperandSize ConstantArrayBuilder::CreateReservedEntry() {
return OperandSize::kNone;
}
ConstantArrayBuilder::index_t ConstantArrayBuilder::AllocateReservedEntry(
Smi* value) {
index_t index = static_cast<index_t>(AllocateEntry());
smi_map_[value] = index;
smi_pairs_.push_back(std::make_pair(value, index));
return index;
}
size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size,
Handle<Object> object) {
Smi* value) {
DiscardReservedEntry(operand_size);
size_t index;
auto entry = constants_map_.find(object.address());
if (entry == constants_map_.end()) {
index = AllocateEntry(object);
auto entry = smi_map_.find(value);
if (entry == smi_map_.end()) {
index = AllocateReservedEntry(value);
} else {
ConstantArraySlice* slice = OperandSizeToSlice(operand_size);
index = entry->second;
@ -223,9 +240,9 @@ size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size,
// The object is already in the constant array, but may have an
// index too big for the reserved operand_size. So, duplicate
// entry with the smaller operand size.
index = slice->Allocate(object);
constants_map_[object.address()] = static_cast<index_t>(index);
index = AllocateReservedEntry(value);
}
DCHECK_LE(index, slice->max_index());
}
return index;
}

View File

@ -61,8 +61,8 @@ class ConstantArrayBuilder final BASE_EMBEDDED {
OperandSize CreateReservedEntry();
// Commit reserved entry and returns the constant pool index for the
// object.
size_t CommitReservedEntry(OperandSize operand_size, Handle<Object> object);
// SMI value.
size_t CommitReservedEntry(OperandSize operand_size, Smi* value);
// Discards constant pool reservation.
void DiscardReservedEntry(OperandSize operand_size);
@ -72,6 +72,7 @@ class ConstantArrayBuilder final BASE_EMBEDDED {
index_t AllocateEntry(Handle<Object> object);
index_t AllocateIndex(Handle<Object> object);
index_t AllocateReservedEntry(Smi* value);
struct ConstantArraySlice final : public ZoneObject {
ConstantArraySlice(Zone* zone, size_t start_index, size_t capacity,
@ -107,6 +108,8 @@ class ConstantArrayBuilder final BASE_EMBEDDED {
Isolate* isolate_;
ConstantArraySlice* idx_slice_[3];
ZoneMap<Address, index_t> constants_map_;
ZoneMap<Smi*, index_t> smi_map_;
ZoneVector<std::pair<Smi*, index_t>> smi_pairs_;
};
} // namespace interpreter

View File

@ -40,113 +40,6 @@ TEST_F(ConstantArrayBuilderTest, AllocateAllEntries) {
}
}
TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) {
CanonicalHandleScope canonical(isolate());
for (size_t reserved = 1; reserved < k8BitCapacity; reserved *= 3) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kByte);
}
for (size_t i = 0; i < 2 * k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
if (i + reserved < k8BitCapacity) {
CHECK_LE(builder.size(), k8BitCapacity);
CHECK_EQ(builder.size(), i + 1);
CHECK(builder.At(i)->SameValue(*object));
} else {
CHECK_GE(builder.size(), k8BitCapacity);
CHECK_EQ(builder.size(), i + reserved + 1);
CHECK(builder.At(i + reserved)->SameValue(*object));
}
}
CHECK_EQ(builder.size(), 2 * k8BitCapacity + reserved);
// Check reserved values represented by the hole.
for (size_t i = 0; i < reserved; i++) {
Handle<Object> empty = builder.At(k8BitCapacity - reserved + i);
CHECK(empty->SameValue(isolate()->heap()->the_hole_value()));
}
// Commmit reserved entries with duplicates and check size does not change.
DCHECK_EQ(reserved + 2 * k8BitCapacity, builder.size());
size_t duplicates_in_idx8_space =
std::min(reserved, k8BitCapacity - reserved);
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
builder.CommitReservedEntry(OperandSize::kByte,
isolate()->factory()->NewNumberFromSize(i));
DCHECK_EQ(reserved + 2 * k8BitCapacity, builder.size());
}
// Check all committed values match expected (holes where
// duplicates_in_idx8_space allocated).
for (size_t i = 0; i < k8BitCapacity - reserved; i++) {
Smi* smi = Smi::FromInt(static_cast<int>(i));
CHECK(Handle<Smi>::cast(builder.At(i))->SameValue(smi));
}
for (size_t i = k8BitCapacity; i < 2 * k8BitCapacity + reserved; i++) {
Smi* smi = Smi::FromInt(static_cast<int>(i - reserved));
CHECK(Handle<Smi>::cast(builder.At(i))->SameValue(smi));
}
for (size_t i = 0; i < reserved; i++) {
size_t index = k8BitCapacity - reserved + i;
CHECK(builder.At(index)->IsTheHole(isolate()));
}
// Now make reservations, and commit them with unique entries.
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kByte);
}
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
Handle<Object> object =
isolate()->factory()->NewNumberFromSize(2 * k8BitCapacity + i);
size_t index = builder.CommitReservedEntry(OperandSize::kByte, object);
CHECK_EQ(static_cast<int>(index), k8BitCapacity - reserved + i);
CHECK(builder.At(static_cast<int>(index))->SameValue(*object));
}
CHECK_EQ(builder.size(), 2 * k8BitCapacity + reserved);
}
}
TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithWideReservations) {
CanonicalHandleScope canonical(isolate());
for (size_t reserved = 1; reserved < k8BitCapacity; reserved *= 3) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
CHECK(builder.At(i)->SameValue(*object));
CHECK_EQ(builder.size(), i + 1);
}
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = 0; i < reserved; i++) {
builder.DiscardReservedEntry(OperandSize::kShort);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.CommitReservedEntry(operand_size, object);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = k8BitCapacity; i < k8BitCapacity + reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.CommitReservedEntry(operand_size, object);
CHECK_EQ(builder.size(), i + 1);
}
}
}
TEST_F(ConstantArrayBuilderTest, ToFixedArray) {
CanonicalHandleScope canonical(isolate());
ConstantArrayBuilder builder(isolate(), zone());
@ -179,6 +72,128 @@ TEST_F(ConstantArrayBuilderTest, ToLargeFixedArray) {
}
}
TEST_F(ConstantArrayBuilderTest, ToLargeFixedArrayWithReservations) {
CanonicalHandleScope canonical(isolate());
ConstantArrayBuilder builder(isolate(), zone());
static const size_t kNumberOfElements = 37373;
for (size_t i = 0; i < kNumberOfElements; i++) {
builder.CommitReservedEntry(builder.CreateReservedEntry(),
Smi::FromInt(static_cast<int>(i)));
}
Handle<FixedArray> constant_array = builder.ToFixedArray();
CHECK_EQ(constant_array->length(), kNumberOfElements);
for (size_t i = 0; i < kNumberOfElements; i++) {
CHECK(constant_array->get(static_cast<int>(i))->SameValue(*builder.At(i)));
}
}
TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) {
CanonicalHandleScope canonical(isolate());
for (size_t reserved = 1; reserved < k8BitCapacity; reserved *= 3) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kByte);
}
for (size_t i = 0; i < 2 * k8BitCapacity; i++) {
builder.CommitReservedEntry(builder.CreateReservedEntry(),
Smi::FromInt(static_cast<int>(i)));
if (i + reserved < k8BitCapacity) {
CHECK_LE(builder.size(), k8BitCapacity);
CHECK_EQ(builder.size(), i + 1);
} else {
CHECK_GE(builder.size(), k8BitCapacity);
CHECK_EQ(builder.size(), i + reserved + 1);
}
}
CHECK_EQ(builder.size(), 2 * k8BitCapacity + reserved);
// Check reserved values represented by the hole.
for (size_t i = 0; i < reserved; i++) {
Handle<Object> empty = builder.At(k8BitCapacity - reserved + i);
CHECK(empty->SameValue(isolate()->heap()->the_hole_value()));
}
// Commit reserved entries with duplicates and check size does not change.
DCHECK_EQ(reserved + 2 * k8BitCapacity, builder.size());
size_t duplicates_in_idx8_space =
std::min(reserved, k8BitCapacity - reserved);
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
builder.CommitReservedEntry(OperandSize::kByte,
Smi::FromInt(static_cast<int>(i)));
DCHECK_EQ(reserved + 2 * k8BitCapacity, builder.size());
}
// Now make reservations, and commit them with unique entries.
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kByte);
}
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
Smi* value = Smi::FromInt(static_cast<int>(2 * k8BitCapacity + i));
size_t index = builder.CommitReservedEntry(OperandSize::kByte, value);
CHECK_EQ(static_cast<int>(index), k8BitCapacity - reserved + i);
}
Handle<FixedArray> constant_array = builder.ToFixedArray();
CHECK_EQ(constant_array->length(), 2 * k8BitCapacity + reserved);
// Check all committed values match expected
for (size_t i = 0; i < k8BitCapacity - reserved; i++) {
Object* value = constant_array->get(static_cast<int>(i));
Smi* smi = Smi::FromInt(static_cast<int>(i));
CHECK(value->SameValue(smi));
}
for (size_t i = k8BitCapacity; i < 2 * k8BitCapacity + reserved; i++) {
Object* value = constant_array->get(static_cast<int>(i));
Smi* smi = Smi::FromInt(static_cast<int>(i - reserved));
CHECK(value->SameValue(smi));
}
}
}
TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithWideReservations) {
CanonicalHandleScope canonical(isolate());
for (size_t reserved = 1; reserved < k8BitCapacity; reserved *= 3) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < k8BitCapacity; i++) {
builder.CommitReservedEntry(builder.CreateReservedEntry(),
Smi::FromInt(static_cast<int>(i)));
CHECK_EQ(builder.size(), i + 1);
}
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = 0; i < reserved; i++) {
builder.DiscardReservedEntry(OperandSize::kShort);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
builder.CommitReservedEntry(operand_size,
Smi::FromInt(static_cast<int>(i)));
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = k8BitCapacity; i < k8BitCapacity + reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
builder.CommitReservedEntry(operand_size,
Smi::FromInt(static_cast<int>(i)));
CHECK_EQ(builder.size(), i + 1);
}
Handle<FixedArray> constant_array = builder.ToFixedArray();
CHECK_EQ(constant_array->length(), k8BitCapacity + reserved);
for (size_t i = 0; i < k8BitCapacity + reserved; i++) {
Object* value = constant_array->get(static_cast<int>(i));
CHECK(value->SameValue(*isolate()->factory()->NewNumberFromSize(i)));
}
}
}
TEST_F(ConstantArrayBuilderTest, GapFilledWhenLowReservationCommitted) {
CanonicalHandleScope canonical(isolate());
ConstantArrayBuilder builder(isolate(), zone());
@ -188,19 +203,21 @@ TEST_F(ConstantArrayBuilderTest, GapFilledWhenLowReservationCommitted) {
CHECK_EQ(builder.size(), 0);
}
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
builder.CommitReservedEntry(builder.CreateReservedEntry(),
Smi::FromInt(static_cast<int>(i)));
CHECK_EQ(builder.size(), i + k8BitCapacity + 1);
}
for (size_t i = 0; i < k8BitCapacity; i++) {
builder.CommitReservedEntry(OperandSize::kByte,
builder.At(i + k8BitCapacity));
Smi::FromInt(static_cast<int>(i)));
CHECK_EQ(builder.size(), 2 * k8BitCapacity);
}
Handle<FixedArray> constant_array = builder.ToFixedArray();
CHECK_EQ(constant_array->length(), 2 * k8BitCapacity);
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> original = builder.At(k8BitCapacity + i);
Handle<Object> duplicate = builder.At(i);
CHECK(original->SameValue(*duplicate));
Object* original = constant_array->get(static_cast<int>(k8BitCapacity + i));
Object* duplicate = constant_array->get(static_cast<int>(i));
CHECK(original->SameValue(duplicate));
Handle<Object> reference = isolate()->factory()->NewNumberFromSize(i);
CHECK(original->SameValue(*reference));
}
@ -269,14 +286,10 @@ TEST_F(ConstantArrayBuilderTest, ReservationsAtAllScales) {
for (int i = 65536; i < 131072; ++i) {
CHECK_EQ(builder.CreateReservedEntry(), OperandSize::kQuad);
}
CHECK_EQ(builder.CommitReservedEntry(OperandSize::kByte,
isolate()->factory()->NewNumber(1)),
0);
CHECK_EQ(builder.CommitReservedEntry(OperandSize::kShort,
isolate()->factory()->NewNumber(2)),
CHECK_EQ(builder.CommitReservedEntry(OperandSize::kByte, Smi::FromInt(1)), 0);
CHECK_EQ(builder.CommitReservedEntry(OperandSize::kShort, Smi::FromInt(2)),
256);
CHECK_EQ(builder.CommitReservedEntry(OperandSize::kQuad,
isolate()->factory()->NewNumber(3)),
CHECK_EQ(builder.CommitReservedEntry(OperandSize::kQuad, Smi::FromInt(3)),
65536);
Handle<FixedArray> constant_array = builder.ToFixedArray();
CHECK_EQ(constant_array->length(), 65537);