Commit 66c8130b authored by ulan@chromium.org's avatar ulan@chromium.org

Simplify GetEnumPropertyKeys and avoid trimming fixed arrays in large object space.

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
parent f1e18135
......@@ -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;
}
}
......
......@@ -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;
}
......
......@@ -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);
......
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