[runtime] Change backing store of LayoutDescriptor to ByteArray.

BUG=v8:6277

Change-Id: I80314e6c5146e1f5021d07081b9eda3da5da6834
Reviewed-on: https://chromium-review.googlesource.com/518047
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45632}
This commit is contained in:
Ulan Degenbaev 2017-05-31 19:06:28 +06:00 committed by Commit Bot
parent 0f11aa626c
commit d8a42e4c09
8 changed files with 68 additions and 52 deletions

View File

@ -153,6 +153,7 @@ const int kShortSize = sizeof(short); // NOLINT
const int kIntSize = sizeof(int); const int kIntSize = sizeof(int);
const int kInt32Size = sizeof(int32_t); const int kInt32Size = sizeof(int32_t);
const int kInt64Size = sizeof(int64_t); const int kInt64Size = sizeof(int64_t);
const int kUInt32Size = sizeof(uint32_t);
const int kSizetSize = sizeof(size_t); const int kSizetSize = sizeof(size_t);
const int kFloatSize = sizeof(float); const int kFloatSize = sizeof(float);
const int kDoubleSize = sizeof(double); const int kDoubleSize = sizeof(double);

View File

@ -20,9 +20,11 @@ Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
// The whole bit vector fits into a smi. // The whole bit vector fits into a smi.
return handle(LayoutDescriptor::FromSmi(Smi::kZero), isolate); return handle(LayoutDescriptor::FromSmi(Smi::kZero), isolate);
} }
length = GetSlowModeBackingStoreLength(length); int backing_store_length = GetSlowModeBackingStoreLength(length);
return Handle<LayoutDescriptor>::cast(isolate->factory()->NewFixedTypedArray( Handle<LayoutDescriptor> result = Handle<LayoutDescriptor>::cast(
length, kExternalUint32Array, true)); isolate->factory()->NewByteArray(backing_store_length));
memset(result->GetDataStartAddress(), 0, result->DataSize());
return result;
} }
@ -47,11 +49,11 @@ bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index,
return false; return false;
} }
*layout_word_index = field_index / kNumberOfBits; *layout_word_index = field_index / kBitsPerLayoutWord;
CHECK((!IsSmi() && (*layout_word_index < length())) || CHECK((!IsSmi() && (*layout_word_index < length())) ||
(IsSmi() && (*layout_word_index < 1))); (IsSmi() && (*layout_word_index < 1)));
*layout_bit_index = field_index % kNumberOfBits; *layout_bit_index = field_index % kBitsPerLayoutWord;
return true; return true;
} }
@ -72,13 +74,13 @@ LayoutDescriptor* LayoutDescriptor::SetTagged(int field_index, bool tagged) {
uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index; uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
if (IsSlowLayout()) { if (IsSlowLayout()) {
uint32_t value = get_scalar(layout_word_index); uint32_t value = get_layout_word(layout_word_index);
if (tagged) { if (tagged) {
value &= ~layout_mask; value &= ~layout_mask;
} else { } else {
value |= layout_mask; value |= layout_mask;
} }
set(layout_word_index, value); set_layout_word(layout_word_index, value);
return this; return this;
} else { } else {
uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value()); uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
@ -105,7 +107,7 @@ bool LayoutDescriptor::IsTagged(int field_index) {
uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index; uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
if (IsSlowLayout()) { if (IsSlowLayout()) {
uint32_t value = get_scalar(layout_word_index); uint32_t value = get_layout_word(layout_word_index);
return (value & layout_mask) == 0; return (value & layout_mask) == 0;
} else { } else {
uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value()); uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
@ -128,7 +130,7 @@ bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
int LayoutDescriptor::capacity() { int LayoutDescriptor::capacity() {
return IsSlowLayout() ? (length() * kNumberOfBits) : kSmiValueSize; return IsSlowLayout() ? (length() * kBitsPerByte) : kSmiValueSize;
} }
@ -147,20 +149,12 @@ LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* object) {
return LayoutDescriptor::cast(object); return LayoutDescriptor::cast(object);
} }
int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) { int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
length = (length + kNumberOfBits - 1) / kNumberOfBits;
DCHECK_LT(0, length); DCHECK_LT(0, length);
// We allocate kPointerSize rounded blocks of memory anyway so we increase
if (SmiValuesAre32Bits() && (length & 1)) { // the length of allocated array to utilize that "lost" space which could
// On 64-bit systems if the length is odd then the half-word space would be // also help to avoid layout descriptor reallocations.
// lost anyway (due to alignment and the fact that we are allocating return RoundUp(length, kBitsPerByte * kPointerSize) / kBitsPerByte;
// uint32-typed array), so we increase the length of allocated array
// to utilize that "lost" space which could also help to avoid layout
// descriptor reallocations.
++length;
}
return length;
} }

