[interpreter] Preparation for 32-bit operands.

Extends the constant pool to deal with more slices.

Adds ReadUnalignedUInt32().

BUG=v8:4280,v8:4747
LOG=N

Review URL: https://codereview.chromium.org/1731893003

Cr-Commit-Position: refs/heads/master@{#34319}
This commit is contained in:
oth 2016-02-26 02:14:49 -08:00 committed by Commit bot
parent 06fe8afe7f
commit 1db484f7d8
4 changed files with 159 additions and 131 deletions

View File

@ -11,28 +11,25 @@ namespace v8 {
namespace internal {
namespace interpreter {
ConstantArrayBuilder::ConstantArraySlice::ConstantArraySlice(Zone* zone,
size_t start_index,
size_t capacity)
ConstantArrayBuilder::ConstantArraySlice::ConstantArraySlice(
Zone* zone, size_t start_index, size_t capacity, OperandSize operand_size)
: start_index_(start_index),
capacity_(capacity),
reserved_(0),
operand_size_(operand_size),
constants_(zone) {}
void ConstantArrayBuilder::ConstantArraySlice::Reserve() {
DCHECK_GT(available(), 0u);
reserved_++;
DCHECK_LE(reserved_, capacity() - constants_.size());
}
void ConstantArrayBuilder::ConstantArraySlice::Unreserve() {
DCHECK_GT(reserved_, 0u);
reserved_--;
}
size_t ConstantArrayBuilder::ConstantArraySlice::Allocate(
Handle<Object> object) {
DCHECK_GT(available(), 0u);
@ -42,44 +39,53 @@ size_t ConstantArrayBuilder::ConstantArraySlice::Allocate(
return index + start_index();
}
Handle<Object> ConstantArrayBuilder::ConstantArraySlice::At(
size_t index) const {
DCHECK_GE(index, start_index());
DCHECK_LT(index, start_index() + size());
return constants_[index - start_index()];
}
STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::kMaxCapacity;
STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::kLowCapacity;
STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::k8BitCapacity;
STATIC_CONST_MEMBER_DEFINITION const size_t
ConstantArrayBuilder::k16BitCapacity;
STATIC_CONST_MEMBER_DEFINITION const size_t
ConstantArrayBuilder::k32BitCapacity;
ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone)
: isolate_(isolate),
idx8_slice_(zone, 0, kLowCapacity),
idx16_slice_(zone, kLowCapacity, kHighCapacity),
constants_map_(isolate->heap(), zone) {
STATIC_ASSERT(kMaxCapacity == static_cast<size_t>(kMaxUInt16 + 1));
DCHECK_EQ(idx8_slice_.start_index(), 0u);
DCHECK_EQ(idx8_slice_.capacity(), kLowCapacity);
DCHECK_EQ(idx16_slice_.start_index(), kLowCapacity);
DCHECK_EQ(idx16_slice_.capacity(), kMaxCapacity - kLowCapacity);
: isolate_(isolate), constants_map_(isolate->heap(), zone) {
idx_slice_[0] =
new (zone) ConstantArraySlice(zone, 0, k8BitCapacity, OperandSize::kByte);
idx_slice_[1] = new (zone) ConstantArraySlice(
zone, k8BitCapacity, k16BitCapacity, OperandSize::kShort);
}
size_t ConstantArrayBuilder::size() const {
if (idx16_slice_.size() > 0) {
return idx16_slice_.start_index() + idx16_slice_.size();
} else {
return idx8_slice_.size();
size_t i = arraysize(idx_slice_);
while (i > 0) {
ConstantArraySlice* slice = idx_slice_[--i];
if (slice->size() > 0) {
return slice->start_index() + slice->size();
}
}
return idx_slice_[0]->size();
}
const ConstantArrayBuilder::ConstantArraySlice*
ConstantArrayBuilder::IndexToSlice(size_t index) const {
for (const ConstantArraySlice* slice : idx_slice_) {
if (index <= slice->max_index()) {
return slice;
}
}
UNREACHABLE();
return nullptr;
}
Handle<Object> ConstantArrayBuilder::At(size_t index) const {
if (index >= idx16_slice_.start_index()) {
return idx16_slice_.At(index);
} else if (index < idx8_slice_.size()) {
return idx8_slice_.At(index);
const ConstantArraySlice* slice = IndexToSlice(index);
if (index < slice->start_index() + slice->size()) {
return slice->At(index);
} else {
return isolate_->factory()->the_hole_value();
}
@ -88,49 +94,78 @@ Handle<Object> ConstantArrayBuilder::At(size_t index) const {
Handle<FixedArray> ConstantArrayBuilder::ToFixedArray() {
Handle<FixedArray> fixed_array = isolate_->factory()->NewFixedArray(
static_cast<int>(size()), PretenureFlag::TENURED);
for (int i = 0; i < fixed_array->length(); i++) {
fixed_array->set(i, *At(static_cast<size_t>(i)));
int array_index = 0;
for (const ConstantArraySlice* slice : idx_slice_) {
if (array_index == fixed_array->length()) {
break;
}
// Copy objects from slice into array.
for (size_t i = 0; i < slice->size(); ++i) {
fixed_array->set(array_index++, *slice->At(slice->start_index() + i));
}
// Insert holes where reservations led to unused slots.
size_t padding =
std::min(static_cast<size_t>(fixed_array->length() - array_index),
slice->capacity() - slice->size());
for (size_t i = slice->start_index() + slice->size();
i < slice->start_index() + padding; ++i) {
fixed_array->set(array_index++, *isolate_->factory()->the_hole_value());
}
}
DCHECK_EQ(array_index, fixed_array->length());
constants_map()->Clear();
return fixed_array;
}
size_t ConstantArrayBuilder::Insert(Handle<Object> object) {
index_t* entry = constants_map()->Find(object);
return (entry == nullptr) ? AllocateEntry(object) : *entry;
}
ConstantArrayBuilder::index_t ConstantArrayBuilder::AllocateEntry(
Handle<Object> object) {
DCHECK(!object->IsOddball());
size_t index;
index_t* entry = constants_map()->Get(object);
if (idx8_slice_.available() > 0) {
index = idx8_slice_.Allocate(object);
} else {
index = idx16_slice_.Allocate(object);
for (size_t i = 0; i < arraysize(idx_slice_); ++i) {
if (idx_slice_[i]->available() > 0) {
size_t index = idx_slice_[i]->Allocate(object);
*entry = static_cast<index_t>(index);
return *entry;
break;
}
}
CHECK_LT(index, kMaxCapacity);
*entry = static_cast<index_t>(index);
return *entry;
UNREACHABLE();
return kMaxUInt32;
}
OperandSize ConstantArrayBuilder::CreateReservedEntry() {
if (idx8_slice_.available() > 0) {
idx8_slice_.Reserve();
return OperandSize::kByte;
} else if (idx16_slice_.available() > 0) {
idx16_slice_.Reserve();
return OperandSize::kShort;
} else {
UNREACHABLE();
return OperandSize::kNone;
for (size_t i = 0; i < arraysize(idx_slice_); ++i) {
if (idx_slice_[i]->available() > 0) {
idx_slice_[i]->Reserve();
return idx_slice_[i]->operand_size();
}
}
UNREACHABLE();
return OperandSize::kNone;
}
ConstantArrayBuilder::ConstantArraySlice*
ConstantArrayBuilder::OperandSizeToSlice(OperandSize operand_size) const {
ConstantArraySlice* slice = nullptr;
switch (operand_size) {
case OperandSize::kNone:
UNREACHABLE();
break;
case OperandSize::kByte:
slice = idx_slice_[0];
break;
case OperandSize::kShort:
slice = idx_slice_[1];
break;
}
DCHECK(slice->operand_size() == operand_size);
return slice;
}
size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size,
Handle<Object> object) {
@ -140,33 +175,20 @@ size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size,
if (nullptr == entry) {
index = AllocateEntry(object);
} else {
if (operand_size == OperandSize::kByte &&
*entry >= idx8_slice_.capacity()) {
// The object is already in the constant array, but has an index
// outside the range of an idx8 operand so we need to create a
// duplicate entry in the idx8 operand range to satisfy the
// commitment.
*entry = static_cast<index_t>(idx8_slice_.Allocate(object));
ConstantArraySlice* slice = OperandSizeToSlice(operand_size);
if (*entry > slice->max_index()) {
// 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.
*entry = static_cast<index_t>(slice->Allocate(object));
}
index = *entry;
}
DCHECK(operand_size == OperandSize::kShort || index < idx8_slice_.capacity());
DCHECK_LT(index, kMaxCapacity);
return index;
}
void ConstantArrayBuilder::DiscardReservedEntry(OperandSize operand_size) {
switch (operand_size) {
case OperandSize::kByte:
idx8_slice_.Unreserve();
return;
case OperandSize::kShort:
idx16_slice_.Unreserve();
return;
default:
UNREACHABLE();
}
OperandSizeToSlice(operand_size)->Unreserve();
}
} // namespace interpreter

View File

@ -23,13 +23,14 @@ namespace interpreter {
class ConstantArrayBuilder final BASE_EMBEDDED {
public:
// Capacity of the 8-bit operand slice.
static const size_t kLowCapacity = 1u << kBitsPerByte;
// Capacity of the combined 8-bit and 16-bit operand slices.
static const size_t kMaxCapacity = 1u << (2 * kBitsPerByte);
static const size_t k8BitCapacity = 1u << kBitsPerByte;
// Capacity of the 16-bit operand slice.
static const size_t kHighCapacity = kMaxCapacity - kLowCapacity;
static const size_t k16BitCapacity = (1u << 2 * kBitsPerByte) - k8BitCapacity;
// Capacity of the 32-bit operand slice.
static const size_t k32BitCapacity =
kMaxUInt32 - k16BitCapacity - k8BitCapacity + 1;
ConstantArrayBuilder(Isolate* isolate, Zone* zone);
@ -60,12 +61,13 @@ class ConstantArrayBuilder final BASE_EMBEDDED {
void DiscardReservedEntry(OperandSize operand_size);
private:
typedef uint16_t index_t;
typedef uint32_t index_t;
index_t AllocateEntry(Handle<Object> object);
struct ConstantArraySlice final {
ConstantArraySlice(Zone* zone, size_t start_index, size_t capacity);
struct ConstantArraySlice final : public ZoneObject {
ConstantArraySlice(Zone* zone, size_t start_index, size_t capacity,
OperandSize operand_size);
void Reserve();
void Unreserve();
size_t Allocate(Handle<Object> object);
@ -76,21 +78,26 @@ class ConstantArrayBuilder final BASE_EMBEDDED {
inline size_t capacity() const { return capacity_; }
inline size_t size() const { return constants_.size(); }
inline size_t start_index() const { return start_index_; }
inline size_t max_index() const { return start_index_ + capacity() - 1; }
inline OperandSize operand_size() const { return operand_size_; }
private:
const size_t start_index_;
const size_t capacity_;
size_t reserved_;
OperandSize operand_size_;
ZoneVector<Handle<Object>> constants_;
DISALLOW_COPY_AND_ASSIGN(ConstantArraySlice);
};
const ConstantArraySlice* IndexToSlice(size_t index) const;
ConstantArraySlice* OperandSizeToSlice(OperandSize operand_size) const;
IdentityMap<index_t>* constants_map() { return &constants_map_; }
Isolate* isolate_;
ConstantArraySlice idx8_slice_;
ConstantArraySlice idx16_slice_;
ConstantArraySlice* idx_slice_[2];
IdentityMap<index_t> constants_map_;
};

View File

@ -1752,21 +1752,22 @@ static inline double ReadDoubleValue(const void* p) {
return ReadUnalignedValue<double>(p);
}
static inline void WriteDoubleValue(void* p, double value) {
WriteUnalignedValue(p, value);
}
static inline uint16_t ReadUnalignedUInt16(const void* p) {
return ReadUnalignedValue<uint16_t>(p);
}
static inline void WriteUnalignedUInt16(void* p, uint16_t value) {
WriteUnalignedValue(p, value);
}
static inline uint32_t ReadUnalignedUInt32(const void* p) {
return ReadUnalignedValue<uint32_t>(p);
}
static inline void WriteUnalignedUInt32(void* p, uint32_t value) {
WriteUnalignedValue(p, value);
}

View File

@ -19,79 +19,77 @@ class ConstantArrayBuilderTest : public TestWithIsolateAndZone {
ConstantArrayBuilderTest() {}
~ConstantArrayBuilderTest() override {}
static const size_t kLowCapacity = ConstantArrayBuilder::kLowCapacity;
static const size_t kMaxCapacity = ConstantArrayBuilder::kMaxCapacity;
static const size_t k8BitCapacity = ConstantArrayBuilder::k8BitCapacity;
static const size_t k16BitCapacity = ConstantArrayBuilder::k16BitCapacity;
};
STATIC_CONST_MEMBER_DEFINITION const size_t
ConstantArrayBuilderTest::kMaxCapacity;
ConstantArrayBuilderTest::k16BitCapacity;
STATIC_CONST_MEMBER_DEFINITION const size_t
ConstantArrayBuilderTest::kLowCapacity;
ConstantArrayBuilderTest::k8BitCapacity;
TEST_F(ConstantArrayBuilderTest, AllocateAllEntries) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < kMaxCapacity; i++) {
for (size_t i = 0; i < k16BitCapacity; i++) {
builder.Insert(handle(Smi::FromInt(static_cast<int>(i)), isolate()));
}
CHECK_EQ(builder.size(), kMaxCapacity);
for (size_t i = 0; i < kMaxCapacity; i++) {
CHECK_EQ(builder.size(), k16BitCapacity);
for (size_t i = 0; i < k16BitCapacity; i++) {
CHECK_EQ(Handle<Smi>::cast(builder.At(i))->value(), i);
}
}
TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) {
for (size_t reserved = 1; reserved < kLowCapacity; reserved *= 3) {
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 * kLowCapacity; i++) {
for (size_t i = 0; i < 2 * k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
if (i + reserved < kLowCapacity) {
CHECK_LE(builder.size(), kLowCapacity);
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(), kLowCapacity);
CHECK_GE(builder.size(), k8BitCapacity);
CHECK_EQ(builder.size(), i + reserved + 1);
CHECK(builder.At(i + reserved)->SameValue(*object));
}
}
CHECK_EQ(builder.size(), 2 * kLowCapacity + reserved);
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(kLowCapacity - 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 * kLowCapacity, builder.size());
DCHECK_EQ(reserved + 2 * k8BitCapacity, builder.size());
size_t duplicates_in_idx8_space =
std::min(reserved, kLowCapacity - reserved);
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 * kLowCapacity, builder.size());
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 < kLowCapacity - reserved; i++) {
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 = kLowCapacity; i < 2 * kLowCapacity + reserved; i++) {
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 = kLowCapacity - reserved + i;
size_t index = k8BitCapacity - reserved + i;
CHECK(builder.At(index)->IsTheHole());
}
@ -102,20 +100,20 @@ TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx8Reservations) {
}
for (size_t i = 0; i < duplicates_in_idx8_space; i++) {
Handle<Object> object =
isolate()->factory()->NewNumberFromSize(2 * kLowCapacity + i);
isolate()->factory()->NewNumberFromSize(2 * k8BitCapacity + i);
size_t index = builder.CommitReservedEntry(OperandSize::kByte, object);
CHECK_EQ(static_cast<int>(index), kLowCapacity - reserved + i);
CHECK_EQ(static_cast<int>(index), k8BitCapacity - reserved + i);
CHECK(builder.At(static_cast<int>(index))->SameValue(*object));
}
CHECK_EQ(builder.size(), 2 * kLowCapacity + reserved);
CHECK_EQ(builder.size(), 2 * k8BitCapacity + reserved);
}
}
TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx16Reservations) {
for (size_t reserved = 1; reserved < kLowCapacity; reserved *= 3) {
for (size_t reserved = 1; reserved < k8BitCapacity; reserved *= 3) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
CHECK(builder.At(i)->SameValue(*object));
@ -124,20 +122,20 @@ TEST_F(ConstantArrayBuilderTest, AllocateEntriesWithIdx16Reservations) {
for (size_t i = 0; i < reserved; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(operand_size == OperandSize::kShort);
CHECK_EQ(builder.size(), kLowCapacity);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = 0; i < reserved; i++) {
builder.DiscardReservedEntry(OperandSize::kShort);
CHECK_EQ(builder.size(), kLowCapacity);
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(), kLowCapacity);
CHECK_EQ(builder.size(), k8BitCapacity);
}
for (size_t i = kLowCapacity; i < kLowCapacity + reserved; i++) {
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);
@ -166,23 +164,23 @@ TEST_F(ConstantArrayBuilderTest, ToFixedArray) {
TEST_F(ConstantArrayBuilderTest, GapFilledWhenLowReservationCommitted) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(OperandSize::kByte == operand_size);
CHECK_EQ(builder.size(), 0);
}
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
CHECK_EQ(builder.size(), i + kLowCapacity + 1);
CHECK_EQ(builder.size(), i + k8BitCapacity + 1);
}
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
builder.CommitReservedEntry(OperandSize::kByte,
builder.At(i + kLowCapacity));
CHECK_EQ(builder.size(), 2 * kLowCapacity);
builder.At(i + k8BitCapacity));
CHECK_EQ(builder.size(), 2 * k8BitCapacity);
}
for (size_t i = 0; i < kLowCapacity; i++) {
Handle<Object> original = builder.At(kLowCapacity + i);
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));
Handle<Object> reference = isolate()->factory()->NewNumberFromSize(i);
@ -193,24 +191,24 @@ TEST_F(ConstantArrayBuilderTest, GapFilledWhenLowReservationCommitted) {
TEST_F(ConstantArrayBuilderTest, GapNotFilledWhenLowReservationDiscarded) {
ConstantArrayBuilder builder(isolate(), zone());
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
OperandSize operand_size = builder.CreateReservedEntry();
CHECK(OperandSize::kByte == operand_size);
CHECK_EQ(builder.size(), 0);
}
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> object = isolate()->factory()->NewNumberFromSize(i);
builder.Insert(object);
CHECK_EQ(builder.size(), i + kLowCapacity + 1);
CHECK_EQ(builder.size(), i + k8BitCapacity + 1);
}
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
builder.DiscardReservedEntry(OperandSize::kByte);
builder.Insert(builder.At(i + kLowCapacity));
CHECK_EQ(builder.size(), 2 * kLowCapacity);
builder.Insert(builder.At(i + k8BitCapacity));
CHECK_EQ(builder.size(), 2 * k8BitCapacity);
}
for (size_t i = 0; i < kLowCapacity; i++) {
for (size_t i = 0; i < k8BitCapacity; i++) {
Handle<Object> reference = isolate()->factory()->NewNumberFromSize(i);
Handle<Object> original = builder.At(kLowCapacity + i);
Handle<Object> original = builder.At(k8BitCapacity + i);
CHECK(original->SameValue(*reference));
Handle<Object> duplicate = builder.At(i);
CHECK(duplicate->SameValue(*isolate()->factory()->the_hole_value()));