Commit 4988e42e authored by cbruni's avatar cbruni Committed by Commit bot

JSObject::GetEnumProperty cleanup

BUG=

Committed: https://crrev.com/a00d47c802f93cf9835eafce4c9da2dd10b44f6a
Cr-Commit-Position: refs/heads/master@{#30946}

Review URL: https://codereview.chromium.org/1363293002

Cr-Commit-Position: refs/heads/master@{#31018}
parent 9e0e7273
......@@ -89,8 +89,7 @@ inline int FieldIndex::GetLoadByFieldIndex() const {
inline FieldIndex FieldIndex::ForDescriptor(Map* map, int descriptor_index) {
PropertyDetails details =
map->instance_descriptors()->GetDetails(descriptor_index);
int field_index =
map->instance_descriptors()->GetFieldIndex(descriptor_index);
int field_index = details.field_index();
return ForPropertyIndex(map, field_index,
details.representation().IsDouble());
}
......
......@@ -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);
}
}
......
......@@ -2768,9 +2768,9 @@ class DescriptorArray: public FixedArray {
// Initialize or change the enum cache,
// using the supplied storage for the small "bridge".
void SetEnumCache(FixedArray* bridge_storage,
FixedArray* new_cache,
Object* new_index_cache);
static void SetEnumCache(Handle<DescriptorArray> descriptors,
Isolate* isolate, Handle<FixedArray> new_cache,
Handle<FixedArray> new_index_cache);
bool CanHoldValue(int descriptor, Object* value);
......
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