[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 kInt32Size = sizeof(int32_t);
const int kInt64Size = sizeof(int64_t);
const int kUInt32Size = sizeof(uint32_t);
const int kSizetSize = sizeof(size_t);
const int kFloatSize = sizeof(float);
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.
return handle(LayoutDescriptor::FromSmi(Smi::kZero), isolate);
}
length = GetSlowModeBackingStoreLength(length);
return Handle<LayoutDescriptor>::cast(isolate->factory()->NewFixedTypedArray(
length, kExternalUint32Array, true));
int backing_store_length = GetSlowModeBackingStoreLength(length);
Handle<LayoutDescriptor> result = Handle<LayoutDescriptor>::cast(
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;
}
*layout_word_index = field_index / kNumberOfBits;
*layout_word_index = field_index / kBitsPerLayoutWord;
CHECK((!IsSmi() && (*layout_word_index < length())) ||
(IsSmi() && (*layout_word_index < 1)));
*layout_bit_index = field_index % kNumberOfBits;
*layout_bit_index = field_index % kBitsPerLayoutWord;
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;
if (IsSlowLayout()) {
uint32_t value = get_scalar(layout_word_index);
uint32_t value = get_layout_word(layout_word_index);
if (tagged) {
value &= ~layout_mask;
} else {
value |= layout_mask;
}
set(layout_word_index, value);
set_layout_word(layout_word_index, value);
return this;
} else {
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;
if (IsSlowLayout()) {
uint32_t value = get_scalar(layout_word_index);
uint32_t value = get_layout_word(layout_word_index);
return (value & layout_mask) == 0;
} else {
uint32_t value = static_cast<uint32_t>(Smi::cast(this)->value());
@ -128,7 +130,7 @@ bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); }
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);
}
int LayoutDescriptor::GetSlowModeBackingStoreLength(int length) {
length = (length + kNumberOfBits - 1) / kNumberOfBits;
DCHECK_LT(0, length);
if (SmiValuesAre32Bits() && (length & 1)) {
// On 64-bit systems if the length is odd then the half-word space would be
// lost anyway (due to alignment and the fact that we are allocating
// 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;
// We allocate kPointerSize rounded blocks of memory anyway so we increase
// the length of allocated array to utilize that "lost" space which could
// also help to avoid layout descriptor reallocations.
return RoundUp(length, kBitsPerByte * kPointerSize) / kBitsPerByte;
}

View File

@ -107,14 +107,15 @@ Handle<LayoutDescriptor> LayoutDescriptor::EnsureCapacity(
DCHECK(new_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());
return new_layout_descriptor;
} else {
// Fast layout.
uint32_t 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;
}
}
@ -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 value = IsSlowLayout()
? get_scalar(layout_word_index)
? get_layout_word(layout_word_index)
: static_cast<uint32_t>(Smi::cast(this)->value());
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.
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
// counting in the subsequent words.
if (IsSlowLayout()) {
int len = length();
++layout_word_index;
for (; layout_word_index < len; layout_word_index++) {
value = get_scalar(layout_word_index);
int num_words = number_of_layout_words();
for (; layout_word_index < num_words; layout_word_index++) {
value = get_layout_word(layout_word_index);
bool cur_is_tagged = (value & 1) == 0;
if (cur_is_tagged != is_tagged) break;
if (!is_tagged) value = ~value; // Count set bits instead.
int cur_sequence_length = CountTrailingZeros32(value);
sequence_length += cur_sequence_length;
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())) {
@ -241,14 +242,15 @@ LayoutDescriptor* LayoutDescriptor::Trim(Heap* heap, Map* map,
DCHECK_LT(kSmiValueSize, layout_descriptor_length);
// Trim, clean and reinitialize this slow-mode layout descriptor.
int array_length = GetSlowModeBackingStoreLength(layout_descriptor_length);
int current_length = length();
if (current_length != array_length) {
DCHECK_LT(array_length, current_length);
int delta = current_length - array_length;
int new_backing_store_length =
GetSlowModeBackingStoreLength(layout_descriptor_length);
int backing_store_length = length();
if (new_backing_store_length != backing_store_length) {
DCHECK_LT(new_backing_store_length, backing_store_length);
int delta = backing_store_length - new_backing_store_length;
heap->RightTrimFixedArray(this, delta);
}
memset(DataPtr(), 0, DataSize());
memset(GetDataStartAddress(), 0, DataSize());
LayoutDescriptor* layout_descriptor =
Initialize(this, map, descriptors, num_descriptors);
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"
// of the descriptor then the field is also considered tagged.
// Once a layout descriptor is created it is allowed only to append properties
// to it.
class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
// to it. GC uses layout descriptors to iterate objects. Avoid heap pointers
// in a layout descriptor because they can lead to data races in GC when
// GC moves objects in parallel.
class LayoutDescriptor : public ByteArray {
public:
V8_INLINE bool IsTagged(int field_index);
@ -94,7 +96,10 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
LayoutDescriptor* SetTaggedForTesting(int field_index, bool tagged);
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 LayoutDescriptor* FromSmi(Smi* smi);

View File

@ -310,9 +310,7 @@ bool HeapObject::IsArrayList() const { return IsFixedArray(); }
bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArray(); }
bool Object::IsLayoutDescriptor() const {
return IsSmi() || IsFixedTypedArrayBase();
}
bool Object::IsLayoutDescriptor() const { return IsSmi() || IsByteArray(); }
bool HeapObject::IsFeedbackVector() const {
return map() == GetHeap()->feedback_vector_map();
@ -3694,7 +3692,7 @@ void StringCharacterStream::VisitTwoByteString(
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());
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);
}
int ByteArray::get_int(int index) {
int ByteArray::get_int(int index) const {
DCHECK(index >= 0 && index < this->length() / 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);
}
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) {
DCHECK_TAG_ALIGNED(address);
return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag);
}
int ByteArray::DataSize() const { return RoundUp(length(), kPointerSize); }
int ByteArray::ByteArraySize() { return SizeFor(this->length()); }

View File

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

View File

@ -3187,7 +3187,7 @@ class ByteArray: public FixedArrayBase {
inline int Size();
// Setter and getter.
inline byte get(int index);
inline byte get(int index) const;
inline void set(int index, byte value);
// 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);
// 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 uint32_t get_uint32(int index) const;
inline void set_uint32(int index, uint32_t value);
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length);
}
@ -3214,6 +3217,8 @@ class ByteArray: public FixedArrayBase {
// Returns data start address.
inline Address GetDataStartAddress();
inline int DataSize() const;
// Returns a pointer to the ByteArray object for a given data start address.
static inline ByteArray* FromDataStartAddress(Address address);

View File

@ -602,7 +602,7 @@ TEST(LayoutDescriptorCreateNewSlow) {
LayoutDescriptor* layout_desc = *layout_descriptor;
CHECK_EQ(layout_desc, LayoutDescriptor::cast(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.
MapWord map_word = layout_desc->map_word();
CHECK(!map_word.IsForwardingAddress());
@ -982,7 +982,7 @@ TEST(DescriptorArrayTrimming) {
CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
CHECK(map->layout_descriptor()->IsSlowLayout());
CHECK(map->owns_descriptors());
CHECK_EQ(2, map->layout_descriptor()->length());
CHECK_EQ(8, map->layout_descriptor()->length());
{
// Add transitions to double fields.
@ -1002,7 +1002,7 @@ TEST(DescriptorArrayTrimming) {
CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor());
}
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.
CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
@ -1022,7 +1022,7 @@ TEST(DescriptorArrayTrimming) {
CHECK_EQ(map->NumberOfOwnDescriptors(),
map->instance_descriptors()->number_of_descriptors());
CHECK(map->layout_descriptor()->IsSlowLayout());
CHECK_EQ(2, map->layout_descriptor()->length());
CHECK_EQ(8, map->layout_descriptor()->length());
{
// Add transitions to tagged fields.