| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index aa48edb36570bce4e4c7c33911afa611c3f0e4dd..02d8d3481f636d0b90702251b59684cde3eb8861 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -6568,90 +6568,91 @@
|
| }
|
|
|
|
|
| -namespace {
|
| -
|
| -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 (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_enum_length) map->SetEnumLength(own_property_count);
|
| - return ReduceFixedArrayTo(keys, own_property_count);
|
| - }
|
| - }
|
| -
|
| - if (descs->IsEmpty()) {
|
| - isolate->counters()->enum_cache_hits()->Increment();
|
| - if (cache_enum_length) map->SetEnumLength(0);
|
| - return isolate->factory()->empty_fixed_array();
|
| - }
|
| -
|
| - isolate->counters()->enum_cache_misses()->Increment();
|
| -
|
| - 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;
|
| -
|
| - 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));
|
| - }
|
| - }
|
| - index++;
|
| - }
|
| - DCHECK(index == storage->length());
|
| -
|
| - descs->SetEnumCache(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) {
|
| + bool cache_result) {
|
| Isolate* isolate = object->GetIsolate();
|
| if (object->HasFastProperties()) {
|
| - return GetFastEnumPropertyKeys(isolate, object, cache_enum_length);
|
| + 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);
|
| + }
|
| + }
|
| +
|
| + Handle<Map> map(object->map());
|
| +
|
| + if (map->instance_descriptors()->IsEmpty()) {
|
| + isolate->counters()->enum_cache_hits()->Increment();
|
| + if (cache_result) map->SetEnumLength(0);
|
| + return isolate->factory()->empty_fixed_array();
|
| + }
|
| +
|
| + isolate->counters()->enum_cache_misses()->Increment();
|
| +
|
| + Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
|
| + own_property_count);
|
| + Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
|
| + own_property_count);
|
| +
|
| + Handle<DescriptorArray> descs =
|
| + Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
|
| +
|
| + 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++;
|
| + }
|
| + }
|
| + 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;
|
| } else if (object->IsGlobalObject()) {
|
| Handle<GlobalDictionary> dictionary(object->global_dictionary());
|
| int length = dictionary->NumberOfEnumElements();
|
| @@ -6855,14 +6856,14 @@
|
| // 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_length =
|
| + bool cache_enum_keys =
|
| ((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_length);
|
| + JSObject::GetEnumPropertyKeys(current, cache_enum_keys);
|
| accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS);
|
| DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys()));
|
|
|
| @@ -8615,25 +8616,18 @@
|
| }
|
|
|
|
|
| -void DescriptorArray::SetEnumCache(Isolate* isolate,
|
| - Handle<FixedArray> new_cache,
|
| - Handle<FixedArray> new_index_cache) {
|
| +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());
|
| - FixedArray* bridge_storage;
|
| - bool needs_new_enum_cache = !HasEnumCache();
|
| - if (needs_new_enum_cache) {
|
| - bridge_storage = *isolate->factory()->NewFixedArray(
|
| - DescriptorArray::kEnumCacheBridgeLength);
|
| - } else {
|
| - bridge_storage = FixedArray::cast(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) {
|
| - set(kEnumCacheIndex, bridge_storage);
|
| - }
|
| + 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);
|
| }
|
|
|
|
|
|
|