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

Reply via email to