Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/lookup.cc b/src/lookup.cc
index 8088f4d..48da4fa 100644
--- a/src/lookup.cc
+++ b/src/lookup.cc
@@ -2,17 +2,49 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
+#include "src/lookup.h"
 
 #include "src/bootstrapper.h"
 #include "src/deoptimizer.h"
-#include "src/lookup.h"
-#include "src/lookup-inl.h"
+#include "src/elements.h"
+#include "src/isolate-inl.h"
 
 namespace v8 {
 namespace internal {
 
 
+// static
+LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
+                                                 Handle<Object> receiver,
+                                                 Handle<Object> key,
+                                                 bool* success,
+                                                 Configuration configuration) {
+  uint32_t index = 0;
+  if (key->ToArrayIndex(&index)) {
+    *success = true;
+    return LookupIterator(isolate, receiver, index, configuration);
+  }
+
+  Handle<Name> name;
+  *success = Object::ToName(isolate, key).ToHandle(&name);
+  if (!*success) {
+    DCHECK(isolate->has_pending_exception());
+    // Return an unusable dummy.
+    return LookupIterator(receiver, isolate->factory()->empty_string());
+  }
+
+  if (name->AsArrayIndex(&index)) {
+    LookupIterator it(isolate, receiver, index, configuration);
+    // Here we try to avoid having to rebuild the string later
+    // by storing it on the indexed LookupIterator.
+    it.name_ = name;
+    return it;
+  }
+
+  return LookupIterator(receiver, name, configuration);
+}
+
+
 void LookupIterator::Next() {
   DCHECK_NE(JSPROXY, state_);
   DCHECK_NE(TRANSITION, state_);
@@ -29,7 +61,13 @@
   // Continue lookup if lookup on current holder failed.
   do {
     JSReceiver* maybe_holder = NextHolder(map);
-    if (maybe_holder == NULL) break;
+    if (maybe_holder == nullptr) {
+      if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
+        RestartLookupForNonMaskingInterceptors();
+        return;
+      }
+      break;
+    }
     holder = maybe_holder;
     map = holder->map();
     state_ = LookupInHolder(map, holder);
@@ -42,17 +80,42 @@
 }
 
 
-Handle<JSReceiver> LookupIterator::GetRoot() const {
-  if (receiver_->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver_);
-  Handle<Object> root =
-      handle(receiver_->GetRootMap(isolate_)->prototype(), isolate_);
-  CHECK(!root->IsNull());
+void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
+  state_ = NOT_FOUND;
+  interceptor_state_ = interceptor_state;
+  property_details_ = PropertyDetails::Empty();
+  holder_ = initial_holder_;
+  holder_map_ = handle(holder_->map(), isolate_);
+  number_ = DescriptorArray::kNotFound;
+  Next();
+}
+
+
+// static
+Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
+    Isolate* isolate, Handle<Object> receiver, uint32_t index) {
+  // Strings are the only objects with properties (only elements) directly on
+  // the wrapper. Hence we can skip generating the wrapper for all other cases.
+  if (index != kMaxUInt32 && receiver->IsString() &&
+      index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
+    // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
+    // context, ensuring that we don't leak it into JS?
+    Handle<JSFunction> constructor = isolate->string_function();
+    Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
+    Handle<JSValue>::cast(result)->set_value(*receiver);
+    return result;
+  }
+  auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
+  if (root->IsNull()) {
+    unsigned int magic = 0xbbbbbbbb;
+    isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
+  }
   return Handle<JSReceiver>::cast(root);
 }
 
 
 Handle<Map> LookupIterator::GetReceiverMap() const {
-  if (receiver_->IsNumber()) return isolate_->factory()->heap_number_map();
+  if (receiver_->IsNumber()) return factory()->heap_number_map();
   return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
 }
 
@@ -61,37 +124,63 @@
   if (receiver_->IsJSGlobalProxy()) {
     PrototypeIterator iter(isolate(), receiver_);
     if (iter.IsAtEnd()) return Handle<JSGlobalProxy>::cast(receiver_);
-    return Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+    return PrototypeIterator::GetCurrent<JSGlobalObject>(iter);
   }
   return Handle<JSObject>::cast(receiver_);
 }
 
 
