Index: src/elements.cc |
diff --git a/src/elements.cc b/src/elements.cc |
index 29fa4fb08c8bdaef6bda5d26794b4deab44a962c..56d800168de6fc1c6e7747c9e5cb7fd34d1eb438 100644 |
--- a/src/elements.cc |
+++ b/src/elements.cc |
@@ -489,6 +489,26 @@ static Maybe<bool> IncludesValueSlowPath(Isolate* isolate, |
return Just(false); |
} |
+static Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, |
+ uint32_t length) { |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ LookupIterator it(isolate, receiver, k); |
+ if (!it.IsFound()) { |
+ continue; |
+ } |
+ Handle<Object> element_k; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, element_k, Object::GetProperty(&it), Nothing<int64_t>()); |
+ |
+ if (value->StrictEquals(*element_k)) return Just<int64_t>(k); |
+ } |
+ |
+ return Just<int64_t>(-1); |
+} |
+ |
// Base class for element handler implementations. Contains the |
// the common logic for objects with different ElementsKinds. |
// Subclasses must specialize method for which the element |
@@ -1123,6 +1143,20 @@ class ElementsAccessorBase : public ElementsAccessor { |
length); |
} |
+ static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ return IndexOfValueSlowPath(isolate, receiver, value, start_from, length); |
+ } |
+ |
+ Maybe<int64_t> IndexOfValue(Isolate* isolate, Handle<JSObject> receiver, |
+ Handle<Object> value, uint32_t start_from, |
+ uint32_t length) final { |
+ return Subclass::IndexOfValueImpl(isolate, receiver, value, start_from, |
+ length); |
+ } |
+ |
static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, |
uint32_t entry) { |
return entry; |
@@ -1571,6 +1605,68 @@ class DictionaryElementsAccessor |
} |
return Just(false); |
} |
+ |
+ static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver)); |
+ |
+ Handle<SeededNumberDictionary> dictionary( |
+ SeededNumberDictionary::cast(receiver->elements()), isolate); |
+ // Iterate through entire range, as accessing elements out of order is |
+ // observable. |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ int entry = dictionary->FindEntry(k); |
+ if (entry == SeededNumberDictionary::kNotFound) { |
+ continue; |
+ } |
+ |
+ PropertyDetails details = GetDetailsImpl(*dictionary, entry); |
+ switch (details.kind()) { |
+ case kData: { |
+ Object* element_k = dictionary->ValueAt(entry); |
+ if (value->StrictEquals(element_k)) { |
+ return Just<int64_t>(k); |
+ } |
+ break; |
+ } |
+ case kAccessor: { |
+ LookupIterator it(isolate, receiver, k, |
+ LookupIterator::OWN_SKIP_INTERCEPTOR); |
+ DCHECK(it.IsFound()); |
+ DCHECK_EQ(it.state(), LookupIterator::ACCESSOR); |
+ Handle<Object> element_k; |
+ |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, element_k, JSObject::GetPropertyWithAccessor(&it), |
+ Nothing<int64_t>()); |
+ |
+ if (value->StrictEquals(*element_k)) return Just<int64_t>(k); |
+ |
+ // Bailout to slow path if elements on prototype changed. |
+ if (!JSObject::PrototypeHasNoElements(isolate, *receiver)) { |
+ return IndexOfValueSlowPath(isolate, receiver, value, k + 1, |
+ length); |
+ } |
+ |
+ // Continue if elements unchanged. |
+ if (*dictionary == receiver->elements()) continue; |
+ |
+ // Otherwise, bailout or update elements. |
+ if (receiver->GetElementsKind() != DICTIONARY_ELEMENTS) { |
+ // Otherwise, switch to slow path. |
+ return IndexOfValueSlowPath(isolate, receiver, value, k + 1, |
+ length); |
+ } |
+ dictionary = handle( |
+ SeededNumberDictionary::cast(receiver->elements()), isolate); |
+ break; |
+ } |
+ } |
+ } |
+ return Just<int64_t>(-1); |
+ } |
}; |
@@ -2277,6 +2373,33 @@ class FastSmiOrObjectElementsAccessor |
break; // Nothing to do. |
} |
} |
+ |
+ static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> search_value, |
+ uint32_t start_from, uint32_t length) { |
+ DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver)); |
+ DisallowHeapAllocation no_gc; |
+ FixedArrayBase* elements_base = receiver->elements(); |
+ Object* value = *search_value; |
+ |
+ if (start_from >= length) return Just<int64_t>(-1); |
+ |
+ length = std::min(static_cast<uint32_t>(elements_base->length()), length); |
+ |
+ // Only FAST_{,HOLEY_}ELEMENTS can store non-numbers. |
+ if (!value->IsNumber() && !IsFastObjectElementsKind(Subclass::kind())) { |
+ return Just<int64_t>(-1); |
+ } |
+ // NaN can never be found by strict equality. |
+ if (value->IsNaN()) return Just<int64_t>(-1); |
+ |
+ FixedArray* elements = FixedArray::cast(receiver->elements()); |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ if (value->StrictEquals(elements->get(k))) return Just<int64_t>(k); |
+ } |
+ return Just<int64_t>(-1); |
+ } |
}; |
@@ -2398,6 +2521,39 @@ class FastDoubleElementsAccessor |
break; |
} |
} |
+ |
+ static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> search_value, |
+ uint32_t start_from, uint32_t length) { |
+ DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver)); |
+ DisallowHeapAllocation no_gc; |
+ FixedArrayBase* elements_base = receiver->elements(); |
+ Object* value = *search_value; |
+ |
+ if (start_from >= length) return Just<int64_t>(-1); |
+ |
+ length = std::min(static_cast<uint32_t>(elements_base->length()), length); |
+ |
+ if (!value->IsNumber()) { |
+ return Just<int64_t>(-1); |
+ } |
+ if (value->IsNaN()) { |
+ return Just<int64_t>(-1); |
+ } |
+ double numeric_search_value = value->Number(); |
+ FixedDoubleArray* elements = FixedDoubleArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ if (elements->is_the_hole(k)) { |
+ continue; |
+ } |
+ if (elements->get_scalar(k) == numeric_search_value) { |
+ return Just<int64_t>(k); |
+ } |
+ } |
+ return Just<int64_t>(-1); |
+ } |
}; |
@@ -2591,6 +2747,52 @@ class TypedElementsAccessor |
return Just(false); |
} |
} |
+ |
+ static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ DCHECK(JSObject::PrototypeHasNoElements(isolate, *receiver)); |
+ DisallowHeapAllocation no_gc; |
+ |
+ BackingStore* elements = BackingStore::cast(receiver->elements()); |
+ if (!value->IsNumber()) return Just<int64_t>(-1); |
+ |
+ double search_value = value->Number(); |
+ |
+ if (!std::isfinite(search_value)) { |
+ // Integral types cannot represent +Inf or NaN. |
+ if (AccessorClass::kind() < FLOAT32_ELEMENTS || |
+ AccessorClass::kind() > FLOAT64_ELEMENTS) { |
+ return Just<int64_t>(-1); |
+ } |
+ } else if (search_value < std::numeric_limits<ctype>::lowest() || |
+ search_value > std::numeric_limits<ctype>::max()) { |
+ // Return false if value can't be represented in this ElementsKind. |
+ return Just<int64_t>(-1); |
+ } |
+ |
+ // Prototype has no elements, and not searching for the hole --- limit |
+ // search to backing store length. |
+ if (static_cast<uint32_t>(elements->length()) < length) { |
+ length = elements->length(); |
+ } |
+ |
+ if (std::isnan(search_value)) { |
+ return Just<int64_t>(-1); |
+ } |
+ |
+ ctype typed_search_value = static_cast<ctype>(search_value); |
+ if (static_cast<double>(typed_search_value) != search_value) { |
+ return Just<int64_t>(-1); // Loss of precision. |
+ } |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ ctype element_k = elements->get_scalar(k); |
+ if (element_k == typed_search_value) return Just<int64_t>(k); |
+ } |
+ return Just<int64_t>(-1); |
+ } |
}; |
#define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \ |
@@ -2869,6 +3071,46 @@ class SloppyArgumentsElementsAccessor |
} |
return Just(false); |
} |
+ |
+ static Maybe<int64_t> IndexOfValueImpl(Isolate* isolate, |
+ Handle<JSObject> object, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ DCHECK(JSObject::PrototypeHasNoElements(isolate, *object)); |
+ Handle<Map> original_map = handle(object->map(), isolate); |
+ FixedArray* parameter_map = FixedArray::cast(object->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ uint32_t entry = |
+ GetEntryForIndexImpl(*object, parameter_map, k, ALL_PROPERTIES); |
+ if (entry == kMaxUInt32) { |
+ continue; |
+ } |
+ |
+ Handle<Object> element_k = GetImpl(parameter_map, entry); |
+ |
+ if (element_k->IsAccessorPair()) { |
+ LookupIterator it(isolate, object, k, LookupIterator::OWN); |
+ DCHECK(it.IsFound()); |
+ DCHECK_EQ(it.state(), LookupIterator::ACCESSOR); |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k, |
+ Object::GetPropertyWithAccessor(&it), |
+ Nothing<int64_t>()); |
+ |
+ if (value->StrictEquals(*element_k)) { |
+ return Just<int64_t>(k); |
+ } |
+ |
+ if (object->map() != *original_map) { |
+ // Some mutation occurred in accessor. Abort "fast" path. |
+ return IndexOfValueSlowPath(isolate, object, value, k + 1, length); |
+ } |
+ } else if (value->StrictEquals(*element_k)) { |
+ return Just<int64_t>(k); |
+ } |
+ } |
+ return Just<int64_t>(-1); |
+ } |
}; |