Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Layout descriptor must be trimmed when corresponding descriptors arra…
Browse files Browse the repository at this point in the history
…y is trimmed to stay in sync.

BUG=chromium:470804
LOG=Y

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

Cr-Commit-Position: refs/heads/master@{#27528}
  • Loading branch information
isheludko authored and Commit bot committed Mar 30, 2015
1 parent 8baa09c commit 3cb9f13
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 62 deletions.
7 changes: 7 additions & 0 deletions src/heap/mark-compact.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2610,6 +2610,13 @@ void MarkCompactCollector::TrimDescriptorArray(Map* map,

if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors);
descriptors->Sort();

if (FLAG_unbox_double_fields) {
LayoutDescriptor* layout_descriptor = map->layout_descriptor();
layout_descriptor = layout_descriptor->Trim(heap_, map, descriptors,
number_of_own_descriptors);
SLOW_DCHECK(layout_descriptor->IsConsistentWithMap(map, true));
}
}


Expand Down
84 changes: 72 additions & 12 deletions src/layout-descriptor-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,7 @@ Handle<LayoutDescriptor> LayoutDescriptor::New(Isolate* isolate, int length) {
// The whole bit vector fits into a smi.
return handle(LayoutDescriptor::FromSmi(Smi::FromInt(0)), isolate);
}

length = (length + kNumberOfBits - 1) / kNumberOfBits;
DCHECK(length > 0);

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;
}
length = GetSlowModeBackingStoreLength(length);
return Handle<LayoutDescriptor>::cast(
isolate->factory()->NewFixedTypedArray(length, kExternalUint32Array));
}
Expand Down Expand Up @@ -154,6 +143,77 @@ LayoutDescriptor* LayoutDescriptor::cast_gc_safe(Object* 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;
}


int LayoutDescriptor::CalculateCapacity(Map* map, DescriptorArray* descriptors,
int num_descriptors) {
int inobject_properties = map->inobject_properties();
if (inobject_properties == 0) return 0;

DCHECK_LE(num_descriptors, descriptors->number_of_descriptors());

int layout_descriptor_length;
const int kMaxWordsPerField = kDoubleSize / kPointerSize;

if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) {
// Even in the "worst" case (all fields are doubles) it would fit into
// a Smi, so no need to calculate length.
layout_descriptor_length = kSmiValueSize;

} else {
layout_descriptor_length = 0;

for (int i = 0; i < num_descriptors; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (!InobjectUnboxedField(inobject_properties, details)) continue;
int field_index = details.field_index();
int field_width_in_words = details.field_width_in_words();
layout_descriptor_length =
Max(layout_descriptor_length, field_index + field_width_in_words);
}
}
layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);
return layout_descriptor_length;
}


LayoutDescriptor* LayoutDescriptor::Initialize(
LayoutDescriptor* layout_descriptor, Map* map, DescriptorArray* descriptors,
int num_descriptors) {
DisallowHeapAllocation no_allocation;
int inobject_properties = map->inobject_properties();

for (int i = 0; i < num_descriptors; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (!InobjectUnboxedField(inobject_properties, details)) {
DCHECK(details.location() != kField ||
layout_descriptor->IsTagged(details.field_index()));
continue;
}
int field_index = details.field_index();
layout_descriptor = layout_descriptor->SetRawData(field_index);
if (details.field_width_in_words() > 1) {
layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
}
}
return layout_descriptor;
}