-bool LookupIterator::IsBootstrapping() const {
-  return isolate_->bootstrapper()->IsActive();
-}
-
-
-bool LookupIterator::HasAccess(v8::AccessType access_type) const {
+bool LookupIterator::HasAccess() const {
   DCHECK_EQ(ACCESS_CHECK, state_);
-  return isolate_->MayNamedAccess(GetHolder<JSObject>(), name_, access_type);
+  return isolate_->MayAccess(handle(isolate_->context()),
+                             GetHolder<JSObject>());
 }
 
 
 void LookupIterator::ReloadPropertyInformation() {
   state_ = BEFORE_PROPERTY;
+  interceptor_state_ = InterceptorState::kUninitialized;
   state_ = LookupInHolder(*holder_map_, *holder_);
   DCHECK(IsFound() || holder_map_->is_dictionary_map());
 }
 
 
+void LookupIterator::ReloadHolderMap() {
+  DCHECK_EQ(DATA, state_);
+  DCHECK(IsElement());
+  DCHECK(JSObject::cast(*holder_)->HasFixedTypedArrayElements());
+  if (*holder_map_ != holder_->map()) {
+    holder_map_ = handle(holder_->map(), isolate_);
+  }
+}
+
+
 void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
   DCHECK(state_ == DATA || state_ == ACCESSOR);
   DCHECK(HolderIsReceiverOrHiddenPrototype());
-  if (holder_map_->is_dictionary_map()) return;
-  holder_map_ =
-      Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
-  JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_);
+
+  Handle<JSObject> holder = GetHolder<JSObject>();
+
+  if (IsElement()) {
+    ElementsKind kind = holder_map_->elements_kind();
+    ElementsKind to = value->OptimalElementsKind();
+    if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
+    to = GetMoreGeneralElementsKind(kind, to);
+    JSObject::TransitionElementsKind(holder, to);
+    holder_map_ = handle(holder->map(), isolate_);
+
+    // Copy the backing store if it is copy-on-write.
+    if (IsFastSmiOrObjectElementsKind(to)) {
+      JSObject::EnsureWritableFastElements(holder);
+    }
+
+  } else {
+    if (holder_map_->is_dictionary_map()) return;
+    holder_map_ =
+        Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
+  }
+
+  JSObject::MigrateToMap(holder, holder_map_);
   ReloadPropertyInformation();
 }
 
@@ -101,16 +190,32 @@
   DCHECK(state_ == DATA || state_ == ACCESSOR);
   DCHECK(HolderIsReceiverOrHiddenPrototype());
   Handle<JSObject> holder = GetHolder<JSObject>();
-  if (holder_map_->is_dictionary_map()) {
-    PropertyDetails details(attributes, FIELD, 0);
+  if (IsElement()) {
+    DCHECK(!holder->HasFixedTypedArrayElements());
+    DCHECK(attributes != NONE || !holder->HasFastElements());
+    Handle<FixedArrayBase> elements(holder->elements());
+    holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
+                                               attributes);
+  } else if (holder_map_->is_dictionary_map()) {
+    PropertyDetails details(attributes, v8::internal::DATA, 0,
+                            PropertyCellType::kMutable);
     JSObject::SetNormalizedProperty(holder, name(), value, details);
   } else {
-    holder_map_ = Map::ReconfigureDataProperty(holder_map_, descriptor_number(),
-                                               attributes);
+    holder_map_ = Map::ReconfigureExistingProperty(
+        holder_map_, descriptor_number(), i::kData, attributes);
+    holder_map_ =
+        Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
     JSObject::MigrateToMap(holder, holder_map_);
   }
 
   ReloadPropertyInformation();
+  WriteDataValue(value);
+
+#if VERIFY_HEAP
+  if (FLAG_verify_heap) {
+    holder->JSObjectVerify();
+  }
+#endif
 }
 
 
