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,
case FAST_ELEMENTS:
case FAST_HOLEY_SMI_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());
if (range < length) length = range;
for (uint32_t i = 0; i < length; i++) {
......@@ -1067,17 +1068,21 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
break;
}
case DICTIONARY_ELEMENTS: {
Handle<SeededNumberDictionary> dict(
SeededNumberDictionary::cast(object->elements()));
DisallowHeapAllocation no_gc;
SeededNumberDictionary* dict =
SeededNumberDictionary::cast(object->elements());
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++, {
Handle<Object> k(dict->KeyAt(j), isolate);
if (dict->IsKey(*k)) {
DCHECK(k->IsNumber());
uint32_t index = static_cast<uint32_t>(k->Number());
if (index < range) {
indices->Add(index);
}
Object* k = dict->KeyAt(j);
if (k == undefined) continue;
if (k == the_hole) continue;
DCHECK(k->IsNumber());
uint32_t index = static_cast<uint32_t>(k->Number());
if (index < range) {
indices->Add(index);
}
});
break;
......@@ -1410,6 +1415,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
double_storage->set(j, obj->Number());
j++;
} else {
DisallowHeapAllocation no_gc;
JSArray* array = JSArray::cast(*obj);
uint32_t length = static_cast<uint32_t>(array->length()->Number());
switch (array->GetElementsKind()) {
......@@ -1437,10 +1443,11 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
}
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_SMI_ELEMENTS: {
Object* the_hole = isolate->heap()->the_hole_value();
FixedArray* elements(FixedArray::cast(array->elements()));
for (uint32_t i = 0; i < length; i++) {
Object* element = elements->get(i);
if (element->IsTheHole()) {
if (element == the_hole) {
failure = true;
break;
}
......@@ -1530,11 +1537,10 @@ MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) {
for (int i = 0; i < n_arguments; i++) {
Object* arg = (*args)[i];
if (!arg->IsJSArray()) return MaybeHandle<JSArray>();
if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) {
if (!JSObject::cast(arg)->HasFastElements()) {
return MaybeHandle<JSArray>();
}
// TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS.
if (!JSObject::cast(arg)->HasFastElements()) {
if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) {
return MaybeHandle<JSArray>();
}
Handle<JSArray> array(JSArray::cast(arg), isolate);
......
......@@ -1192,12 +1192,16 @@ class DictionaryElementsAccessor
static bool HasAccessorsImpl(JSObject* holder,
FixedArrayBase* backing_store) {
DisallowHeapAllocation no_gc;
SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store);
if (!dict->requires_slow_elements()) return false;
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++) {
Object* key = dict->KeyAt(i);
if (!dict->IsKey(key)) continue;
if (key == the_hole || key == undefined) continue;
DCHECK(!dict->IsDeleted(i));
PropertyDetails details = dict->DetailsAt(i);
if (details.type() == ACCESSOR_CONSTANT) return true;
......@@ -1296,11 +1300,8 @@ class DictionaryElementsAccessor
return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
}
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;
static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
int entry, Object* raw_key, PropertyFilter filter) {
DCHECK(!dictionary->IsDeleted(entry));
DCHECK(raw_key->IsNumber());
DCHECK_LE(raw_key->Number(), kMaxUInt32);
......@@ -1310,17 +1311,41 @@ class DictionaryElementsAccessor
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,
Handle<FixedArrayBase> backing_store,
KeyAccumulator* keys, uint32_t range,
PropertyFilter filter,
uint32_t offset) {
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>::cast(backing_store);
int capacity = dictionary->Capacity();
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;
keys->AddKey(key);
}
......@@ -1335,11 +1360,15 @@ class DictionaryElementsAccessor
uint32_t insertion_index = 0) {
if (filter & SKIP_STRINGS) 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>::cast(backing_store);
uint32_t capacity = dictionary->Capacity();
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;
Handle<Object> index = isolate->factory()->NewNumberFromUint(key);
list->set(insertion_index, *index);
......@@ -1352,12 +1381,16 @@ class DictionaryElementsAccessor
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
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::cast(receiver->elements());
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; 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;
Object* value = dictionary->ValueAt(i);
DCHECK(!value->IsTheHole());
......
......@@ -2998,6 +2998,9 @@ int HashTableBase::ComputeCapacity(int at_least_space_for) {
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) {
return !k->IsTheHole() && !k->IsUndefined();
......
......@@ -3211,6 +3211,7 @@ class HashTableBase : public FixedArray {
// 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.
inline bool IsKey(Object* k);
inline bool IsKey(Heap* heap, Object* k);
// Compute the probe offset (quadratic probing).
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