Revision: 12426
Author: [email protected]
Date: Mon Sep 3 05:31:24 2012
Log: Optimize dictionary enum generation.
Review URL: https://chromiumcodereview.appspot.com/10916076
http://code.google.com/p/v8/source/detail?r=12426
Modified:
/branches/bleeding_edge/src/handles.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
=======================================
--- /branches/bleeding_edge/src/handles.cc Tue Aug 28 07:20:50 2012
+++ /branches/bleeding_edge/src/handles.cc Mon Sep 3 05:31:24 2012
@@ -771,10 +771,36 @@
}
return storage;
} else {
- int num_enum = object->NumberOfLocalProperties(DONT_ENUM);
- Handle<FixedArray> storage =
isolate->factory()->NewFixedArray(num_enum);
- Handle<FixedArray> sort_array =
isolate->factory()->NewFixedArray(num_enum);
- object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
+ Handle<StringDictionary> dictionary(object->property_dictionary());
+
+ int length = dictionary->NumberOfElements();
+ 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 (next_enumeration > (length * 3) / 2) {
+ StringDictionary::DoGenerateNewEnumerationIndices(dictionary);
+ next_enumeration = dictionary->NextEnumerationIndex();
+ }
+
+ Handle<FixedArray> storage =
+ isolate->factory()->NewFixedArray(next_enumeration);
+
+ dictionary->CopyEnumKeysTo(*storage);
+ ASSERT(storage->length() ==
object->NumberOfLocalProperties(DONT_ENUM));
return storage;
}
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Fri Aug 31 11:12:25 2012
+++ /branches/bleeding_edge/src/objects.cc Mon Sep 3 05:31:24 2012
@@ -12149,6 +12149,12 @@
return obj;
}
+
+void StringDictionary::DoGenerateNewEnumerationIndices(
+ Handle<StringDictionary> dictionary) {
+ CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
+ dictionary->GenerateNewEnumerationIndices());
+}
template<typename Shape, typename Key>
MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
@@ -12468,23 +12474,43 @@
}
-void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
- FixedArray* sort_array) {
- ASSERT(storage->length() >= NumberOfEnumElements());
+void StringDictionary::CopyEnumKeysTo(FixedArray* storage) {
+ int length = storage->length();
+ ASSERT(length >= NumberOfEnumElements());
+ Heap* heap = GetHeap();
+ Object* undefined_value = heap->undefined_value();
int capacity = Capacity();
- int index = 0;
+ 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)) {
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted() || details.IsDontEnum()) continue;
- storage->set(index, k);
- sort_array->set(index, Smi::FromInt(details.dictionary_index()));
- index++;
+ properties++;
+ storage->set(details.dictionary_index() - 1, k);
+ if (properties == length) break;
}
}
- storage->SortPairs(sort_array, sort_array->length());
- ASSERT(storage->length() >= index);
+
+ // 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) {
+ 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);
+ }
}
=======================================
--- /branches/bleeding_edge/src/objects.h Tue Aug 28 07:20:50 2012
+++ /branches/bleeding_edge/src/objects.h Mon Sep 3 05:31:24 2012
@@ -3128,7 +3128,9 @@
}
// Copies enumerable keys to preallocated fixed array.
- void CopyEnumKeysTo(FixedArray* storage, FixedArray* sort_array);
+ void CopyEnumKeysTo(FixedArray* storage);
+ static void DoGenerateNewEnumerationIndices(
+ Handle<StringDictionary> dictionary);
// For transforming properties of a JSObject.
MUST_USE_RESULT MaybeObject* TransformPropertiesToFastFor(
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev