Simplify GetEnumPropertyKeys and avoid trimming fixed arrays in large object space.
authorulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 13 Mar 2014 12:45:12 +0000 (12:45 +0000)
committerulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 13 Mar 2014 12:45:12 +0000 (12:45 +0000)
BUG=352070
LOG=N
R=verwaest@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19894 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/handles.cc
src/objects.cc
src/objects.h

index 899f9bf..398a682 100644 (file)
@@ -712,35 +712,12 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
     return ReduceFixedArrayTo(storage, enum_size);
   } else {
     Handle<NameDictionary> dictionary(object->property_dictionary());
-
-    int length = dictionary->NumberOfElements();
+    int length = dictionary->NumberOfEnumElements();
     if (length == 0) {
       return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
     }
-
-    // The enumeration array is generated by allocating an array big enough to
-    // hold all properties that have been seen, whether they are are deleted or
-    // not. Subsequently all visible properties are added to the array. If some
-    // properties were not visible, the array is trimmed so it only contains
-    // visible properties. This improves over adding elements and sorting by
-    // index by having linear complexity rather than n*log(n).
-
-    // By comparing the monotonous NextEnumerationIndex to the NumberOfElements,
-    // we can predict the number of holes in the final array. If there will be
-    // more than 50% holes, regenerate the enumeration indices to reduce the
-    // number of holes to a minimum. This avoids allocating a large array if
-    // many properties were added but subsequently deleted.
-    int next_enumeration = dictionary->NextEnumerationIndex();
-    if (!object->IsGlobalObject() && next_enumeration > (length * 3) / 2) {
-      NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
-      next_enumeration = dictionary->NextEnumerationIndex();
-    }
-
-    Handle<FixedArray> storage =
-        isolate->factory()->NewFixedArray(next_enumeration);
-
-    storage = Handle<FixedArray>(dictionary->CopyEnumKeysTo(*storage));
-    ASSERT(storage->length() == object->NumberOfLocalProperties(DONT_SHOW));
+    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
+    dictionary->CopyEnumKeysTo(*storage);
     return storage;
   }
 }
index b03c39e..492f752 100644 (file)
@@ -15511,7 +15511,7 @@ int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
 template<typename Shape, typename Key>
 int Dictionary<Shape, Key>::NumberOfEnumElements() {
   return NumberOfElementsFilterAttributes(
-      static_cast<PropertyAttributes>(DONT_ENUM));
+      static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
 }
 
 
@@ -15539,45 +15539,38 @@ void Dictionary<Shape, Key>::CopyKeysTo(
 }
 
 
-FixedArray* NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
+struct EnumIndexComparator {
+  explicit EnumIndexComparator(NameDictionary* dict) : dict(dict) { }
+  bool operator() (Smi* a, Smi* b) {
+    PropertyDetails da(dict->DetailsAt(a->value()));
+    PropertyDetails db(dict->DetailsAt(b->value()));
+    return da.dictionary_index() < db.dictionary_index();
+  }
+  NameDictionary* dict;
+};
+
+
+void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
   int length = storage->length();
-  ASSERT(length >= NumberOfEnumElements());
-  Heap* heap = GetHeap();
-  Object* undefined_value = heap->undefined_value();
   int capacity = Capacity();
   int properties = 0;
-
-  // Fill in the enumeration array by assigning enumerable keys at their
-  // enumeration index. This will leave holes in the array if there are keys
-  // that are deleted or not enumerable.
   for (int i = 0; i < capacity; i++) {
      Object* k = KeyAt(i);
      if (IsKey(k) && !k->IsSymbol()) {
        PropertyDetails details = DetailsAt(i);
        if (details.IsDeleted() || details.IsDontEnum()) continue;
+       storage->set(properties, Smi::FromInt(i));
        properties++;
-       storage->set(details.dictionary_index() - 1, k);
        if (properties == length) break;
      }
   }
-
-  // There are holes in the enumeration array if less properties were assigned
-  // than the length of the array. If so, crunch all the existing properties
-  // together by shifting them to the left (maintaining the enumeration order),
-  // and trimming of the right side of the array.
-  if (properties < length) {
-    if (properties == 0) return heap->empty_fixed_array();
-    properties = 0;
-    for (int i = 0; i < length; ++i) {
-      Object* value = storage->get(i);
-      if (value != undefined_value) {
-        storage->set(properties, value);
-        ++properties;
-      }
-    }
-    RightTrimFixedArray<FROM_MUTATOR>(heap, storage, length - properties);
+  EnumIndexComparator cmp(this);
+  Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
+  std::sort(start, start + length, cmp);
+  for (int i = 0; i < length; i++) {
+    int index = Smi::cast(storage->get(i))->value();
+    storage->set(i, KeyAt(index));
   }
-  return storage;
 }
 
 
index 8b0cd41..c772578 100644 (file)
@@ -4036,7 +4036,7 @@ class NameDictionary: public Dictionary<NameDictionaryShape, Name*> {
   }
 
   // Copies enumerable keys to preallocated fixed array.
-  FixedArray* CopyEnumKeysTo(FixedArray* storage);
+  void CopyEnumKeysTo(FixedArray* storage);
   static void DoGenerateNewEnumerationIndices(
       Handle<NameDictionary> dictionary);