@@ -119,9 +224,10 @@
     Object::StoreFromKeyed store_mode) {
   if (state_ == TRANSITION) return;
   DCHECK(state_ != LookupIterator::ACCESSOR ||
-         GetAccessors()->IsDeclaredAccessorInfo());
+         (GetAccessors()->IsAccessorInfo() &&
+          AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
+  DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
   DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
-
   // Can only be called when the receiver is a JSObject. JSProxy has to be
   // handled via a trap. Adding properties to primitive values is not
   // observable.
@@ -132,9 +238,22 @@
     return;
   }
 
-  transition_map_ = Map::TransitionToDataProperty(
+  auto transition = Map::TransitionToDataProperty(
       handle(receiver->map(), isolate_), name_, value, attributes, store_mode);
   state_ = TRANSITION;
+  transition_ = transition;
+
+  if (receiver->IsJSGlobalObject()) {
+    // Install a property cell.
+    InternalizeName();
+    auto cell = JSGlobalObject::EnsurePropertyCell(
+        Handle<JSGlobalObject>::cast(receiver), name());
+    DCHECK(cell->value()->IsTheHole());
+    transition_ = cell;
+  } else if (!transition->is_dictionary_map()) {
+    property_details_ = transition->GetLastDescriptorDetails();
+    has_property_ = true;
+  }
 }
 
 
@@ -142,13 +261,40 @@
   DCHECK_EQ(TRANSITION, state_);
 
   Handle<JSObject> receiver = GetStoreTarget();
+  if (receiver->IsJSGlobalObject()) return;
   holder_ = receiver;
-  holder_map_ = transition_map_;
+  holder_map_ = transition_map();
   JSObject::MigrateToMap(receiver, holder_map_);
   ReloadPropertyInformation();
 }
 
 
+void LookupIterator::Delete() {
+  Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
+  if (IsElement()) {
+    Handle<JSObject> object = Handle<JSObject>::cast(holder);
+    ElementsAccessor* accessor = object->GetElementsAccessor();
+    accessor->Delete(object, number_);
+  } else {
+    PropertyNormalizationMode mode = holder->map()->is_prototype_map()
+                                         ? KEEP_INOBJECT_PROPERTIES
+                                         : CLEAR_INOBJECT_PROPERTIES;
+
+    if (holder->HasFastProperties()) {
+      JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
+                                    "DeletingProperty");
+      holder_map_ = handle(holder->map(), isolate_);
+      ReloadPropertyInformation();
+    }
+    // TODO(verwaest): Get rid of the name_ argument.
+    JSReceiver::DeleteNormalizedProperty(holder, name_, number_);
+    if (holder->IsJSObject()) {
+      JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
+    }
+  }
+}
+
+
 void LookupIterator::TransitionToAccessorProperty(
     AccessorComponent component, Handle<Object> accessor,
     PropertyAttributes attributes) {
@@ -157,24 +303,19 @@
   // handled via a trap. Adding properties to primitive values is not
   // observable.
   Handle<JSObject> receiver = GetStoreTarget();
-  holder_ = receiver;
-  holder_map_ =
-      Map::TransitionToAccessorProperty(handle(receiver->map(), isolate_),
-                                        name_, component, accessor, attributes);
-  JSObject::MigrateToMap(receiver, holder_map_);
 
-  ReloadPropertyInformation();
+  if (!IsElement() && !receiver->map()->is_dictionary_map()) {
+    holder_ = receiver;
+    holder_map_ = Map::TransitionToAccessorProperty(
+        handle(receiver->map(), isolate_), name_, component, accessor,
+        attributes);
+    JSObject::MigrateToMap(receiver, holder_map_);
 
-  if (!holder_map_->is_dictionary_map()) return;
+    ReloadPropertyInformation();
 
-  // We have to deoptimize since accesses to data properties may have been
-  // inlined without a corresponding map-check.
-  if (holder_map_->IsGlobalObjectMap()) {
-    Deoptimizer::DeoptimizeGlobalObject(*receiver);
+    if (!holder_map_->is_dictionary_map()) return;
   }
 
-  // Install the accessor into the dictionary-mode object.
-  PropertyDetails details(attributes, CALLBACKS, 0);
   Handle<AccessorPair> pair;
   if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
     pair = Handle<AccessorPair>::cast(GetAccessors());
@@ -186,12 +327,62 @@
       pair->set(component, *accessor);
     }
   } else {
-    pair = isolate()->factory()->NewAccessorPair();
+    pair = factory()->NewAccessorPair();
     pair->set(component, *accessor);
   }
