Revision: 11922
Author: [email protected]
Date: Mon Jun 25 06:10:54 2012
Log: In-place shrinking of descriptor arrays with non-live transitions.
Instead of overwriting non-live transitions with NULL_DESCRIPTORs, we
remove them from the array by compacting the array (shifting live values to
the left) and in-place trimming the array. If the final descriptor array
contains no live values (only contained transitions which are now all
cleared), we move bit_field3 back from the descriptor array to the map. The
descriptor array itself will be collected in the next GC.
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com/10575032
http://code.google.com/p/v8/source/detail?r=11922
Modified:
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/factory.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/mark-compact.cc
/branches/bleeding_edge/src/objects-debug.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects-printer.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/profile-generator.cc
/branches/bleeding_edge/src/property-details.h
/branches/bleeding_edge/src/property.cc
/branches/bleeding_edge/src/property.h
/branches/bleeding_edge/src/runtime.cc
=======================================
--- /branches/bleeding_edge/src/ast.cc Tue Jun 19 07:29:48 2012
+++ /branches/bleeding_edge/src/ast.cc Mon Jun 25 06:10:54 2012
@@ -520,9 +520,11 @@
return false;
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
// Perhaps something interesting is up in the prototype chain...
break;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
}
}
// If we reach the end of the prototype chain, we don't know the
target.
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Jun 21 08:32:52 2012
+++ /branches/bleeding_edge/src/bootstrapper.cc Mon Jun 25 06:10:54 2012
@@ -2193,13 +2193,13 @@
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
// Ignore non-properties.
break;
case NORMAL:
// Do not occur since the from object has fast properties.
case HANDLER:
case INTERCEPTOR:
+ case NONEXISTENT:
// No element in instance descriptors have proxy or interceptor
type.
UNREACHABLE();
break;
=======================================
--- /branches/bleeding_edge/src/factory.cc Fri Jun 22 06:55:15 2012
+++ /branches/bleeding_edge/src/factory.cc Mon Jun 25 06:10:54 2012
@@ -922,24 +922,17 @@
Handle<Object> descriptors) {
v8::NeanderArray callbacks(descriptors);
int nof_callbacks = callbacks.length();
+ int descriptor_count = array->number_of_descriptors();
Handle<DescriptorArray> result =
- NewDescriptorArray(array->number_of_descriptors() + nof_callbacks);
-
- // Number of descriptors added to the result so far.
- int descriptor_count = 0;
+ NewDescriptorArray(descriptor_count + nof_callbacks);
// Ensure that marking will not progress and change color of objects.
DescriptorArray::WhitenessWitness witness(*result);
// Copy the descriptors from the array.
- for (int i = 0; i < array->number_of_descriptors(); i++) {
- if (!array->IsNullDescriptor(i)) {
- DescriptorArray::CopyFrom(result, descriptor_count++, array, i,
witness);
- }
- }
-
- // Number of duplicates detected.
- int duplicates = 0;
+ for (int i = 0; i < descriptor_count; i++) {
+ DescriptorArray::CopyFrom(result, i, array, i, witness);
+ }
// Fill in new callback descriptors. Process the callbacks from
// back to front so that the last callback with a given name takes
@@ -956,18 +949,14 @@
CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
result->Set(descriptor_count, &desc, witness);
descriptor_count++;
- } else {
- duplicates++;
}
}
// If duplicates were detected, allocate a result of the right size
// and transfer the elements.
- if (duplicates > 0) {
- int number_of_descriptors = result->number_of_descriptors() -
duplicates;
- Handle<DescriptorArray> new_result =
- NewDescriptorArray(number_of_descriptors);
- for (int i = 0; i < number_of_descriptors; i++) {
+ if (descriptor_count < result->length()) {
+ Handle<DescriptorArray> new_result =
NewDescriptorArray(descriptor_count);
+ for (int i = 0; i < descriptor_count; i++) {
DescriptorArray::CopyFrom(new_result, i, result, i, witness);
}
result = new_result;
=======================================
--- /branches/bleeding_edge/src/ic.cc Mon Jun 25 04:35:23 2012
+++ /branches/bleeding_edge/src/ic.cc Mon Jun 25 06:10:54 2012
@@ -1298,7 +1298,7 @@
static bool StoreICableLookup(LookupResult* lookup) {
// Bail out if we didn't find a result.
- if (!lookup->IsFound() || lookup->type() == NULL_DESCRIPTOR) return
false;
+ if (!lookup->IsFound()) return false;
// Bail out if inline caching is not allowed.
if (!lookup->IsCacheable()) return false;
@@ -1434,10 +1434,10 @@
Handle<Object> value) {
ASSERT(!receiver->IsJSGlobalProxy());
ASSERT(StoreICableLookup(lookup));
+ ASSERT(lookup->IsFound());
+
// These are not cacheable, so we never see such LookupResults here.
ASSERT(!lookup->IsHandler());
- // We get only called for properties or transitions, see
StoreICableLookup.
- ASSERT(lookup->type() != NULL_DESCRIPTOR);
// If the property has a non-field type allowing map transitions
// where there is extra room in the object, we leave the IC in its
@@ -1509,8 +1509,8 @@
case CONSTANT_FUNCTION:
case CONSTANT_TRANSITION:
return;
+ case NONEXISTENT:
case HANDLER:
- case NULL_DESCRIPTOR:
UNREACHABLE();
return;
}
@@ -1936,10 +1936,10 @@
Handle<Object> value) {
ASSERT(!receiver->IsJSGlobalProxy());
ASSERT(StoreICableLookup(lookup));
+ ASSERT(lookup->IsFound());
+
// These are not cacheable, so we never see such LookupResults here.
ASSERT(!lookup->IsHandler());
- // We get only called for properties or transitions, see
StoreICableLookup.
- ASSERT(lookup->type() != NULL_DESCRIPTOR);
// If the property has a non-field type allowing map transitions
// where there is extra room in the object, we leave the IC in its
@@ -1978,7 +1978,7 @@
: generic_stub();
break;
case HANDLER:
- case NULL_DESCRIPTOR:
+ case NONEXISTENT:
UNREACHABLE();
return;
}
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Fri Jun 22 04:47:30 2012
+++ /branches/bleeding_edge/src/mark-compact.cc Mon Jun 25 06:10:54 2012
@@ -1901,8 +1901,7 @@
}
// If the descriptor contains a transition (value is a Map), we don't
mark the
- // value as live. It might be set to the NULL_DESCRIPTOR in
- // ClearNonLiveTransitions later.
+ // value as live. It might be removed by ClearNonLiveTransitions later.
for (int i = 0; i < descriptors->number_of_descriptors(); ++i) {
Object** key_slot = descriptors->GetKeySlot(i);
Object* key = *key_slot;
@@ -1940,7 +1939,9 @@
break;
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
+ break;
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
}
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc Mon Jun 18 04:43:09 2012
+++ /branches/bleeding_edge/src/objects-debug.cc Mon Jun 25 06:10:54 2012
@@ -953,7 +953,9 @@
case CONSTANT_FUNCTION:
case HANDLER:
case INTERCEPTOR:
- case NULL_DESCRIPTOR:
+ break;
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
}
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Mon Jun 25 04:35:23 2012
+++ /branches/bleeding_edge/src/objects-inl.h Mon Jun 25 06:10:54 2012
@@ -1863,7 +1863,7 @@
void FixedArray::set_null_unchecked(Heap* heap, int index) {
ASSERT(index >= 0 && index < this->length());
- ASSERT(!HEAP->InNewSpace(heap->null_value()));
+ ASSERT(!heap->InNewSpace(heap->null_value()));
WRITE_FIELD(this, kHeaderSize + index * kPointerSize,
heap->null_value());
}
@@ -1974,6 +1974,17 @@
ASSERT(descriptor_number < number_of_descriptors());
return String::cast(get(ToKeyIndex(descriptor_number)));
}
+
+
+void DescriptorArray::SetKeyUnchecked(Heap* heap,
+ int descriptor_number,
+ String* key) {
+ ASSERT(descriptor_number < number_of_descriptors());
+ set_unchecked(heap,
+ ToKeyIndex(descriptor_number),
+ key,
+ UPDATE_WRITE_BARRIER);
+}
Object** DescriptorArray::GetValueSlot(int descriptor_number) {
@@ -1990,10 +2001,22 @@
}
-void DescriptorArray::SetNullValueUnchecked(int descriptor_number, Heap*
heap) {
+void DescriptorArray::SetNullValueUnchecked(Heap* heap, int
descriptor_number) {
ASSERT(descriptor_number < number_of_descriptors());
set_null_unchecked(heap, ToValueIndex(descriptor_number));
}
+
+
+
+void DescriptorArray::SetValueUnchecked(Heap* heap,
+ int descriptor_number,
+ Object* value) {
+ ASSERT(descriptor_number < number_of_descriptors());
+ set_unchecked(heap,
+ ToValueIndex(descriptor_number),
+ value,
+ UPDATE_WRITE_BARRIER);
+}
PropertyDetails DescriptorArray::GetDetails(int descriptor_number) {
@@ -2059,17 +2082,14 @@
case CONSTANT_FUNCTION:
case HANDLER:
case INTERCEPTOR:
- case NULL_DESCRIPTOR:
return false;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
}
UNREACHABLE(); // Keep the compiler happy.
return false;
}
-
-
-bool DescriptorArray::IsNullDescriptor(int descriptor_number) {
- return GetType(descriptor_number) == NULL_DESCRIPTOR;
-}
void DescriptorArray::Get(int descriptor_number, Descriptor* desc) {
@@ -3462,12 +3482,25 @@
return DescriptorArray::cast(object)->bit_field3_storage();
}
}
+
+
+void Map::ClearDescriptorArray() {
+ int bitfield3 = bit_field3();
+#ifdef DEBUG
+ Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
+ if (!object->IsSmi()) {
+ ZapInstanceDescriptors();
+ }
+#endif
+ WRITE_FIELD(this,
+ kInstanceDescriptorsOrBitField3Offset,
+ Smi::FromInt(bitfield3));
+}
void Map::set_bit_field3(int value) {
ASSERT(Smi::IsValid(value));
- Object* object = READ_FIELD(this,
- kInstanceDescriptorsOrBitField3Offset);
+ Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
if (object->IsSmi()) {
WRITE_FIELD(this,
kInstanceDescriptorsOrBitField3Offset,
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc Thu Jun 14 08:33:15 2012
+++ /branches/bleeding_edge/src/objects-printer.cc Mon Jun 25 06:10:54 2012
@@ -279,12 +279,10 @@
case CONSTANT_TRANSITION:
PrintF(out, "(constant transition)\n");
break;
- case NULL_DESCRIPTOR:
- PrintF(out, "(null descriptor)\n");
- break;
case NORMAL: // only in slow mode
case HANDLER: // only in lookup results, not in descriptors
case INTERCEPTOR: // only in lookup results, not in descriptors
+ case NONEXISTENT:
UNREACHABLE();
break;
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Mon Jun 25 04:35:23 2012
+++ /branches/bleeding_edge/src/objects.cc Mon Jun 25 06:10:54 2012
@@ -418,7 +418,7 @@
case HANDLER:
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
+ case NONEXISTENT:
UNREACHABLE();
}
}
@@ -643,7 +643,9 @@
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
+ break;
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
UNREACHABLE();
@@ -2156,7 +2158,9 @@
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
+ break;
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
}
@@ -2939,9 +2943,8 @@
// FIELD, even if the value is a constant function.
return ConvertDescriptorToFieldAndMapTransition(name, value,
attributes);
}
- case NULL_DESCRIPTOR:
- return ConvertDescriptorToFieldAndMapTransition(name, value,
attributes);
case HANDLER:
+ case NONEXISTENT:
UNREACHABLE();
return value;
}
@@ -3037,9 +3040,9 @@
case CONSTANT_TRANSITION:
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
// if the value is a function.
- case NULL_DESCRIPTOR:
return ConvertDescriptorToFieldAndMapTransition(name, value,
attributes);
case HANDLER:
+ case NONEXISTENT:
UNREACHABLE();
}
UNREACHABLE(); // keep the compiler happy
@@ -3332,11 +3335,11 @@
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
case INTERCEPTOR:
break;
case HANDLER:
case NORMAL:
+ case NONEXISTENT:
UNREACHABLE();
break;
}
@@ -3680,8 +3683,7 @@
this->FastPropertyAt(descriptors->GetFieldIndex(0));
return StringDictionary::cast(hidden_store);
} else {
- ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
- descriptors->GetType(0) == MAP_TRANSITION);
+ ASSERT(descriptors->GetType(0) == MAP_TRANSITION);
}
}
} else {
@@ -3729,8 +3731,7 @@
this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
return this;
} else {
- ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
- descriptors->GetType(0) == MAP_TRANSITION);
+ ASSERT(descriptors->GetType(0) == MAP_TRANSITION);
}
}
}
@@ -4177,9 +4178,7 @@
int Map::PropertyIndexFor(String* name) {
DescriptorArray* descs = instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
- return descs->GetFieldIndex(i);
- }
+ if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i);
}
return -1;
}
@@ -5086,11 +5085,13 @@
case CONSTANT_FUNCTION:
case HANDLER:
case INTERCEPTOR:
- case NULL_DESCRIPTOR:
// We definitely have no map transition.
raw_index += 2;
++index;
break;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
}
}
if (index == descriptor_array_->number_of_descriptors()) {
@@ -5880,7 +5881,6 @@
// removing all other transitions is not supported.
bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
ASSERT(remove_transitions == !descriptor->ContainsTransition());
- ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
// Ensure the key is a symbol.
{ MaybeObject* maybe_result = descriptor->KeyToSymbol();
@@ -5889,7 +5889,6 @@
int new_size = 0;
for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsNullDescriptor(i)) continue;
if (remove_transitions && IsTransitionOnly(i)) continue;
new_size++;
}
@@ -5947,8 +5946,7 @@
insertion_index = to_index++;
if (replacing) from_index++;
} else {
- if (!(IsNullDescriptor(from_index) ||
- (remove_transitions && IsTransitionOnly(from_index)))) {
+ if (!(remove_transitions && IsTransitionOnly(from_index))) {
MaybeObject* copy_result =
new_descriptors->CopyFrom(to_index++, this, from_index,
witness);
if (copy_result->IsFailure()) return copy_result;
@@ -6078,8 +6076,7 @@
}
for (; low <= limit && GetKey(low)->Hash() == hash; ++low) {
- if (GetKey(low)->Equals(name) && !IsNullDescriptor(low))
- return low;
+ if (GetKey(low)->Equals(name)) return low;
}
return kNotFound;
@@ -6091,9 +6088,7 @@
for (int number = 0; number < len; number++) {
String* entry = GetKey(number);
if (mode == EXPECT_SORTED && entry->Hash() > hash) break;
- if (name->Equals(entry) && !IsNullDescriptor(number)) {
- return number;
- }
+ if (name->Equals(entry)) return number;
}
return kNotFound;
}
@@ -7352,75 +7347,147 @@
}
-void Map::ClearNonLiveTransitions(Heap* heap) {
- DescriptorArray* d = DescriptorArray::cast(
- *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
- if (d->IsEmpty()) return;
- Map* elements_transition = d->elements_transition_map();
- if (elements_transition != NULL &&
- ClearBackPointer(heap, elements_transition)) {
- d->ClearElementsTransition();
- }
- Smi* NullDescriptorDetails =
- PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
- for (int i = 0; i < d->number_of_descriptors(); ++i) {
- // If the pair (value, details) is a map transition, check if the
target is
- // live. If not, null the descriptor. Also drop the back pointer for
that
- // map transition, so that this map is not reached again by following
a back
- // pointer from that non-live map.
- bool keep_entry = false;
- PropertyDetails details(d->GetDetails(i));
- switch (details.type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- keep_entry = !ClearBackPointer(heap, d->GetValue(i));
- break;
- case CALLBACKS: {
- Object* object = d->GetValue(i);
- if (object->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(object);
- Object* getter = accessors->getter();
- if (getter->IsMap()) {
- if (ClearBackPointer(heap, getter)) {
- accessors->set_getter(heap->the_hole_value());
- } else {
- keep_entry = true;
- }
- } else if (!getter->IsTheHole()) {
- keep_entry = true;
- }
- Object* setter = accessors->setter();
- if (setter->IsMap()) {
- if (ClearBackPointer(heap, setter)) {
- accessors->set_setter(heap->the_hole_value());
- } else {
- keep_entry = true;
- }
- } else if (!setter->IsTheHole()) {
- keep_entry = true;
- }
- } else {
- keep_entry = true;
- }
- break;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- keep_entry = true;
- break;
- }
- // Make sure that an entry containing only dead transitions gets
collected.
- // What we *really* want to do here is removing this entry completely,
but
- // for technical reasons we can't do this, so we zero it out instead.
- if (!keep_entry) {
- d->SetDetailsUnchecked(i, NullDescriptorDetails);
- d->SetNullValueUnchecked(i, heap);
+// This function should only be called from within the GC, since it uses
+// IncrementLiveBytesFromGC. If called from anywhere else, this results in
an
+// inconsistent live-bytes count.
+static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim)
{
+ ASSERT(elms->map() != HEAP->fixed_cow_array_map());
+ // For now this trick is only applied to fixed arrays in new and paged
space.
+ // In large object space the object's start must coincide with chunk
+ // and thus the trick is just not applicable.
+ ASSERT(!HEAP->lo_space()->Contains(elms));
+
+ const int len = elms->length();
+
+ ASSERT(to_trim < len);
+
+ Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
+
+#ifdef DEBUG
+ // If we are doing a big trim in old space then we zap the space.
+ Object** zap = reinterpret_cast<Object**>(new_end);
+ for (int i = 1; i < to_trim; i++) {
+ *zap++ = Smi::FromInt(0);
+ }
+#endif
+
+ int size_delta = to_trim * kPointerSize;
+
+ // Technically in new space this write might be omitted (except for
+ // debug mode which iterates through the heap), but to play safer
+ // we still do it.
+ heap->CreateFillerObjectAt(new_end, size_delta);
+
+ elms->set_length(len - to_trim);
+
+ // Maintain marking consistency for IncrementalMarking.
+ if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
+ MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
+ }
+}
+
+
+// If the descriptor describes a transition to a dead map, the back pointer
+// of this map is cleared and we return true. Otherwise we return false.
+static bool ClearNonLiveTransitionsFromDescriptor(Heap* heap,
+ DescriptorArray* d,
+ int descriptor_index) {
+ // If the pair (value, details) is a map transition, check if the target
is
+ // live. If not, null the descriptor. Also drop the back pointer for that
+ // map transition, so that this map is not reached again by following a
back
+ // pointer from that non-live map.
+ PropertyDetails details(d->GetDetails(descriptor_index));
+ switch (details.type()) {
+ case MAP_TRANSITION:
+ case CONSTANT_TRANSITION:
+ return ClearBackPointer(heap, d->GetValue(descriptor_index));
+ case CALLBACKS: {
+ Object* object = d->GetValue(descriptor_index);
+ if (object->IsAccessorPair()) {
+ bool cleared = true;
+ AccessorPair* accessors = AccessorPair::cast(object);
+ Object* getter = accessors->getter();
+ if (getter->IsMap()) {
+ if (ClearBackPointer(heap, getter)) {
+ accessors->set_getter(heap->the_hole_value());
+ } else {
+ cleared = false;
+ }
+ } else if (!getter->IsTheHole()) {
+ cleared = false;
+ }
+ Object* setter = accessors->setter();
+ if (setter->IsMap()) {
+ if (ClearBackPointer(heap, setter)) {
+ accessors->set_setter(heap->the_hole_value());
+ } else {
+ cleared = false;
+ }
+ } else if (!setter->IsTheHole()) {
+ cleared = false;
+ }
+ return cleared;
+ }
+ return false;
+ }
+ case NORMAL:
+ case FIELD:
+ case CONSTANT_FUNCTION:
+ case HANDLER:
+ case INTERCEPTOR:
+ return false;
+ case NONEXISTENT:
+ break;
+ }
+ UNREACHABLE();
+ return true;
+}
+
+
+void Map::ClearNonLiveTransitions(Heap* heap) {
+ Object* array = *RawField(this,
Map::kInstanceDescriptorsOrBitField3Offset);
+ // If there are no descriptors to be cleared, return.
+ // TODO(verwaest) Should be an assert, otherwise back pointers are not
+ // properly cleared.
+ if (array->IsSmi()) return;
+ DescriptorArray* d = DescriptorArray::cast(array);
+
+ int descriptor_index = 0;
+ // Compact all live descriptors to the left.
+ for (int i = 0; i < d->number_of_descriptors(); ++i) {
+ if (!ClearNonLiveTransitionsFromDescriptor(heap, d, i)) {
+ if (i != descriptor_index) {
+ d->SetKeyUnchecked(heap, descriptor_index, d->GetKey(i));
+ d->SetDetailsUnchecked(descriptor_index, d->GetDetails(i).AsSmi());
+ d->SetValueUnchecked(heap, descriptor_index, d->GetValue(i));
+ }
+ descriptor_index++;
}
}
+
+ Map* elements_transition = d->elements_transition_map();
+ if (elements_transition != NULL &&
+ ClearBackPointer(heap, elements_transition)) {
+ elements_transition = NULL;
+ d->ClearElementsTransition();
+ } else {
+ // If there are no descriptors to be cleared, return.
+ // TODO(verwaest) Should be an assert, otherwise back pointers are not
+ // properly cleared.
+ if (descriptor_index == d->number_of_descriptors()) return;
+ }
+
+ // If the final descriptor array does not contain any live descriptors,
remove
+ // the descriptor array from the map.
+ if (descriptor_index == 0 && elements_transition == NULL) {
+ ClearDescriptorArray();
+ return;
+ }
+
+ int trim = d->number_of_descriptors() - descriptor_index;
+ if (trim > 0) {
+ RightTrimFixedArray(heap, d, trim * DescriptorArray::kDescriptorSize);
+ }
}
@@ -11261,8 +11328,10 @@
case CONSTANT_FUNCTION:
case HANDLER:
case INTERCEPTOR:
- case NULL_DESCRIPTOR:
return false;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
}
UNREACHABLE(); // Keep the compiler happy.
return false;
=======================================
--- /branches/bleeding_edge/src/objects.h Mon Jun 25 04:35:23 2012
+++ /branches/bleeding_edge/src/objects.h Mon Jun 25 06:10:54 2012
@@ -2501,9 +2501,13 @@
// Accessors for fetching instance descriptor at descriptor number.
inline String* GetKey(int descriptor_number);
inline Object** GetKeySlot(int descriptor_number);
+ inline void SetKeyUnchecked(Heap* heap, int descriptor_number, String*
value);
inline Object* GetValue(int descriptor_number);
inline Object** GetValueSlot(int descriptor_number);
- inline void SetNullValueUnchecked(int descriptor_number, Heap* heap);
+ inline void SetNullValueUnchecked(Heap* heap, int descriptor_number);
+ inline void SetValueUnchecked(Heap* heap,
+ int descriptor_number,
+ Object* value);
inline PropertyDetails GetDetails(int descriptor_number);
inline void SetDetailsUnchecked(int descriptor_number, Smi* value);
inline PropertyType GetType(int descriptor_number);
@@ -2513,7 +2517,6 @@
inline AccessorDescriptor* GetCallbacks(int descriptor_number);
inline bool IsProperty(int descriptor_number);
inline bool IsTransitionOnly(int descriptor_number);
- inline bool IsNullDescriptor(int descriptor_number);
// WhitenessWitness is used to prove that a specific descriptor array is
white
// (unmarked), so incremental write barriers can be skipped because the
@@ -4780,6 +4783,10 @@
// [instance descriptors]: describes the object.
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
+ // Should only be called to clear a descriptor array that was only used
to
+ // store transitions and does not contain any live transitions anymore.
+ inline void ClearDescriptorArray();
+
// Sets the instance descriptor array for the map to be an empty
descriptor
// array.
inline void clear_instance_descriptors();
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Thu Jun 14 05:21:05
2012
+++ /branches/bleeding_edge/src/profile-generator.cc Mon Jun 25 06:10:54
2012
@@ -2220,7 +2220,9 @@
case INTERCEPTOR: // only in lookup results, not in descriptors
case MAP_TRANSITION: // we do not care about transitions here...
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR: // ... and not about "holes"
+ break;
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
}
=======================================
--- /branches/bleeding_edge/src/property-details.h Mon Jun 25 04:35:23 2012
+++ /branches/bleeding_edge/src/property-details.h Mon Jun 25 06:10:54 2012
@@ -64,7 +64,8 @@
// All properties before MAP_TRANSITION are real.
MAP_TRANSITION = 6, // only in fast mode
CONSTANT_TRANSITION = 7, // only in fast mode
- NULL_DESCRIPTOR = 8 // only in fast mode
+ // Only used as a marker in LookupResult.
+ NONEXISTENT = 8
};
=======================================
--- /branches/bleeding_edge/src/property.cc Sun Jun 10 23:59:56 2012
+++ /branches/bleeding_edge/src/property.cc Mon Jun 25 06:10:54 2012
@@ -89,8 +89,8 @@
GetTransitionMap()->Print(out);
PrintF(out, "\n");
break;
- case NULL_DESCRIPTOR:
- PrintF(out, " =type = null descriptor\n");
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
}
@@ -123,8 +123,10 @@
case CONSTANT_FUNCTION:
case HANDLER:
case INTERCEPTOR:
- case NULL_DESCRIPTOR:
return false;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
}
UNREACHABLE(); // Keep the compiler happy.
return false;
=======================================
--- /branches/bleeding_edge/src/property.h Mon Jun 25 04:35:23 2012
+++ /branches/bleeding_edge/src/property.h Mon Jun 25 06:10:54 2012
@@ -173,8 +173,10 @@
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
return false;
+ case NONEXISTENT:
+ UNREACHABLE();
+ break;
}
UNREACHABLE(); // keep the compiler happy
return false;
@@ -189,7 +191,7 @@
lookup_type_(NOT_FOUND),
holder_(NULL),
cacheable_(true),
- details_(NONE, NULL_DESCRIPTOR) {
+ details_(NONE, NONEXISTENT) {
isolate->SetTopLookupResult(this);
}
@@ -237,7 +239,7 @@
void NotFound() {
lookup_type_ = NOT_FOUND;
- details_ = PropertyDetails(NONE, NULL_DESCRIPTOR);
+ details_ = PropertyDetails(NONE, NONEXISTENT);
holder_ = NULL;
}
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Jun 22 06:55:15 2012
+++ /branches/bleeding_edge/src/runtime.cc Mon Jun 25 06:10:54 2012
@@ -10286,9 +10286,9 @@
case INTERCEPTOR:
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
return heap->undefined_value();
case HANDLER:
+ case NONEXISTENT:
UNREACHABLE();
return heap->undefined_value();
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev