Chromium Code Reviews

Unified Diff: src/objects.cc

Issue 1751643003: [esnext] use map instance_descriptors() when possible in Object.values/entries() (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@ObjectValuesEntriesPerf
Patch Set: Trial: handle elements even in "fast" case, in order to still take advantage? Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index b626e447b75a48cdccb0398b98ebd512610e1157..1f62435029038c2f5ca4324e2a8455ba29250878 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -8835,10 +8835,155 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
return keys;
}
+MUST_USE_RESULT Maybe<bool> GetOwnElementValuesOrEntries(
+ Isolate* isolate, Handle<JSObject> object, bool get_entries,
+ Handle<FixedArray> values_or_entries, int num_elements, int* count) {
+ Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
+ object->GetOwnElementKeys(*keys, ENUMERABLE_STRINGS);
+
+ int elements = 0;
+
+ for (int i = 0; i < num_elements; ++i) {
+ Handle<Object> next_key(keys->get(i), isolate);
+ Handle<Object> prop_value;
+
+ bool success;
+ LookupIterator it =
+ LookupIterator::PropertyOrElement(isolate, object, next_key, &success,
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
Camillo Bruni 2016/03/04 09:40:25 I think you will only have the full benefits when
caitp (gmail) 2016/03/04 16:34:33 Acknowledged.
+ USE(success);
+
+ if (!it.IsFound()) continue;
+ DCHECK(it.state() == LookupIterator::DATA ||
+ it.state() == LookupIterator::ACCESSOR);
+ if (!it.IsEnumerable()) continue;
Camillo Bruni 2016/03/04 09:40:25 For instance the enumerability check would only be
caitp (gmail) 2016/03/04 16:34:33 Acknowledged.
+
+ PropertyDetails details = it.property_details();
+ if (details.kind() == kData) {
+ prop_value = it.GetDataValue();
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
Camillo Bruni 2016/03/04 09:40:25 Same here, you can only have a getter with DICTION
caitp (gmail) 2016/03/04 16:34:33 Acknowledged.
+ }
+
+ if (get_entries) {
+ Handle<FixedArray> entry_storage =
+ isolate->factory()->NewUninitializedFixedArray(2);
+
+ if (!next_key->IsName()) {
Camillo Bruni 2016/03/04 09:40:25 element keys should always be Numbers. DCHECK(next
caitp (gmail) 2016/03/04 16:34:33 Dictionary gave me the impression that they could
Camillo Bruni 2016/03/04 17:23:26 Sure :). DICTIONARY_ELEMENTS is used for elements
+ DCHECK(next_key->IsNumber());
+ Handle<String> property_name;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, property_name,
+ Object::ToString(isolate, next_key),
+ Nothing<bool>());
+ next_key = property_name;
+ }
+ entry_storage->set(0, *next_key);
+ entry_storage->set(1, *prop_value);
+ prop_value = isolate->factory()->NewJSArrayWithElements(entry_storage,
+ FAST_ELEMENTS, 2);
+ }
+
+ values_or_entries->set(elements, *prop_value);
+ elements++;
+ }
+
+ *count = elements;
+ return Just(true);
+}
+
+MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
+ Isolate* isolate, Handle<JSObject> object, bool get_entries,
+ Handle<FixedArray>* result) {
+ Handle<Map> map(JSReceiver::cast(*object)->map(), isolate);
+
+ if (!map->IsJSObjectMap()) return Just(false);
+ if (!map->OnlyHasSimpleProperties()) return Just(false);
+
+ Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate);
+ int length = map->NumberOfOwnDescriptors();
+ int elements_length = object->NumberOfOwnElements(ENUMERABLE_STRINGS);
+ Handle<FixedArray> values_or_entries =
+ isolate->factory()->NewFixedArray(length + elements_length);
+ int count = 0;
+
+ bool stable = true;
+
+ if (object->elements() != isolate->heap()->empty_fixed_array()) {
+ MAYBE_RETURN(GetOwnElementValuesOrEntries(isolate, object, get_entries,
+ values_or_entries,
+ elements_length, &count),
+ Nothing<bool>());
+ stable = object->map() == *map;
+ }
+
+ for (int index = 0; index < length; index++) {
+ Handle<Name> next_key(descriptors->GetKey(index), isolate);
+ if (!next_key->IsString()) continue;
+ Handle<Object> prop_value;
+
+ // Directly decode from the descriptor array if |from| did not change shape.
+ if (stable) {
+ PropertyDetails details = descriptors->GetDetails(index);
+ if (!details.IsEnumerable()) continue;
+ if (details.kind() == kData) {
+ if (details.location() == kDescriptor) {
+ prop_value = handle(descriptors->GetValue(index), isolate);
+ } else {
+ Representation representation = details.representation();
+ FieldIndex field_index = FieldIndex::ForDescriptor(*map, index);
+ prop_value =
+ JSObject::FastPropertyAt(object, representation, field_index);
+ }
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, prop_value,
+ Object::GetProperty(object, next_key),
+ Nothing<bool>());
+ stable = object->map() == *map;
+ }
+ } else {
+ // If the map did change, do a slower lookup. We are still guaranteed that
+ // the object has a simple shape, and that the key is a name.
+ LookupIterator it(object, next_key, LookupIterator::OWN_SKIP_INTERCEPTOR);
+ if (!it.IsFound()) continue;
+ DCHECK(it.state() == LookupIterator::DATA ||
+ it.state() == LookupIterator::ACCESSOR);
+ if (!it.IsEnumerable()) continue;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, prop_value, Object::GetProperty(&it), Nothing<bool>());
+ }
+
+ if (get_entries) {
+ Handle<FixedArray> entry_storage =
+ isolate->factory()->NewUninitializedFixedArray(2);
+ entry_storage->set(0, *next_key);
+ entry_storage->set(1, *prop_value);
+ prop_value = isolate->factory()->NewJSArrayWithElements(entry_storage,
+ FAST_ELEMENTS, 2);
+ }
+
+ values_or_entries->set(count, *prop_value);
+ count++;
+ }
+
+ if (count < values_or_entries->length()) values_or_entries->Shrink(count);
+ *result = values_or_entries;
+ return Just(true);
+}
+
MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
Handle<JSReceiver> object,
PropertyFilter filter,
bool get_entries) {
+ Handle<FixedArray> values_or_entries;
+ if (filter == ENUMERABLE_STRINGS && object->IsJSObject()) {
+ Maybe<bool> fast_values_or_entries =
+ FastGetOwnValuesOrEntries(isolate, Handle<JSObject>::cast(object),
+ get_entries, &values_or_entries);
+ if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
+ if (fast_values_or_entries.FromJust()) return values_or_entries;
+ }
+
PropertyFilter key_filter =
static_cast<PropertyFilter>(filter & ~ONLY_ENUMERABLE);
KeyAccumulator accumulator(isolate, OWN_ONLY, key_filter);
@@ -8848,8 +8993,7 @@ MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
Handle<FixedArray> keys = accumulator.GetKeys(CONVERT_TO_STRING);
DCHECK(ContainsOnlyValidKeys(keys));
- Handle<FixedArray> values_or_entries =
- isolate->factory()->NewFixedArray(keys->length());
+ values_or_entries = isolate->factory()->NewFixedArray(keys->length());
int length = 0;
for (int i = 0; i < keys->length(); ++i) {
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine