Index: src/elements.cc |
diff --git a/src/elements.cc b/src/elements.cc |
index 3cf8378162844a1fc00525e3ccacdb6f47406ac5..b9dfe8ce2b6c5f6b3ffc574fdd16528c887df3ec 100644 |
--- a/src/elements.cc |
+++ b/src/elements.cc |
@@ -468,6 +468,27 @@ static void SortIndices( |
} |
} |
+static Maybe<bool> IncludesValueSlowPath(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ bool search_for_hole = value->IsUndefined(isolate); |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ LookupIterator it(isolate, receiver, k); |
+ if (!it.IsFound()) { |
+ if (search_for_hole) return Just(true); |
+ continue; |
+ } |
+ Handle<Object> element_k; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_k, |
+ Object::GetProperty(&it), Nothing<bool>()); |
+ |
+ if (value->SameValueZero(*element_k)) return Just(true); |
+ } |
+ |
+ return Just(false); |
+} |
+ |
// Base class for element handler implementations. Contains the |
// the common logic for objects with different ElementsKinds. |
// Subclasses must specialize method for which the element |
@@ -1046,6 +1067,20 @@ class ElementsAccessorBase : public ElementsAccessor { |
return Subclass::GetCapacityImpl(holder, backing_store); |
} |
+ static Maybe<bool> IncludesValueImpl(Isolate* isolate, |
+ Handle<JSReceiver> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ UNREACHABLE(); |
caitp
2016/07/21 03:28:55
mostly for debugging, could make this fall back to
|
+ } |
+ |
+ Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver, |
+ Handle<Object> value, uint32_t start_from, |
+ uint32_t length) final { |
+ return Subclass::IncludesValueImpl(isolate, receiver, value, start_from, |
+ length); |
+ } |
+ |
static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, |
uint32_t entry) { |
return entry; |
@@ -1382,6 +1417,57 @@ class DictionaryElementsAccessor |
accumulator->AddKey(value, convert); |
} |
} |
+ |
+ static Maybe<bool> IncludesValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ Handle<SeededNumberDictionary> dictionary( |
+ SeededNumberDictionary::cast(receiver->elements()), isolate); |
+ |
+ Handle<Map> original_map = handle(receiver->map(), isolate); |
+ |
+ bool search_for_hole = value->IsUndefined(isolate); |
+ |
+ // Iterate through entire range, as accessing elements out of order is |
+ // observable |
+ for (uint32_t k = start_from; k < length; ++k) { |
caitp
2016/07/21 03:28:55
This comment _may_ be wrong --- if there's some so
Camillo Bruni
2016/07/21 08:01:55
Right, this is probably tricky to get fast always.
|
+ int entry = dictionary->FindEntry(k); |
+ if (entry == SeededNumberDictionary::kNotFound) { |
+ if (search_for_hole) return Just(true); |
+ continue; |
+ } |
+ |
+ PropertyDetails details = GetDetailsImpl(receiver->elements(), entry); |
+ switch (details.kind()) { |
+ case kData: { |
+ Object* element_k = dictionary->ValueAt(entry); |
+ if (value->SameValueZero(element_k)) return Just(true); |
+ break; |
+ } |
+ case kAccessor: { |
+ LookupIterator it(isolate, receiver, k, LookupIterator::OWN); |
+ 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<bool>()); |
+ |
+ if (value->SameValueZero(*element_k)) return Just(true); |
+ |
+ if (receiver->map() != *original_map) { |
+ // Some mutation occurred in accessor. Abort "fast" path |
+ return IncludesValueSlowPath(isolate, receiver, value, k + 1, |
+ length); |
+ } |
+ break; |
+ } |
+ } |
+ } |
+ return Just(false); |
+ } |
}; |
@@ -1742,6 +1828,128 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> { |
} |
} |
+ static Maybe<bool> IncludesValueImpl(Isolate* isolate, |
+ Handle<JSObject> receiver, |
+ Handle<Object> search_value, |
+ uint32_t start_from, uint32_t length) { |
+ DisallowHeapAllocation no_gc; |
+ FixedArrayBase* elements_base = receiver->elements(); |
+ Object* the_hole = isolate->heap()->the_hole_value(); |
+ Object* undefined = isolate->heap()->undefined_value(); |
+ Object* value = *search_value; |
+ |
+ // Elements beyond the capacity of the backing store treated as undefined. |
+ if (value == undefined && elements_base->length() < length) { |
caitp
2016/07/21 03:28:55
I think this assumption holds if there are no elem
|
+ return Just(true); |
+ } |
+ |
+ if (start_from >= length) return Just(false); |
+ |
+ if (!value->IsNumber()) { |
caitp
2016/07/21 03:28:55
I prefer not to add these sorts of fast paths in a
Camillo Bruni
2016/07/21 08:01:55
I'd vouch for exactly the opposite. TF and Cranksh
caitp
2016/07/21 20:32:29
Maybe the way to do this is to have just a C++ bui
|
+ if (value == undefined) { |
+ // Only FAST_ELEMENTS, FAST_HOLEY_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, and |
+ // FAST_HOLEY_DOUBLE_ELEMENTS can have `undefined` as a value. |
+ if (!IsFastObjectElementsKind(KindTraits::Kind) && |
+ !IsFastHoleyElementsKind(KindTraits::Kind)) { |
+ return Just(false); |
+ } |
+ if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { |
+ auto elements = FixedArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ Object* element_k = elements->get(k); |
+ |
+ if (IsFastHoleyElementsKind(KindTraits::Kind) && |
+ element_k == the_hole) { |
+ return Just(true); |
+ } |
+ if (IsFastObjectElementsKind(KindTraits::Kind) && |
+ element_k == undefined) { |
+ return Just(true); |
+ } |
+ } |
+ return Just(false); |
+ } else { |
+ // Loop searching for non-Number, non-Undefined elements |
+ auto elements = FixedDoubleArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ if (IsFastHoleyElementsKind(KindTraits::Kind) && |
+ elements->is_the_hole(k)) { |
+ return Just(true); |
+ } |
+ } |
+ return Just(false); |
+ } |
+ } else if (!IsFastObjectElementsKind(KindTraits::Kind)) { |
+ // Only Numbers can be represented as packed Smi or Double elements |
+ return Just(false); |
+ } else { |
+ auto elements = FixedArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ Object* element_k = elements->get(k); |
+ if (IsFastHoleyElementsKind(KindTraits::Kind) && |
+ element_k == the_hole) { |
+ continue; |
+ } |
+ |
+ if (value->SameValueZero(element_k)) return Just(true); |
+ } |
+ return Just(false); |
+ } |
+ } else { |
+ if (!value->IsNaN()) { |
+ double search_value = value->Number(); |
+ if (IsFastDoubleElementsKind(KindTraits::Kind)) { |
+ auto elements = FixedDoubleArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ if (IsFastHoleyElementsKind(KindTraits::Kind) && |
+ elements->is_the_hole(k)) { |
+ continue; |
+ } |
+ if (elements->get_scalar(k) == search_value) return Just(true); |
+ } |
+ return Just(false); |
+ } else { |
+ auto elements = FixedArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ Object* element_k = elements->get(k); |
+ if (element_k->IsNumber() && element_k->Number() == search_value) { |
+ return Just(true); |
+ } |
+ } |
+ return Just(false); |
+ } |
+ } else { |
+ // NaN cannot be represented with Smi elements |
+ if (IsFastSmiElementsKind(KindTraits::Kind)) return Just(false); |
+ |
+ if (IsFastDoubleElementsKind(KindTraits::Kind)) { |
+ auto elements = FixedDoubleArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ if (IsFastHoleyElementsKind(KindTraits::Kind) && |
+ elements->is_the_hole(k)) { |
+ continue; |
+ } |
+ if (std::isnan(elements->get_scalar(k))) return Just(true); |
+ } |
+ return Just(false); |
+ } else { |
+ auto elements = FixedArray::cast(receiver->elements()); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ if (elements->get(k)->IsNaN()) return Just(true); |
+ } |
+ return Just(false); |
+ } |
+ } |
+ } |
+ } |
+ |
private: |
// SpliceShrinkStep might modify the backing_store. |
static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver, |
@@ -2430,6 +2638,45 @@ class SloppyArgumentsElementsAccessor |
isolate, object, store, convert, filter, list, nof_indices, |
insertion_index); |
} |
+ |
+ static Maybe<bool> IncludesValueImpl(Isolate* isolate, |
+ Handle<JSObject> object, |
+ Handle<Object> value, |
+ uint32_t start_from, uint32_t length) { |
+ Handle<Map> original_map = handle(object->map(), isolate); |
+ FixedArray* parameter_map = FixedArray::cast(object->elements()); |
+ bool search_for_hole = value->IsUndefined(isolate); |
+ |
+ for (uint32_t k = start_from; k < length; ++k) { |
+ uint32_t entry = |
+ GetEntryForIndexImpl(*object, parameter_map, k, ALL_PROPERTIES); |
+ if (entry == kMaxUInt32) { |
+ if (search_for_hole) return Just(true); |
+ 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<bool>()); |
+ |
+ if (value->SameValueZero(*element_k)) return Just(true); |
+ |
+ if (object->map() != *original_map) { |
+ // Some mutation occurred in accessor. Abort "fast" path |
+ return IncludesValueSlowPath(isolate, object, value, k + 1, length); |
caitp
2016/07/21 03:28:55
I don't think a map check is really adequate for t
Camillo Bruni
2016/07/21 08:01:55
You can only have a dictionary (with potential acc
caitp
2016/07/21 20:32:29
I agree that it only applies to the SlowArgumentsC
caitp
2016/07/26 21:09:45
the map-check was not enough --- I changed it to a
|
+ } |
+ } else if (value->SameValueZero(*element_k)) { |
+ return Just(true); |
+ } |
+ } |
+ return Just(false); |
+ } |
}; |