-  JSObject::SetNormalizedProperty(receiver, name_, pair, details);
 
-  JSObject::ReoptimizeIfPrototype(receiver);
+  TransitionToAccessorPair(pair, attributes);
+
+#if VERIFY_HEAP
+  if (FLAG_verify_heap) {
+    receiver->JSObjectVerify();
+  }
+#endif
+}
+
+
+void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
+                                              PropertyAttributes attributes) {
+  Handle<JSObject> receiver = GetStoreTarget();
+  holder_ = receiver;
+
+  PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0,
+                          PropertyCellType::kMutable);
+
+  if (IsElement()) {
+    // TODO(verwaest): Move code into the element accessor.
+    Handle<SeededNumberDictionary> dictionary =
+        JSObject::NormalizeElements(receiver);
+
+    // We unconditionally pass used_as_prototype=false here because the call
+    // to RequireSlowElements takes care of the required IC clearing and
+    // we don't want to walk the heap twice.
+    dictionary =
+        SeededNumberDictionary::Set(dictionary, index_, pair, details, false);
+    receiver->RequireSlowElements(*dictionary);
+
+    if (receiver->HasSlowArgumentsElements()) {
+      FixedArray* parameter_map = FixedArray::cast(receiver->elements());
+      uint32_t length = parameter_map->length() - 2;
+      if (number_ < length) {
+        parameter_map->set(number_ + 2, heap()->the_hole_value());
+      }
+      FixedArray::cast(receiver->elements())->set(1, *dictionary);
+    } else {
+      receiver->set_elements(*dictionary);
+    }
+  } else {
+    PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
+                                         ? KEEP_INOBJECT_PROPERTIES
+                                         : CLEAR_INOBJECT_PROPERTIES;
+    // Normalize object to make this operation simple.
+    JSObject::NormalizeProperties(receiver, mode, 0,
+                                  "TransitionToAccessorPair");
+
+    JSObject::SetNormalizedProperty(receiver, name_, pair, details);
+    JSObject::ReoptimizeIfPrototype(receiver);
+  }
+
   holder_map_ = handle(receiver->map(), isolate_);
   ReloadPropertyInformation();
 }
@@ -199,6 +390,10 @@
 
 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
+  return InternalHolderIsReceiverOrHiddenPrototype();
+}
+
+bool LookupIterator::InternalHolderIsReceiverOrHiddenPrototype() const {
   // Optimization that only works if configuration_ is not mutable.
   if (!check_prototype_chain()) return true;
   DisallowHeapAllocation no_gc;
@@ -212,7 +407,7 @@
   PrototypeIterator iter(isolate(), current,
                          PrototypeIterator::START_AT_RECEIVER);
   do {
-    if (JSReceiver::cast(iter.GetCurrent()) == holder) return true;
+    if (iter.GetCurrent<JSReceiver>() == holder) return true;
     DCHECK(!current->IsJSProxy());
     iter.Advance();
   } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
@@ -222,13 +417,27 @@
 
 Handle<Object> LookupIterator::FetchValue() const {
   Object* result = NULL;
-  Handle<JSObject> holder = GetHolder<JSObject>();
-  if (holder_map_->is_dictionary_map()) {
-    result = holder->property_dictionary()->ValueAt(number_);
-    if (holder_map_->IsGlobalObjectMap()) {
-      result = PropertyCell::cast(result)->value();
+  if (IsElement()) {
+    Handle<JSObject> holder = GetHolder<JSObject>();
+    // TODO(verwaest): Optimize.
+    if (holder->IsStringObjectWithCharacterAt(index_)) {
+      Handle<JSValue> js_value = Handle<JSValue>::cast(holder);
+      Handle<String> string(String::cast(js_value->value()));
+      return factory()->LookupSingleCharacterStringFromCode(
+          String::Flatten(string)->Get(index_));
     }
-  } else if (property_details_.type() == v8::internal::FIELD) {
+
+    ElementsAccessor* accessor = holder->GetElementsAccessor();
+    return accessor->Get(handle(holder->elements()), number_);
+  } else if (holder_map_->IsJSGlobalObjectMap()) {
+    Handle<JSObject> holder = GetHolder<JSObject>();
+    result = holder->global_dictionary()->ValueAt(number_);
+    DCHECK(result->IsPropertyCell());
+    result = PropertyCell::cast(result)->value();
+  } else if (holder_map_->is_dictionary_map()) {
+    result = holder_->property_dictionary()->ValueAt(number_);
+  } else if (property_details_.type() == v8::internal::DATA) {
+    Handle<JSObject> holder = GetHolder<JSObject>();
     FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_);
     return JSObject::FastPropertyAt(holder, property_details_.representation(),
                                     field_index);
@@ -239,10 +448,19 @@
 }
 
 
+int LookupIterator::GetAccessorIndex() const {
+  DCHECK(has_property_);
+  DCHECK(!holder_map_->is_dictionary_map());
+  DCHECK_EQ(v8::internal::ACCESSOR_CONSTANT, property_details_.type());
+  return descriptor_number();
+}
+
+
 int LookupIterator::GetConstantIndex() const {
   DCHECK(has_property_);
   DCHECK(!holder_map_->is_dictionary_map());
-  DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
+  DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
+  DCHECK(!IsElement());
   return descriptor_number();
 }
 
@@ -250,7 +468,8 @@
 FieldIndex LookupIterator::GetFieldIndex() const {
   DCHECK(has_property_);
   DCHECK(!holder_map_->is_dictionary_map());
-  DCHECK_EQ(v8::internal::FIELD, property_details_.type());
+  DCHECK_EQ(v8::internal::DATA, property_details_.type());
+  DCHECK(!IsElement());
   int index =
       holder_map_->instance_descriptors()->GetFieldIndex(descriptor_number());
   bool is_double = representation().IsDouble();
@@ -261,7 +480,7 @@
 Handle<HeapType> LookupIterator::GetFieldType() const {
   DCHECK(has_property_);
   DCHECK(!holder_map_->is_dictionary_map());
-  DCHECK_EQ(v8::internal::FIELD, property_details_.type());
+  DCHECK_EQ(v8::internal::DATA, property_details_.type());
   return handle(
       holder_map_->instance_descriptors()->GetFieldType(descriptor_number()),
       isolate_);
@@ -269,10 +488,12 @@
 
 
 Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
+  DCHECK(!IsElement());
   Handle<JSObject> holder = GetHolder<JSObject>();
-  Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
-  Object* value = global->property_dictionary()->ValueAt(dictionary_entry());
-  return Handle<PropertyCell>(PropertyCell::cast(value));
+  Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
+  Object* value = global->global_dictionary()->ValueAt(dictionary_entry());
+  DCHECK(value->IsPropertyCell());
+  return handle(PropertyCell::cast(value));
 }
 
 
@@ -289,46 +510,50 @@
 }
 
 
-Handle<Object> LookupIterator::WriteDataValue(Handle<Object> value) {
+void LookupIterator::WriteDataValue(Handle<Object> value) {
   DCHECK_EQ(DATA, state_);
-  Handle<JSObject> holder = GetHolder<JSObject>();
-  if (holder_map_->is_dictionary_map()) {
+  Handle<JSReceiver> holder = GetHolder<JSReceiver>();
+  if (IsElement()) {
+    Handle<JSObject> object = Handle<JSObject>::cast(holder);
+    ElementsAccessor* accessor = object->GetElementsAccessor();
+    accessor->Set(object->elements(), number_, *value);
+  } else if (holder->IsJSGlobalObject()) {
+    Handle<GlobalDictionary> property_dictionary =
+        handle(JSObject::cast(*holder)->global_dictionary());
+    PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value,
+                             property_details_);
+  } else if (holder_map_->is_dictionary_map()) {
     NameDictionary* property_dictionary = holder->property_dictionary();
-    if (holder->IsGlobalObject()) {
-      Handle<PropertyCell> cell(
-          PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
-      value = PropertyCell::SetValueInferType(cell, value);
-    } else {
-      property_dictionary->ValueAtPut(dictionary_entry(), *value);
-    }
-  } else if (property_details_.type() == v8::internal::FIELD) {
-    holder->WriteToField(descriptor_number(), *value);
+    property_dictionary->ValueAtPut(dictionary_entry(), *value);
+  } else if (property_details_.type() == v8::internal::DATA) {
+    JSObject::cast(*holder)->WriteToField(descriptor_number(), *value);
   } else {
-    DCHECK_EQ(v8::internal::CONSTANT, property_details_.type());
+    DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
   }
-  return value;
 }
 
 
-bool LookupIterator::IsSpecialNumericIndex() const {
-  if (GetStoreTarget()->IsJSTypedArray() && name()->IsString()) {
+bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) {
+  DCHECK(exotic_index_state_ != ExoticIndexState::kNotExotic);
+  if (exotic_index_state_ == ExoticIndexState::kExotic) return true;
+  if (!InternalHolderIsReceiverOrHiddenPrototype()) {
+    exotic_index_state_ = ExoticIndexState::kNotExotic;
+    return false;
+  }
+  DCHECK(exotic_index_state_ == ExoticIndexState::kUninitialized);
+  bool result = false;
+  // Compute and cache result.
+  if (IsElement()) {
+    result = index_ >= JSTypedArray::cast(holder)->length_value();
+  } else if (name()->IsString()) {
     Handle<String> name_string = Handle<String>::cast(name());
-    if (name_string->length() > 0) {
-      double d =
-          StringToDouble(isolate()->unicode_cache(), name_string, NO_FLAGS);
-      if (!std::isnan(d)) {
-        if (String::Equals(isolate()->factory()->minus_zero_string(),
-                           name_string))
-          return true;
-
-        Factory* factory = isolate()->factory();
-        Handle<Object> num = factory->NewNumber(d);
-        Handle<String> roundtrip_string = factory->NumberToString(num);
-        if (String::Equals(name_string, roundtrip_string)) return true;
-      }
+    if (name_string->length() != 0) {
+      result = IsSpecialIndex(isolate_->unicode_cache(), *name_string);
     }
   }
-  return false;
+  exotic_index_state_ =
+      result ? ExoticIndexState::kExotic : ExoticIndexState::kNotExotic;
+  return result;
 }
 
 
@@ -336,4 +561,160 @@
   if (name_->IsUniqueName()) return;
   name_ = factory()->InternalizeString(Handle<String>::cast(name_));
 }
-} }  // namespace v8::internal
+
+
+bool LookupIterator::HasInterceptor(Map* map) const {
+  if (IsElement()) return map->has_indexed_interceptor();
+  return map->has_named_interceptor();
+}
+
+
+bool LookupIterator::SkipInterceptor(JSObject* holder) {
+  auto info = GetInterceptor(holder);
+  // TODO(dcarney): check for symbol/can_intercept_symbols here as well.
+  if (info->non_masking()) {
+    switch (interceptor_state_) {
+      case InterceptorState::kUninitialized:
+        interceptor_state_ = InterceptorState::kSkipNonMasking;
+      // Fall through.
+      case InterceptorState::kSkipNonMasking:
+        return true;
+      case InterceptorState::kProcessNonMasking:
+        return false;
+    }
+  }
+  return interceptor_state_ == InterceptorState::kProcessNonMasking;
+}
+
+
+JSReceiver* LookupIterator::NextHolder(Map* map) {
+  DisallowHeapAllocation no_gc;
+  if (!map->prototype()->IsJSReceiver()) return NULL;
+
+  JSReceiver* next = JSReceiver::cast(map->prototype());
+  DCHECK(!next->map()->IsJSGlobalObjectMap() ||
+         next->map()->is_hidden_prototype());
+
+  if (!check_prototype_chain() &&
+      !(check_hidden() && next->map()->is_hidden_prototype()) &&
+      // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even
+      // when not checking other hidden prototypes.
+      !map->IsJSGlobalProxyMap()) {
+    return NULL;
+  }
+
+  return next;
+}
+
+
+LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
+                                                     JSReceiver* const holder) {
+  STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
+  DisallowHeapAllocation no_gc;
+  if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
+    return LookupNonMaskingInterceptorInHolder(map, holder);
+  }
+  switch (state_) {
+    case NOT_FOUND:
+      if (map->IsJSProxyMap()) {
+        // Do not leak private property names.
+        if (IsElement() || !name_->IsPrivate()) return JSPROXY;
+      }
+      if (map->is_access_check_needed() &&
+          (IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) {
+        return ACCESS_CHECK;
+      }
+    // Fall through.
+    case ACCESS_CHECK:
+      if (exotic_index_state_ != ExoticIndexState::kNotExotic &&
+          holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) {
+        return INTEGER_INDEXED_EXOTIC;
+      }
+      if (check_interceptor() && HasInterceptor(map) &&
+          !SkipInterceptor(JSObject::cast(holder))) {
+        // Do not leak private property names.
+        if (!name_.is_null() && name_->IsPrivate()) return NOT_FOUND;
+        return INTERCEPTOR;
+      }
+    // Fall through.
+    case INTERCEPTOR:
+      if (IsElement()) {
+        // TODO(verwaest): Optimize.
+        if (holder->IsStringObjectWithCharacterAt(index_)) {
+          PropertyAttributes attributes =
+              static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
+          property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0,
+                                              PropertyCellType::kNoCell);
+        } else {
+          JSObject* js_object = JSObject::cast(holder);
+          if (js_object->elements() == isolate()->heap()->empty_fixed_array()) {
+            return NOT_FOUND;
+          }
+
+          ElementsAccessor* accessor = js_object->GetElementsAccessor();
+          FixedArrayBase* backing_store = js_object->elements();
+          number_ =
+              accessor->GetEntryForIndex(js_object, backing_store, index_);
+          if (number_ == kMaxUInt32) return NOT_FOUND;
+          property_details_ = accessor->GetDetails(backing_store, number_);
+        }
+      } else if (!map->is_dictionary_map()) {
+        DescriptorArray* descriptors = map->instance_descriptors();
+        int number = descriptors->SearchWithCache(*name_, map);
+        if (number == DescriptorArray::kNotFound) return NOT_FOUND;
+        number_ = static_cast<uint32_t>(number);
+        property_details_ = descriptors->GetDetails(number_);
+      } else if (map->IsJSGlobalObjectMap()) {
+        GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
+        int number = dict->FindEntry(name_);
+        if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
+        number_ = static_cast<uint32_t>(number);
+        DCHECK(dict->ValueAt(number_)->IsPropertyCell());
+        PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
+        if (cell->value()->IsTheHole()) return NOT_FOUND;
+        property_details_ = cell->property_details();
+      } else {
+        NameDictionary* dict = holder->property_dictionary();
+        int number = dict->FindEntry(name_);
+        if (number == NameDictionary::kNotFound) return NOT_FOUND;
+        number_ = static_cast<uint32_t>(number);
+        property_details_ = dict->DetailsAt(number_);
+      }
+      has_property_ = true;
+      switch (property_details_.kind()) {
+        case v8::internal::kData:
+          return DATA;
+        case v8::internal::kAccessor:
+          return ACCESSOR;
+      }
+    case ACCESSOR:
+    case DATA:
+      return NOT_FOUND;
+    case INTEGER_INDEXED_EXOTIC:
+    case JSPROXY:
+    case TRANSITION:
+      UNREACHABLE();
+  }
+  UNREACHABLE();
+  return state_;
+}
+
+
+LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder(
+    Map* const map, JSReceiver* const holder) {
+  switch (state_) {
+    case NOT_FOUND:
+      if (check_interceptor() && HasInterceptor(map) &&
+          !SkipInterceptor(JSObject::cast(holder))) {
+        return INTERCEPTOR;
+      }
+    // Fall through.
+    default:
+      return NOT_FOUND;
+  }
+  UNREACHABLE();
+  return state_;
+}
+
+}  // namespace internal
+}  // namespace v8