Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Unified Diff: src/elements.cc

Issue 2232063002: [builtins] WIP: Array indexOf in TurboFan/Runtime (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Move fast path FastElements -> FastSmiOrObjectElements Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/elements.h ('k') | src/js/array.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
+ }
};
« no previous file with comments | « src/elements.h ('k') | src/js/array.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698