Commit 3eed540a authored by verwaest@chromium.org's avatar verwaest@chromium.org

Optimize dictionary enum generation.

Review URL: https://chromiumcodereview.appspot.com/10916076

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12426 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a50dbcea
......@@ -771,10 +771,36 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
}
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;
}
}
......
......@@ -12150,6 +12150,12 @@ MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
}
void StringDictionary::DoGenerateNewEnumerationIndices(
Handle<StringDictionary> dictionary) {
CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
dictionary->GenerateNewEnumerationIndices());
}
template<typename Shape, typename Key>
MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Heap* heap = Dictionary<Shape, Key>::GetHeap();
......@@ -12468,23 +12474,43 @@ void Dictionary<Shape, Key>::CopyKeysTo(
}
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);
}
}
......
......@@ -3128,7 +3128,9 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
}
// 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(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment