| 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);
 | 
| +  }
 | 
|  };
 | 
|  
 | 
|  
 | 
| 
 |