Commit ba5a6196 authored by cbruni's avatar cbruni Committed by Commit bot

[elements] Avoid using IsKey in loops

IsKey is much slower compare to direct comparisons with undefined_value
and the_hole_value.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#35209}
parent eaa92feb
...@@ -1039,7 +1039,8 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range, ...@@ -1039,7 +1039,8 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
case FAST_ELEMENTS: case FAST_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS: { case FAST_HOLEY_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements())); DisallowHeapAllocation no_gc;
FixedArray* elements = FixedArray::cast(object->elements());
uint32_t length = static_cast<uint32_t>(elements->length()); uint32_t length = static_cast<uint32_t>(elements->length());
if (range < length) length = range; if (range < length) length = range;
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
...@@ -1067,17 +1068,21 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range, ...@@ -1067,17 +1068,21 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
break; break;
} }
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
Handle<SeededNumberDictionary> dict( DisallowHeapAllocation no_gc;
SeededNumberDictionary::cast(object->elements())); SeededNumberDictionary* dict =
SeededNumberDictionary::cast(object->elements());
uint32_t capacity = dict->Capacity(); uint32_t capacity = dict->Capacity();
Heap* heap = isolate->heap();
Object* undefined = heap->undefined_value();
Object* the_hole = heap->the_hole_value();
FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, { FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, {
Handle<Object> k(dict->KeyAt(j), isolate); Object* k = dict->KeyAt(j);
if (dict->IsKey(*k)) { if (k == undefined) continue;
DCHECK(k->IsNumber()); if (k == the_hole) continue;
uint32_t index = static_cast<uint32_t>(k->Number()); DCHECK(k->IsNumber());
if (index < range) { uint32_t index = static_cast<uint32_t>(k->Number());
indices->Add(index); if (index < range) {
} indices->Add(index);
} }
}); });
break; break;
...@@ -1410,6 +1415,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, ...@@ -1410,6 +1415,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
double_storage->set(j, obj->Number()); double_storage->set(j, obj->Number());
j++; j++;
} else { } else {
DisallowHeapAllocation no_gc;
JSArray* array = JSArray::cast(*obj); JSArray* array = JSArray::cast(*obj);
uint32_t length = static_cast<uint32_t>(array->length()->Number()); uint32_t length = static_cast<uint32_t>(array->length()->Number());
switch (array->GetElementsKind()) { switch (array->GetElementsKind()) {
...@@ -1437,10 +1443,11 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, ...@@ -1437,10 +1443,11 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
} }
case FAST_HOLEY_SMI_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS:
case FAST_SMI_ELEMENTS: { case FAST_SMI_ELEMENTS: {
Object* the_hole = isolate->heap()->the_hole_value();
FixedArray* elements(FixedArray::cast(array->elements())); FixedArray* elements(FixedArray::cast(array->elements()));
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
Object* element = elements->get(i); Object* element = elements->get(i);
if (element->IsTheHole()) { if (element == the_hole) {
failure = true; failure = true;
break; break;
} }
...@@ -1530,11 +1537,10 @@ MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { ...@@ -1530,11 +1537,10 @@ MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) {
for (int i = 0; i < n_arguments; i++) { for (int i = 0; i < n_arguments; i++) {
Object* arg = (*args)[i]; Object* arg = (*args)[i];
if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); if (!arg->IsJSArray()) return MaybeHandle<JSArray>();
if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { if (!JSObject::cast(arg)->HasFastElements()) {
return MaybeHandle<JSArray>(); return MaybeHandle<JSArray>();
} }
// TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) {
if (!JSObject::cast(arg)->HasFastElements()) {
return MaybeHandle<JSArray>(); return MaybeHandle<JSArray>();
} }
Handle<JSArray> array(JSArray::cast(arg), isolate); Handle<JSArray> array(JSArray::cast(arg), isolate);
......
...@@ -1192,12 +1192,16 @@ class DictionaryElementsAccessor ...@@ -1192,12 +1192,16 @@ class DictionaryElementsAccessor
static bool HasAccessorsImpl(JSObject* holder, static bool HasAccessorsImpl(JSObject* holder,
FixedArrayBase* backing_store) { FixedArrayBase* backing_store) {
DisallowHeapAllocation no_gc;
SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store); SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
if (!dict->requires_slow_elements()) return false; if (!dict->requires_slow_elements()) return false;
int capacity = dict->Capacity(); int capacity = dict->Capacity();
Heap* heap = holder->GetHeap();
Object* undefined = heap->undefined_value();
Object* the_hole = heap->the_hole_value();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* key = dict->KeyAt(i); Object* key = dict->KeyAt(i);
if (!dict->IsKey(key)) continue; if (key == the_hole || key == undefined) continue;
DCHECK(!dict->IsDeleted(i)); DCHECK(!dict->IsDeleted(i));
PropertyDetails details = dict->DetailsAt(i); PropertyDetails details = dict->DetailsAt(i);
if (details.type() == ACCESSOR_CONSTANT) return true; if (details.type() == ACCESSOR_CONSTANT) return true;
...@@ -1296,11 +1300,8 @@ class DictionaryElementsAccessor ...@@ -1296,11 +1300,8 @@ class DictionaryElementsAccessor
return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry); return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
} }
static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary, static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
int entry, PropertyFilter filter) { int entry, Object* raw_key, PropertyFilter filter) {
DisallowHeapAllocation no_gc;
Object* raw_key = dictionary->KeyAt(entry);
if (!dictionary->IsKey(raw_key)) return kMaxUInt32;
DCHECK(!dictionary->IsDeleted(entry)); DCHECK(!dictionary->IsDeleted(entry));
DCHECK(raw_key->IsNumber()); DCHECK(raw_key->IsNumber());
DCHECK_LE(raw_key->Number(), kMaxUInt32); DCHECK_LE(raw_key->Number(), kMaxUInt32);
...@@ -1310,17 +1311,41 @@ class DictionaryElementsAccessor ...@@ -1310,17 +1311,41 @@ class DictionaryElementsAccessor
return static_cast<uint32_t>(raw_key->Number()); return static_cast<uint32_t>(raw_key->Number());
} }
static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
int entry, PropertyFilter filter) {
DisallowHeapAllocation no_gc;
Object* raw_key = dictionary->KeyAt(entry);
if (!dictionary->IsKey(raw_key)) return kMaxUInt32;
return FilterKey(dictionary, entry, raw_key, filter);
}
static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary,
int entry, PropertyFilter filter,
Object* undefined, Object* the_hole) {
DisallowHeapAllocation no_gc;
Object* raw_key = dictionary->KeyAt(entry);
// Replace the IsKey check with a direct comparison which is much faster.
if (raw_key == undefined || raw_key == the_hole) {
return kMaxUInt32;
}
return FilterKey(dictionary, entry, raw_key, filter);
}
static void CollectElementIndicesImpl(Handle<JSObject> object, static void CollectElementIndicesImpl(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store, Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range, KeyAccumulator* keys, uint32_t range,
PropertyFilter filter, PropertyFilter filter,
uint32_t offset) { uint32_t offset) {
if (filter & SKIP_STRINGS) return; if (filter & SKIP_STRINGS) return;
Isolate* isolate = keys->isolate();
Handle<Object> undefined = isolate->factory()->undefined_value();
Handle<Object> the_hole = isolate->factory()->the_hole_value();
Handle<SeededNumberDictionary> dictionary = Handle<SeededNumberDictionary> dictionary =
Handle<SeededNumberDictionary>::cast(backing_store); Handle<SeededNumberDictionary>::cast(backing_store);
int capacity = dictionary->Capacity(); int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
uint32_t key = GetKeyForEntryImpl(dictionary, i, filter); uint32_t key =
GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole);
if (key == kMaxUInt32) continue; if (key == kMaxUInt32) continue;
keys->AddKey(key); keys->AddKey(key);
} }
...@@ -1335,11 +1360,15 @@ class DictionaryElementsAccessor ...@@ -1335,11 +1360,15 @@ class DictionaryElementsAccessor
uint32_t insertion_index = 0) { uint32_t insertion_index = 0) {
if (filter & SKIP_STRINGS) return list; if (filter & SKIP_STRINGS) return list;
if (filter & ONLY_ALL_CAN_READ) return list; if (filter & ONLY_ALL_CAN_READ) return list;
Handle<Object> undefined = isolate->factory()->undefined_value();
Handle<Object> the_hole = isolate->factory()->the_hole_value();
Handle<SeededNumberDictionary> dictionary = Handle<SeededNumberDictionary> dictionary =
Handle<SeededNumberDictionary>::cast(backing_store); Handle<SeededNumberDictionary>::cast(backing_store);
uint32_t capacity = dictionary->Capacity(); uint32_t capacity = dictionary->Capacity();
for (uint32_t i = 0; i < capacity; i++) { for (uint32_t i = 0; i < capacity; i++) {
uint32_t key = GetKeyForEntryImpl(dictionary, i, filter); uint32_t key =
GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole);
if (key == kMaxUInt32) continue; if (key == kMaxUInt32) continue;
Handle<Object> index = isolate->factory()->NewNumberFromUint(key); Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
list->set(insertion_index, *index); list->set(insertion_index, *index);
...@@ -1352,12 +1381,16 @@ class DictionaryElementsAccessor ...@@ -1352,12 +1381,16 @@ class DictionaryElementsAccessor
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator, KeyAccumulator* accumulator,
AddKeyConversion convert) { AddKeyConversion convert) {
Isolate* isolate = accumulator->isolate();
Handle<Object> undefined = isolate->factory()->undefined_value();
Handle<Object> the_hole = isolate->factory()->the_hole_value();
SeededNumberDictionary* dictionary = SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(receiver->elements()); SeededNumberDictionary::cast(receiver->elements());
int capacity = dictionary->Capacity(); int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) { for (int i = 0; i < capacity; i++) {
Object* k = dictionary->KeyAt(i); Object* k = dictionary->KeyAt(i);
if (!dictionary->IsKey(k)) continue; if (k == *undefined) continue;
if (k == *the_hole) continue;
if (dictionary->IsDeleted(i)) continue; if (dictionary->IsDeleted(i)) continue;
Object* value = dictionary->ValueAt(i); Object* value = dictionary->ValueAt(i);
DCHECK(!value->IsTheHole()); DCHECK(!value->IsTheHole());
......
...@@ -2998,6 +2998,9 @@ int HashTableBase::ComputeCapacity(int at_least_space_for) { ...@@ -2998,6 +2998,9 @@ int HashTableBase::ComputeCapacity(int at_least_space_for) {
return Max(capacity, kMinCapacity); return Max(capacity, kMinCapacity);
} }
bool HashTableBase::IsKey(Heap* heap, Object* k) {
return k != heap->the_hole_value() && k != heap->undefined_value();
}
bool HashTableBase::IsKey(Object* k) { bool HashTableBase::IsKey(Object* k) {
return !k->IsTheHole() && !k->IsUndefined(); return !k->IsTheHole() && !k->IsUndefined();
......
...@@ -3211,6 +3211,7 @@ class HashTableBase : public FixedArray { ...@@ -3211,6 +3211,7 @@ class HashTableBase : public FixedArray {
// Tells whether k is a real key. The hole and undefined are not allowed // Tells whether k is a real key. The hole and undefined are not allowed
// as keys and can be used to indicate missing or deleted elements. // as keys and can be used to indicate missing or deleted elements.
inline bool IsKey(Object* k); inline bool IsKey(Object* k);
inline bool IsKey(Heap* heap, Object* k);
// Compute the probe offset (quadratic probing). // Compute the probe offset (quadratic probing).
INLINE(static uint32_t GetProbeOffset(uint32_t n)) { INLINE(static uint32_t GetProbeOffset(uint32_t n)) {
......
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