| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 326b6f169ceb29b9c6364866bb21775fcbf73d3d..c0a0c08bc74d07b4e4308368fd8b543e568561d1 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -8098,8 +8098,8 @@
|
| PropertyFilter filter = static_cast<PropertyFilter>(
|
| ONLY_WRITABLE | ONLY_ENUMERABLE | ONLY_CONFIGURABLE);
|
| KeyAccumulator accumulator(isolate, filter);
|
| - accumulator.NextPrototype();
|
| - copy->CollectOwnPropertyNames(&accumulator, filter);
|
| + accumulator.Prepare();
|
| + copy->CollectOwnPropertyKeys(&accumulator, filter);
|
| Handle<FixedArray> names = accumulator.GetKeys();
|
| for (int i = 0; i < names->length(); i++) {
|
| DCHECK(names->get(i)->IsName());
|
| @@ -8438,10 +8438,9 @@
|
|
|
| namespace {
|
|
|
| -Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
|
| - Handle<JSObject> object,
|
| +Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, JSObject* object,
|
| bool cache_enum_length) {
|
| - Handle<Map> map(object->map());
|
| + Handle<Map> map(object->map(), isolate);
|
| Handle<DescriptorArray> descs =
|
| Handle<DescriptorArray>(map->instance_descriptors(), isolate);
|
| int own_property_count = map->EnumLength();
|
| @@ -8515,30 +8514,13 @@
|
| } // namespace
|
|
|
|
|
| -Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
|
| - bool cache_enum_length) {
|
| - Isolate* isolate = object->GetIsolate();
|
| - if (object->HasFastProperties()) {
|
| - return GetFastEnumPropertyKeys(isolate, object, cache_enum_length);
|
| - } else if (object->IsJSGlobalObject()) {
|
| - Handle<GlobalDictionary> dictionary(object->global_dictionary());
|
| - int length = dictionary->NumberOfEnumElements();
|
| - if (length == 0) {
|
| - return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
|
| - }
|
| - Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
|
| - dictionary->CopyEnumKeysTo(*storage);
|
| - return storage;
|
| - } else {
|
| - Handle<NameDictionary> dictionary(object->property_dictionary());
|
| - int length = dictionary->NumberOfEnumElements();
|
| - if (length == 0) {
|
| - return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
|
| - }
|
| - Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
|
| - dictionary->CopyEnumKeysTo(*storage);
|
| - return storage;
|
| - }
|
| +Handle<FixedArray> JSObject::GetOwnEnumPropertyKeys(Handle<JSObject> object,
|
| + bool cache_enum_length) {
|
| + PropertyFilter filter = PropertyFilter::ENUMERABLE_STRINGS;
|
| + KeyAccumulator keys(object->GetIsolate(), filter);
|
| + keys.Prepare();
|
| + object->CollectOwnPropertyKeys(&keys, filter);
|
| + return keys.GetKeys();
|
| }
|
|
|
|
|
| @@ -8622,30 +8604,7 @@
|
| isolate, receiver, object, *filter, accumulator);
|
| MAYBE_RETURN(success, Nothing<bool>());
|
|
|
| - if (*filter == ENUMERABLE_STRINGS) {
|
| - // We can cache the computed property keys if access checks are
|
| - // not needed and no interceptors are involved.
|
| - //
|
| - // We do not use the cache if the object has elements and
|
| - // therefore it does not make sense to cache the property names
|
| - // for arguments objects. Arguments objects will always have
|
| - // elements.
|
| - // Wrapped strings have elements, but don't have an elements
|
| - // array or dictionary. So the fast inline test for whether to
|
| - // use the cache says yes, so we should not create a cache.
|
| - Handle<JSFunction> arguments_function(
|
| - JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
|
| - bool cache_enum_length =
|
| - ((object->map()->GetConstructor() != *arguments_function) &&
|
| - !object->IsJSValue() && !object->IsAccessCheckNeeded() &&
|
| - !object->HasNamedInterceptor() && !object->HasIndexedInterceptor());
|
| - // Compute the property keys and cache them if possible.
|
| - Handle<FixedArray> enum_keys =
|
| - JSObject::GetEnumPropertyKeys(object, cache_enum_length);
|
| - accumulator->AddKeys(enum_keys);
|
| - } else {
|
| - object->CollectOwnPropertyNames(accumulator, *filter);
|
| - }
|
| + object->CollectOwnPropertyKeys(accumulator, *filter, type);
|
|
|
| // Add the property keys from the interceptor.
|
| success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
|
| @@ -16381,24 +16340,74 @@
|
| }
|
|
|
|
|
| -void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
|
| - PropertyFilter filter) {
|
| +namespace {
|
| +
|
| +void CollectEnumCacheTo(KeyAccumulator* keys, JSObject* object) {
|
| + // We can cache the computed property keys if access checks are
|
| + // not needed and no interceptors are involved.
|
| + //
|
| + // We do not use the cache if the object has elements and
|
| + // therefore it does not make sense to cache the property names
|
| + // for arguments objects. Arguments objects will always have
|
| + // elements.
|
| + // Wrapped strings have elements, but don't have an elements
|
| + // array or dictionary. So the fast inline test for whether to
|
| + // use the cache says yes, so we should not create a cache.
|
| + Isolate* isolate = keys->isolate();
|
| + Handle<JSFunction> arguments_function(
|
| + JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
|
| + bool cache_enum_length =
|
| + ((object->map()->GetConstructor() != *arguments_function) &&
|
| + !object->IsJSValue() && !object->IsAccessCheckNeeded() &&
|
| + !object->HasNamedInterceptor() && !object->HasIndexedInterceptor());
|
| + // Compute the property keys and cache them if possible.
|
| + Handle<FixedArray> enum_keys =
|
| + GetFastEnumPropertyKeys(isolate, object, cache_enum_length);
|
| + keys->AddKeys(enum_keys);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +void JSObject::CollectFastPropertyKeysTo(KeyAccumulator* keys,
|
| + PropertyFilter filter,
|
| + JSReceiver::KeyCollectionType type) {
|
| + // Avoid using the enum cache if we have to walk the prototype chain due
|
| + // to shadowing properties.
|
| + if (filter == ENUMERABLE_STRINGS && type == JSReceiver::OWN_ONLY) {
|
| + CollectEnumCacheTo(keys, this);
|
| + return;
|
| + }
|
| +
|
| + int real_size = map()->NumberOfOwnDescriptors();
|
| + Handle<DescriptorArray> descs(map()->instance_descriptors());
|
| + for (int i = 0; i < real_size; i++) {
|
| + PropertyDetails details = descs->GetDetails(i);
|
| + if ((details.attributes() & filter) != 0) {
|
| + if (type == JSReceiver::OWN_ONLY) continue;
|
| + if (details.attributes() & DONT_ENUM) {
|
| + keys->HideKey(descs->GetKey(i));
|
| + }
|
| + continue;
|
| + }
|
| + if (filter & ONLY_ALL_CAN_READ) {
|
| + if (details.kind() != kAccessor) continue;
|
| + Object* accessors = descs->GetValue(i);
|
| + if (!accessors->IsAccessorInfo()) continue;
|
| + if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
|
| + }
|
| + Name* key = descs->GetKey(i);
|
| + if (key->FilterKey(filter)) continue;
|
| + keys->AddKey(key);
|
| + }
|
| +}
|
| +
|
| +
|
| +void JSObject::CollectOwnPropertyKeys(KeyAccumulator* keys,
|
| + PropertyFilter filter,
|
| + JSReceiver::KeyCollectionType type) {
|
| if (HasFastProperties()) {
|
| - int real_size = map()->NumberOfOwnDescriptors();
|
| - Handle<DescriptorArray> descs(map()->instance_descriptors());
|
| - for (int i = 0; i < real_size; i++) {
|
| - PropertyDetails details = descs->GetDetails(i);
|
| - if ((details.attributes() & filter) != 0) continue;
|
| - if (filter & ONLY_ALL_CAN_READ) {
|
| - if (details.kind() != kAccessor) continue;
|
| - Object* accessors = descs->GetValue(i);
|
| - if (!accessors->IsAccessorInfo()) continue;
|
| - if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
|
| - }
|
| - Name* key = descs->GetKey(i);
|
| - if (key->FilterKey(filter)) continue;
|
| - keys->AddKey(key);
|
| - }
|
| + CollectFastPropertyKeysTo(keys, filter, type);
|
| } else if (IsJSGlobalObject()) {
|
| GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
|
| } else {
|
| @@ -18432,20 +18441,27 @@
|
| void Dictionary<Derived, Shape, Key>::CollectKeysTo(
|
| Handle<Dictionary<Derived, Shape, Key> > dictionary, KeyAccumulator* keys,
|
| PropertyFilter filter) {
|
| + if (dictionary->NumberOfElements() == 0) return;
|
| int capacity = dictionary->Capacity();
|
| Handle<FixedArray> array =
|
| keys->isolate()->factory()->NewFixedArray(dictionary->NumberOfElements());
|
| int array_size = 0;
|
| + std::vector<int> hidden_key_indices;
|
|
|
| {
|
| DisallowHeapAllocation no_gc;
|
| Dictionary<Derived, Shape, Key>* raw_dict = *dictionary;
|
| for (int i = 0; i < capacity; i++) {
|
| - Object* k = raw_dict->KeyAt(i);
|
| - if (!raw_dict->IsKey(k) || k->FilterKey(filter)) continue;
|
| + Object* key = raw_dict->KeyAt(i);
|
| + if (!raw_dict->IsKey(key) || key->FilterKey(filter)) continue;
|
| if (raw_dict->IsDeleted(i)) continue;
|
| PropertyDetails details = raw_dict->DetailsAt(i);
|
| - if ((details.attributes() & filter) != 0) continue;
|
| + if ((details.attributes() & filter) != 0) {
|
| + if (details.attributes() & DONT_ENUM) {
|
| + hidden_key_indices.push_back(i);
|
| + }
|
| + continue;
|
| + }
|
| if (filter & ONLY_ALL_CAN_READ) {
|
| if (details.kind() != kAccessor) continue;
|
| Object* accessors = raw_dict->ValueAt(i);
|
| @@ -18462,7 +18478,9 @@
|
| Smi** start = reinterpret_cast<Smi**>(array->GetFirstElementAddress());
|
| std::sort(start, start + array_size, cmp);
|
| }
|
| -
|
| + for (uint32_t i = 0; i < hidden_key_indices.size(); i++) {
|
| + keys->HideKey(dictionary->KeyAt(hidden_key_indices[i]));
|
| + }
|
| for (int i = 0; i < array_size; i++) {
|
| int index = Smi::cast(array->get(i))->value();
|
| keys->AddKey(dictionary->KeyAt(index));
|
|
|