// InobjectPropertiesHelper is a helper class for querying whether inobject
// property at offset is Double or not.
LayoutDescriptorHelper::LayoutDescriptorHelper(Map* map)
Expand Down
93 changes: 50 additions & 43 deletions src/layout-descriptor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,22 @@ Handle<LayoutDescriptor> LayoutDescriptor::New(
Isolate* isolate = descriptors->GetIsolate();
if (!FLAG_unbox_double_fields) return handle(FastPointerLayout(), isolate);

int inobject_properties = map->inobject_properties();
if (inobject_properties == 0) return handle(FastPointerLayout(), isolate);
int layout_descriptor_length =
CalculateCapacity(*map, *descriptors, num_descriptors);

DCHECK(num_descriptors <= descriptors->number_of_descriptors());

int layout_descriptor_length;
const int kMaxWordsPerField = kDoubleSize / kPointerSize;

if (num_descriptors <= kSmiValueSize / kMaxWordsPerField) {
// Even in the "worst" case (all fields are doubles) it would fit into
// a Smi, so no need to calculate length.
layout_descriptor_length = kSmiValueSize;

} else {
layout_descriptor_length = 0;

for (int i = 0; i < num_descriptors; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (!InobjectUnboxedField(inobject_properties, details)) continue;
int field_index = details.field_index();
int field_width_in_words = details.field_width_in_words();
layout_descriptor_length =
Max(layout_descriptor_length, field_index + field_width_in_words);
}

if (layout_descriptor_length == 0) {
// No double fields were found, use fast pointer layout.
return handle(FastPointerLayout(), isolate);
}
if (layout_descriptor_length == 0) {
// No double fields were found, use fast pointer layout.
return handle(FastPointerLayout(), isolate);
}
layout_descriptor_length = Min(layout_descriptor_length, inobject_properties);

// Initially, layout descriptor corresponds to an object with all fields
// tagged.
Handle<LayoutDescriptor> layout_descriptor_handle =
LayoutDescriptor::New(isolate, layout_descriptor_length);

DisallowHeapAllocation no_allocation;
LayoutDescriptor* layout_descriptor = *layout_descriptor_handle;

for (int i = 0; i < num_descriptors; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (!InobjectUnboxedField(inobject_properties, details)) continue;
int field_index = details.field_index();
layout_descriptor = layout_descriptor->SetRawData(field_index);
if (details.field_width_in_words() > 1) {
layout_descriptor = layout_descriptor->SetRawData(field_index + 1);
}
}
LayoutDescriptor* layout_descriptor = Initialize(
*layout_descriptor_handle, *map, *descriptors, num_descriptors);

return handle(layout_descriptor, isolate);
}

Expand Down Expand Up @@ -258,13 +225,44 @@ bool LayoutDescriptorHelper::IsTagged(
}


bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
LayoutDescriptor* LayoutDescriptor::Trim(Heap* heap, Map* map,
DescriptorArray* descriptors,
int num_descriptors) {
DisallowHeapAllocation no_allocation;
// Fast mode descriptors are never shared and therefore always fully
// correspond to their map.
if (!IsSlowLayout()) return this;

int layout_descriptor_length =
CalculateCapacity(map, descriptors, num_descriptors);
// It must not become fast-mode descriptor here, because otherwise it has to
// be fast pointer layout descriptor already but it's is slow mode now.
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;
heap->RightTrimFixedArray<Heap::FROM_GC>(this, delta);
}
memset(DataPtr(), 0, DataSize());
LayoutDescriptor* layout_descriptor =
Initialize(this, map, descriptors, num_descriptors);
DCHECK_EQ(this, layout_descriptor);
return layout_descriptor;
}


bool LayoutDescriptor::IsConsistentWithMap(Map* map, bool check_tail) {
if (FLAG_unbox_double_fields) {
DescriptorArray* descriptors = map->instance_descriptors();
int nof_descriptors = map->NumberOfOwnDescriptors();
int last_field_index = 0;
for (int i = 0; i < nof_descriptors; i++) {
PropertyDetails details = descriptors->GetDetails(i);
if (details.type() != DATA) continue;
if (details.location() != kField) continue;
FieldIndex field_index = FieldIndex::ForDescriptor(map, i);
bool tagged_expected =
!field_index.is_inobject() || !details.representation().IsDouble();
Expand All @@ -273,6 +271,15 @@ bool LayoutDescriptor::IsConsistentWithMap(Map* map) {
DCHECK_EQ(tagged_expected, tagged_actual);
if (tagged_actual != tagged_expected) return false;
}
last_field_index =
Max(last_field_index,
details.field_index() + details.field_width_in_words());
}
if (check_tail) {
int n = capacity();
for (int i = last_field_index; i < n; i++) {
DCHECK(IsTagged(i));
}
}
}
return true;
Expand Down
24 changes: 23 additions & 1 deletion src/layout-descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
V8_INLINE static LayoutDescriptor* FastPointerLayout();

// Check that this layout descriptor corresponds to given map.
bool IsConsistentWithMap(Map* map);
bool IsConsistentWithMap(Map* map, bool check_tail = false);

// Trims this layout descriptor to given number of descriptors. This happens
// only when corresponding descriptors array is trimmed.
// The layout descriptor could be trimmed if it was slow or it could
// become fast.
LayoutDescriptor* Trim(Heap* heap, Map* map, DescriptorArray* descriptors,
int num_descriptors);

#ifdef OBJECT_PRINT
// For our gdb macros, we should perhaps change these in the future.
Expand All @@ -94,6 +101,21 @@ class LayoutDescriptor : public FixedTypedArray<Uint32ArrayTraits> {
V8_INLINE static bool InobjectUnboxedField(int inobject_properties,
PropertyDetails details);

// Calculates minimal layout descriptor capacity required for given
// |map|, |descriptors| and |num_descriptors|.
V8_INLINE static int CalculateCapacity(Map* map, DescriptorArray* descriptors,
int num_descriptors);

// Calculates the length of the slow-mode backing store array by given layout
// descriptor length.
V8_INLINE static int GetSlowModeBackingStoreLength(int length);

// Fills in clean |layout_descriptor| according to given |map|, |descriptors|
// and |num_descriptors|.
V8_INLINE static LayoutDescriptor* Initialize(
LayoutDescriptor* layout_descriptor, Map* map,
DescriptorArray* descriptors, int num_descriptors);

static Handle<LayoutDescriptor> EnsureCapacity(
Isolate* isolate, Handle<LayoutDescriptor> layout_descriptor,
int new_capacity);
Expand Down
Loading

0 comments on commit 3cb9f13

Please sign in to comment.