| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index ca941ce4e21a0c6c0a6b6eb9cc54e8ffd3441054..172538c061601b64d8fbec4f4c3d80b52ec19d22 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -6612,91 +6612,90 @@ static Handle<FixedArray> ReduceFixedArrayTo(
|
| }
|
|
|
|
|
| -Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object,
|
| - bool cache_result) {
|
| - Isolate* isolate = object->GetIsolate();
|
| - if (object->HasFastProperties()) {
|
| - int own_property_count = object->map()->EnumLength();
|
| - // If the enum length of the given map is set to kInvalidEnumCache, this
|
| - // means that the map itself has never used the present enum cache. The
|
| - // first step to using the cache is to set the enum length of the map by
|
| - // counting the number of own descriptors that are not DONT_ENUM or
|
| - // SYMBOLIC.
|
| - if (own_property_count == kInvalidEnumCacheSentinel) {
|
| - own_property_count = object->map()->NumberOfDescribedProperties(
|
| - OWN_DESCRIPTORS, DONT_SHOW);
|
| - } else {
|
| - DCHECK(own_property_count == object->map()->NumberOfDescribedProperties(
|
| - OWN_DESCRIPTORS, DONT_SHOW));
|
| - }
|
| -
|
| - if (object->map()->instance_descriptors()->HasEnumCache()) {
|
| - DescriptorArray* desc = object->map()->instance_descriptors();
|
| - Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
|
| -
|
| - // In case the number of properties required in the enum are actually
|
| - // present, we can reuse the enum cache. Otherwise, this means that the
|
| - // enum cache was generated for a previous (smaller) version of the
|
| - // Descriptor Array. In that case we regenerate the enum cache.
|
| - if (own_property_count <= keys->length()) {
|
| - if (cache_result) object->map()->SetEnumLength(own_property_count);
|
| - isolate->counters()->enum_cache_hits()->Increment();
|
| - return ReduceFixedArrayTo(keys, own_property_count);
|
| - }
|
| - }
|
| +namespace {
|
|
|
| - Handle<Map> map(object->map());
|
| +Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
|
| + Handle<JSObject> object,
|
| + bool cache_enum_length) {
|
| + Handle<Map> map(object->map());
|
| + Handle<DescriptorArray> descs =
|
| + Handle<DescriptorArray>(map->instance_descriptors(), isolate);
|
| + int own_property_count = map->EnumLength();
|
| + // If the enum length of the given map is set to kInvalidEnumCache, this
|
| + // means that the map itself has never used the present enum cache. The
|
| + // first step to using the cache is to set the enum length of the map by
|
| + // counting the number of own descriptors that are not DONT_ENUM or
|
| + // SYMBOLIC.
|
| + if (own_property_count == kInvalidEnumCacheSentinel) {
|
| + own_property_count =
|
| + map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW);
|
| + } else {
|
| + DCHECK(own_property_count ==
|
| + map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW));
|
| + }
|
|
|
| - if (map->instance_descriptors()->IsEmpty()) {
|
| + if (descs->HasEnumCache()) {
|
| + Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
|
| + // In case the number of properties required in the enum are actually
|
| + // present, we can reuse the enum cache. Otherwise, this means that the
|
| + // enum cache was generated for a previous (smaller) version of the
|
| + // Descriptor Array. In that case we regenerate the enum cache.
|
| + if (own_property_count <= keys->length()) {
|
| isolate->counters()->enum_cache_hits()->Increment();
|
| - if (cache_result) map->SetEnumLength(0);
|
| - return isolate->factory()->empty_fixed_array();
|
| + if (cache_enum_length) map->SetEnumLength(own_property_count);
|
| + return ReduceFixedArrayTo(keys, own_property_count);
|
| }
|
| + }
|
|
|
| - isolate->counters()->enum_cache_misses()->Increment();
|
| + if (descs->IsEmpty()) {
|
| + isolate->counters()->enum_cache_hits()->Increment();
|
| + if (cache_enum_length) map->SetEnumLength(0);
|
| + return isolate->factory()->empty_fixed_array();
|
| + }
|
|
|
| - Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
|
| - own_property_count);
|
| - Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
|
| - own_property_count);
|
| + isolate->counters()->enum_cache_misses()->Increment();
|
|
|
| - Handle<DescriptorArray> descs =
|
| - Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
|
| + Handle<FixedArray> storage =
|
| + isolate->factory()->NewFixedArray(own_property_count);
|
| + Handle<FixedArray> indices =
|
| + isolate->factory()->NewFixedArray(own_property_count);
|
|
|
| - int size = map->NumberOfOwnDescriptors();
|
| - int index = 0;
|
| + int size = map->NumberOfOwnDescriptors();
|
| + int index = 0;
|
|
|
| - for (int i = 0; i < size; i++) {
|
| - PropertyDetails details = descs->GetDetails(i);
|
| - Object* key = descs->GetKey(i);
|
| - if (!(details.IsDontEnum() || key->IsSymbol())) {
|
| - storage->set(index, key);
|
| - if (!indices.is_null()) {
|
| - if (details.type() != DATA) {
|
| - indices = Handle<FixedArray>();
|
| - } else {
|
| - FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
|
| - int load_by_field_index = field_index.GetLoadByFieldIndex();
|
| - indices->set(index, Smi::FromInt(load_by_field_index));
|
| - }
|
| - }
|
| - index++;
|
| + for (int i = 0; i < size; i++) {
|
| + PropertyDetails details = descs->GetDetails(i);
|
| + Object* key = descs->GetKey(i);
|
| + if (details.IsDontEnum() || key->IsSymbol()) continue;
|
| + storage->set(index, key);
|
| + if (!indices.is_null()) {
|
| + if (details.type() != DATA) {
|
| + indices = Handle<FixedArray>();
|
| + } else {
|
| + FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
|
| + int load_by_field_index = field_index.GetLoadByFieldIndex();
|
| + indices->set(index, Smi::FromInt(load_by_field_index));
|
| }
|
| }
|
| - DCHECK(index == storage->length());
|
| + index++;
|
| + }
|
| + DCHECK(index == storage->length());
|
|
|
| - Handle<FixedArray> bridge_storage =
|
| - isolate->factory()->NewFixedArray(
|
| - DescriptorArray::kEnumCacheBridgeLength);
|
| - DescriptorArray* desc = object->map()->instance_descriptors();
|
| - desc->SetEnumCache(*bridge_storage,
|
| - *storage,
|
| - indices.is_null() ? Object::cast(Smi::FromInt(0))
|
| - : Object::cast(*indices));
|
| - if (cache_result) {
|
| - object->map()->SetEnumLength(own_property_count);
|
| - }
|
| - return storage;
|
| + DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
|
| + if (cache_enum_length) {
|
| + map->SetEnumLength(own_property_count);
|
| + }
|
| + return storage;
|
| +}
|
| +
|
| +} // 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->IsGlobalObject()) {
|
| Handle<GlobalDictionary> dictionary(object->global_dictionary());
|
| int length = dictionary->NumberOfEnumElements();
|
| @@ -6900,14 +6899,14 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
|
| // 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.
|
| - bool cache_enum_keys =
|
| + bool cache_enum_length =
|
| ((current->map()->GetConstructor() != *arguments_function) &&
|
| !current->IsJSValue() && !current->IsAccessCheckNeeded() &&
|
| !current->HasNamedInterceptor() && !current->HasIndexedInterceptor());
|
| // Compute the property keys and cache them if possible.
|
|
|
| Handle<FixedArray> enum_keys =
|
| - JSObject::GetEnumPropertyKeys(current, cache_enum_keys);
|
| + JSObject::GetEnumPropertyKeys(current, cache_enum_length);
|
| accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS);
|
| DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
|
|
|
| @@ -8660,18 +8659,27 @@ void DescriptorArray::Replace(int index, Descriptor* descriptor) {
|
| }
|
|
|
|
|
| -void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
|
| - FixedArray* new_cache,
|
| - Object* new_index_cache) {
|
| - DCHECK(bridge_storage->length() >= kEnumCacheBridgeLength);
|
| - DCHECK(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
|
| - DCHECK(!IsEmpty());
|
| - DCHECK(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
|
| - FixedArray::cast(bridge_storage)->
|
| - set(kEnumCacheBridgeCacheIndex, new_cache);
|
| - FixedArray::cast(bridge_storage)->
|
| - set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
|
| - set(kEnumCacheIndex, bridge_storage);
|
| +// static
|
| +void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
|
| + Isolate* isolate,
|
| + Handle<FixedArray> new_cache,
|
| + Handle<FixedArray> new_index_cache) {
|
| + DCHECK(!descriptors->IsEmpty());
|
| + FixedArray* bridge_storage;
|
| + bool needs_new_enum_cache = !descriptors->HasEnumCache();
|
| + if (needs_new_enum_cache) {
|
| + bridge_storage = *isolate->factory()->NewFixedArray(
|
| + DescriptorArray::kEnumCacheBridgeLength);
|
| + } else {
|
| + bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex));
|
| + }
|
| + bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
|
| + bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex,
|
| + new_index_cache.is_null() ? Object::cast(Smi::FromInt(0))
|
| + : *new_index_cache);
|
| + if (needs_new_enum_cache) {
|
| + descriptors->set(kEnumCacheIndex, bridge_storage);
|
| + }
|
| }
|
|
|
|
|
|
|