View File

@ -107,14 +107,15 @@ Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
DCHECK(new_layout_descriptor->IsSlowLayout()); DCHECK(new_layout_descriptor->IsSlowLayout());
if (layout_descriptor->IsSlowLayout()) { if (layout_descriptor->IsSlowLayout()) {
memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(), memcpy(new_layout_descriptor->GetDataStartAddress(),
layout_descriptor->GetDataStartAddress(),
layout_descriptor->DataSize()); layout_descriptor->DataSize());
return new_layout_descriptor; return new_layout_descriptor;
} else { } else {
// Fast layout. // Fast layout.
uint32_t value = uint32_t value =
static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value()); static_cast<uint32_t>(Smi::cast(*layout_descriptor)->value());
new_layout_descriptor->set(0, value); new_layout_descriptor->set_layout_word(0, value);
return new_layout_descriptor; return new_layout_descriptor;
} }
} }
@ -139,7 +140,7 @@ bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index; uint32_t layout_mask = static_cast<uint32_t>(1) << layout_bit_index;
uint32_t value = IsSlowLayout() uint32_t value = IsSlowLayout()
? get_scalar(layout_word_index) ? get_layout_word(layout_word_index)
: static_cast<uint32_t>(Smi::cast(this)->value()); : static_cast<uint32_t>(Smi::cast(this)->value());
bool is_tagged = (value & layout_mask) == 0; bool is_tagged = (value & layout_mask) == 0;
@ -147,21 +148,21 @@ bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length,
value = value & ~(layout_mask - 1); // Clear bits we are not interested in. value = value & ~(layout_mask - 1); // Clear bits we are not interested in.
int sequence_length = CountTrailingZeros32(value) - layout_bit_index; int sequence_length = CountTrailingZeros32(value) - layout_bit_index;
if (layout_bit_index + sequence_length == kNumberOfBits) { if (layout_bit_index + sequence_length == kBitsPerLayoutWord) {
// This is a contiguous sequence till the end of current word, proceed // This is a contiguous sequence till the end of current word, proceed
// counting in the subsequent words. // counting in the subsequent words.
if (IsSlowLayout()) { if (IsSlowLayout()) {
int len = length();
++layout_word_index; ++layout_word_index;
for (; layout_word_index < len; layout_word_index++) { int num_words = number_of_layout_words();
value = get_scalar(layout_word_index); for (; layout_word_index < num_words; layout_word_index++) {
value = get_layout_word(layout_word_index);
bool cur_is_tagged = (value & 1) == 0; bool cur_is_tagged = (value & 1) == 0;
if (cur_is_tagged != is_tagged) break; if (cur_is_tagged != is_tagged) break;
if (!is_tagged) value = ~value; // Count set bits instead. if (!is_tagged) value = ~value; // Count set bits instead.
int cur_sequence_length = CountTrailingZeros32(value); int cur_sequence_length = CountTrailingZeros32(value);
sequence_length += cur_sequence_length; sequence_length += cur_sequence_length;
if (sequence_length >= max_sequence_length) break; if (sequence_length >= max_sequence_length) break;
if (cur_sequence_length != kNumberOfBits) break; if (cur_sequence_length != kBitsPerLayoutWord) break;
} }
} }
if (is_tagged && (field_index + sequence_length == capacity())) { if (is_tagged && (field_index + sequence_length == capacity())) {
@ -241,14 +242,15 @@ LayoutDescriptor* LayoutDescriptor::Trim(Heap* heap, Map* map,
DCHECK_LT(kSmiValueSize, layout_descriptor_length); DCHECK_LT(kSmiValueSize, layout_descriptor_length);
// Trim, clean and reinitialize this slow-mode layout descriptor. // Trim, clean and reinitialize this slow-mode layout descriptor.
int array_length = GetSlowModeBackingStoreLength(layout_descriptor_length); int new_backing_store_length =
int current_length = length(); GetSlowModeBackingStoreLength(layout_descriptor_length);
if (current_length != array_length) { int backing_store_length = length();
DCHECK_LT(array_length, current_length); if (new_backing_store_length != backing_store_length) {
int delta = current_length - array_length; DCHECK_LT(new_backing_store_length, backing_store_length);
int delta = backing_store_length - new_backing_store_length;
heap->RightTrimFixedArray(this, delta); heap->RightTrimFixedArray(this, delta);
} }
memset(DataPtr(), 0, DataSize()); memset(GetDataStartAddress(), 0, DataSize());
LayoutDescriptor* layout_descriptor = LayoutDescriptor* layout_descriptor =
Initialize(this, map, descriptors, num_descriptors); Initialize(this, map, descriptors, num_descriptors);
DCHECK_EQ(this, layout_descriptor); DCHECK_EQ(this, layout_descriptor);

View File

@ -21,8 +21,10 @@ namespace internal {
// Otherwise the field is considered tagged. If the queried bit lays "outside" // Otherwise the field is considered tagged. If the queried bit lays "outside"
// of the descriptor then the field is also considered tagged. // of the descriptor then the field is also considered tagged.
// Once a layout descriptor is created it is allowed only to append properties // Once a layout descriptor is created it is allowed only to append properties
// to it. // to it. GC uses layout descriptors to iterate objects. Avoid heap pointers
class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> { // in a layout descriptor because they can lead to data races in GC when
// GC moves objects in parallel.
class LayoutDescriptor : public ByteArray {
public: public:
V8_INLINE bool IsTagged(int field_index); V8_INLINE bool IsTagged(int field_index);
@ -94,7 +96,10 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
LayoutDescriptor* SetTaggedForTesting(int field_index, bool tagged); LayoutDescriptor* SetTaggedForTesting(int field_index, bool tagged);
private: private:
static const int kNumberOfBits = 32; static const int kBitsPerLayoutWord = 32;
int number_of_layout_words() { return length() / kUInt32Size; }
uint32_t get_layout_word(int index) const { return get_uint32(index); }
void set_layout_word(int index, uint32_t value) { set_uint32(index, value); }
V8_INLINE static Handle<LayoutDescriptor> New(Isolate* isolate, int length); V8_INLINE static Handle<LayoutDescriptor> New(Isolate* isolate, int length);
V8_INLINE static LayoutDescriptor* FromSmi(Smi* smi); V8_INLINE static LayoutDescriptor* FromSmi(Smi* smi);

View File

@ -310,9 +310,7 @@ bool HeapObject::IsArrayList() const { return IsFixedArray(); }
bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArray(); } bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArray(); }
bool Object::IsLayoutDescriptor() const { bool Object::IsLayoutDescriptor() const { return IsSmi() || IsByteArray(); }
return IsSmi() || IsFixedTypedArrayBase();
}
bool HeapObject::IsFeedbackVector() const { bool HeapObject::IsFeedbackVector() const {
return map() == GetHeap()->feedback_vector_map(); return map() == GetHeap()->feedback_vector_map();
@ -3694,7 +3692,7 @@ void StringCharacterStream::VisitTwoByteString(
int ByteArray::Size() { return RoundUp(length() + kHeaderSize, kPointerSize); } int ByteArray::Size() { return RoundUp(length() + kHeaderSize, kPointerSize); }
byte ByteArray::get(int index) { byte ByteArray::get(int index) const {
DCHECK(index >= 0 && index < this->length()); DCHECK(index >= 0 && index < this->length());
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
} }
@ -3718,7 +3716,7 @@ void ByteArray::copy_out(int index, byte* buffer, int length) {
memcpy(buffer, src_addr, length); memcpy(buffer, src_addr, length);
} }
int ByteArray::get_int(int index) { int ByteArray::get_int(int index) const {
DCHECK(index >= 0 && index < this->length() / kIntSize); DCHECK(index >= 0 && index < this->length() / kIntSize);
return READ_INT_FIELD(this, kHeaderSize + index * kIntSize); return READ_INT_FIELD(this, kHeaderSize + index * kIntSize);
} }
@ -3728,11 +3726,22 @@ void ByteArray::set_int(int index, int value) {
WRITE_INT_FIELD(this, kHeaderSize + index * kIntSize, value); WRITE_INT_FIELD(this, kHeaderSize + index * kIntSize, value);
} }
uint32_t ByteArray::get_uint32(int index) const {
DCHECK(index >= 0 && index < this->length() / kUInt32Size);
return READ_UINT32_FIELD(this, kHeaderSize + index * kUInt32Size);
}
void ByteArray::set_uint32(int index, uint32_t value) {
DCHECK(index >= 0 && index < this->length() / kUInt32Size);
WRITE_UINT32_FIELD(this, kHeaderSize + index * kUInt32Size, value);
}
ByteArray* ByteArray::FromDataStartAddress(Address address) { ByteArray* ByteArray::FromDataStartAddress(Address address) {
DCHECK_TAG_ALIGNED(address); DCHECK_TAG_ALIGNED(address);
return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag); return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag);
} }
int ByteArray::DataSize() const { return RoundUp(length(), kPointerSize); }
int ByteArray::ByteArraySize() { return SizeFor(this->length()); } int ByteArray::ByteArraySize() { return SizeFor(this->length()); }

View File

@ -1526,10 +1526,10 @@ void LayoutDescriptor::Print(std::ostream& os) { // NOLINT
os << "<uninitialized>"; os << "<uninitialized>";
} else { } else {
os << "slow"; os << "slow";
int len = length(); int num_words = number_of_layout_words();
for (int i = 0; i < len; i++) { for (int i = 0; i < num_words; i++) {
if (i > 0) os << " |"; if (i > 0) os << " |";
PrintBitMask(os, get_scalar(i)); PrintBitMask(os, get_layout_word(i));
} }
} }
os << "\n"; os << "\n";

View File

@ -3187,7 +3187,7 @@ class ByteArray: public FixedArrayBase {
inline int Size(); inline int Size();
// Setter and getter. // Setter and getter.
inline byte get(int index); inline byte get(int index) const;
inline void set(int index, byte value); inline void set(int index, byte value);
// Copy in / copy out whole byte slices. // Copy in / copy out whole byte slices.
@ -3195,9 +3195,12 @@ class ByteArray: public FixedArrayBase {
inline void copy_in(int index, const byte* buffer, int length); inline void copy_in(int index, const byte* buffer, int length);
// Treat contents as an int array. // Treat contents as an int array.
inline int get_int(int index); inline int get_int(int index) const;
inline void set_int(int index, int value); inline void set_int(int index, int value);
inline uint32_t get_uint32(int index) const;
inline void set_uint32(int index, uint32_t value);
static int SizeFor(int length) { static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length); return OBJECT_POINTER_ALIGN(kHeaderSize + length);
} }
@ -3214,6 +3217,8 @@ class ByteArray: public FixedArrayBase {
// Returns data start address. // Returns data start address.
inline Address GetDataStartAddress(); inline Address GetDataStartAddress();
inline int DataSize() const;
// Returns a pointer to the ByteArray object for a given data start address. // Returns a pointer to the ByteArray object for a given data start address.
static inline ByteArray* FromDataStartAddress(Address address); static inline ByteArray* FromDataStartAddress(Address address);

View File

@ -602,7 +602,7 @@ TEST(LayoutDescriptorCreateNewSlow) {
LayoutDescriptor* layout_desc = *layout_descriptor; LayoutDescriptor* layout_desc = *layout_descriptor;
CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc)); CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc)); CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
CHECK(layout_descriptor->IsFixedTypedArrayBase()); CHECK(layout_desc->IsSlowLayout());
// Now make it look like a forwarding pointer to layout_descriptor_copy. // Now make it look like a forwarding pointer to layout_descriptor_copy.
MapWord map_word = layout_desc->map_word(); MapWord map_word = layout_desc->map_word();
CHECK(!map_word.IsForwardingAddress()); CHECK(!map_word.IsForwardingAddress());
@ -982,7 +982,7 @@ TEST(DescriptorArrayTrimming) {
CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true)); CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
CHECK(map->layout_descriptor()->IsSlowLayout()); CHECK(map->layout_descriptor()->IsSlowLayout());
CHECK(map->owns_descriptors()); CHECK(map->owns_descriptors());
CHECK_EQ(2, map->layout_descriptor()->length()); CHECK_EQ(8, map->layout_descriptor()->length());
{ {
// Add transitions to double fields. // Add transitions to double fields.
@ -1002,7 +1002,7 @@ TEST(DescriptorArrayTrimming) {
CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor()); CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor());
} }
CHECK(map->layout_descriptor()->IsSlowLayout()); CHECK(map->layout_descriptor()->IsSlowLayout());
CHECK_EQ(4, map->layout_descriptor()->length()); CHECK_EQ(16, map->layout_descriptor()->length());
// The unused tail of the layout descriptor is now "durty" because of sharing. // The unused tail of the layout descriptor is now "durty" because of sharing.
CHECK(map->layout_descriptor()->IsConsistentWithMap(*map)); CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
@ -1022,7 +1022,7 @@ TEST(DescriptorArrayTrimming) {
CHECK_EQ(map->NumberOfOwnDescriptors(), CHECK_EQ(map->NumberOfOwnDescriptors(),
map->instance_descriptors()->number_of_descriptors()); map->instance_descriptors()->number_of_descriptors());
CHECK(map->layout_descriptor()->IsSlowLayout()); CHECK(map->layout_descriptor()->IsSlowLayout());
CHECK_EQ(2, map->layout_descriptor()->length()); CHECK_EQ(8, map->layout_descriptor()->length());
{ {
// Add transitions to tagged fields. // Add transitions to tagged fields.