Home | History | Annotate | Download | only in src
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/lookup.h"
      6 
      7 #include "src/bootstrapper.h"
      8 #include "src/deoptimizer.h"
      9 #include "src/elements.h"
     10 #include "src/isolate-inl.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 
     16 // static
     17 LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
     18                                                  Handle<Object> receiver,
     19                                                  Handle<Object> key,
     20                                                  bool* success,
     21                                                  Configuration configuration) {
     22   uint32_t index = 0;
     23   if (key->ToArrayIndex(&index)) {
     24     *success = true;
     25     return LookupIterator(isolate, receiver, index, configuration);
     26   }
     27 
     28   Handle<Name> name;
     29   *success = Object::ToName(isolate, key).ToHandle(&name);
     30   if (!*success) {
     31     DCHECK(isolate->has_pending_exception());
     32     // Return an unusable dummy.
     33     return LookupIterator(receiver, isolate->factory()->empty_string());
     34   }
     35 
     36   if (name->AsArrayIndex(&index)) {
     37     LookupIterator it(isolate, receiver, index, configuration);
     38     // Here we try to avoid having to rebuild the string later
     39     // by storing it on the indexed LookupIterator.
     40     it.name_ = name;
     41     return it;
     42   }
     43 
     44   return LookupIterator(receiver, name, configuration);
     45 }
     46 
     47 
     48 void LookupIterator::Next() {
     49   DCHECK_NE(JSPROXY, state_);
     50   DCHECK_NE(TRANSITION, state_);
     51   DisallowHeapAllocation no_gc;
     52   has_property_ = false;
     53 
     54   JSReceiver* holder = *holder_;
     55   Map* map = *holder_map_;
     56 
     57   // Perform lookup on current holder.
     58   state_ = LookupInHolder(map, holder);
     59   if (IsFound()) return;
     60 
     61   // Continue lookup if lookup on current holder failed.
     62   do {
     63     JSReceiver* maybe_holder = NextHolder(map);
     64     if (maybe_holder == nullptr) {
     65       if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
     66         RestartLookupForNonMaskingInterceptors();
     67         return;
     68       }
     69       break;
     70     }
     71     holder = maybe_holder;
     72     map = holder->map();
     73     state_ = LookupInHolder(map, holder);
     74   } while (!IsFound());
     75 
     76   if (holder != *holder_) {
     77     holder_ = handle(holder, isolate_);
     78     holder_map_ = handle(map, isolate_);
     79   }
     80 }
     81 
     82 
     83 void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
     84   state_ = NOT_FOUND;
     85   interceptor_state_ = interceptor_state;
     86   property_details_ = PropertyDetails::Empty();
     87   holder_ = initial_holder_;
     88   holder_map_ = handle(holder_->map(), isolate_);
     89   number_ = DescriptorArray::kNotFound;
     90   Next();
     91 }
     92 
     93 
     94 // static
     95 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
     96     Isolate* isolate, Handle<Object> receiver, uint32_t index) {
     97   // Strings are the only objects with properties (only elements) directly on
     98   // the wrapper. Hence we can skip generating the wrapper for all other cases.
     99   if (index != kMaxUInt32 && receiver->IsString() &&
    100       index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
    101     // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
    102     // context, ensuring that we don't leak it into JS?
    103     Handle<JSFunction> constructor = isolate->string_function();
    104     Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
    105     Handle<JSValue>::cast(result)->set_value(*receiver);
    106     return result;
    107   }
    108   auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
    109   if (root->IsNull()) {
    110     unsigned int magic = 0xbbbbbbbb;
    111     isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
    112   }
    113   return Handle<JSReceiver>::cast(root);
    114 }
    115 
    116 
    117 Handle<Map> LookupIterator::GetReceiverMap() const {
    118   if (receiver_->IsNumber()) return factory()->heap_number_map();
    119   return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
    120 }
    121 
    122 
    123 Handle<JSObject> LookupIterator::GetStoreTarget() const {
    124   if (receiver_->IsJSGlobalProxy()) {
    125     PrototypeIterator iter(isolate(), receiver_);
    126     if (iter.IsAtEnd()) return Handle<JSGlobalProxy>::cast(receiver_);
    127     return PrototypeIterator::GetCurrent<JSGlobalObject>(iter);
    128   }
    129   return Handle<JSObject>::cast(receiver_);
    130 }
    131 
    132 
    133 bool LookupIterator::HasAccess() const {
    134   DCHECK_EQ(ACCESS_CHECK, state_);
    135   return isolate_->MayAccess(handle(isolate_->context()),
    136                              GetHolder<JSObject>());
    137 }
    138 
    139 
    140 void LookupIterator::ReloadPropertyInformation() {
    141   state_ = BEFORE_PROPERTY;
    142   interceptor_state_ = InterceptorState::kUninitialized;
    143   state_ = LookupInHolder(*holder_map_, *holder_);
    144   DCHECK(IsFound() || holder_map_->is_dictionary_map());
    145 }
    146 
    147 
    148 void LookupIterator::ReloadHolderMap() {
    149   DCHECK_EQ(DATA, state_);
    150   DCHECK(IsElement());
    151   DCHECK(JSObject::cast(*holder_)->HasFixedTypedArrayElements());
    152   if (*holder_map_ != holder_->map()) {
    153     holder_map_ = handle(holder_->map(), isolate_);
    154   }
    155 }
    156 
    157 
    158 void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
    159   DCHECK(state_ == DATA || state_ == ACCESSOR);
    160   DCHECK(HolderIsReceiverOrHiddenPrototype());
    161 
    162   Handle<JSObject> holder = GetHolder<JSObject>();
    163 
    164   if (IsElement()) {
    165     ElementsKind kind = holder_map_->elements_kind();
    166     ElementsKind to = value->OptimalElementsKind();
    167     if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
    168     to = GetMoreGeneralElementsKind(kind, to);
    169     JSObject::TransitionElementsKind(holder, to);
    170     holder_map_ = handle(holder->map(), isolate_);
    171 
    172     // Copy the backing store if it is copy-on-write.
    173     if (IsFastSmiOrObjectElementsKind(to)) {
    174       JSObject::EnsureWritableFastElements(holder);
    175     }
    176 
    177   } else {
    178     if (holder_map_->is_dictionary_map()) return;
    179     holder_map_ =
    180         Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
    181   }
    182 
    183   JSObject::MigrateToMap(holder, holder_map_);
    184   ReloadPropertyInformation();
    185 }
    186 
    187 
    188 void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
    189                                              PropertyAttributes attributes) {
    190   DCHECK(state_ == DATA || state_ == ACCESSOR);
    191   DCHECK(HolderIsReceiverOrHiddenPrototype());
    192   Handle<JSObject> holder = GetHolder<JSObject>();
    193   if (IsElement()) {
    194     DCHECK(!holder->HasFixedTypedArrayElements());
    195     DCHECK(attributes != NONE || !holder->HasFastElements());
    196     Handle<FixedArrayBase> elements(holder->elements());
    197     holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
    198                                                attributes);
    199   } else if (holder_map_->is_dictionary_map()) {
    200     PropertyDetails details(attributes, v8::internal::DATA, 0,
    201                             PropertyCellType::kMutable);
    202     JSObject::SetNormalizedProperty(holder, name(), value, details);
    203   } else {
    204     holder_map_ = Map::ReconfigureExistingProperty(
    205         holder_map_, descriptor_number(), i::kData, attributes);
    206     holder_map_ =
    207         Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
    208     JSObject::MigrateToMap(holder, holder_map_);
    209   }
    210 
    211   ReloadPropertyInformation();
    212   WriteDataValue(value);
    213 
    214 #if VERIFY_HEAP
    215   if (FLAG_verify_heap) {
    216     holder->JSObjectVerify();
    217   }
    218 #endif
    219 }
    220 
    221 
    222 void LookupIterator::PrepareTransitionToDataProperty(
    223     Handle<Object> value, PropertyAttributes attributes,
    224     Object::StoreFromKeyed store_mode) {
    225   if (state_ == TRANSITION) return;
    226   DCHECK(state_ != LookupIterator::ACCESSOR ||
    227          (GetAccessors()->IsAccessorInfo() &&
    228           AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
    229   DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
    230   DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
    231   // Can only be called when the receiver is a JSObject. JSProxy has to be
    232   // handled via a trap. Adding properties to primitive values is not
    233   // observable.
    234   Handle<JSObject> receiver = GetStoreTarget();
    235 
    236   if (!isolate()->IsInternallyUsedPropertyName(name()) &&
    237       !receiver->map()->is_extensible()) {
    238     return;
    239   }
    240 
    241   auto transition = Map::TransitionToDataProperty(
    242       handle(receiver->map(), isolate_), name_, value, attributes, store_mode);
    243   state_ = TRANSITION;
    244   transition_ = transition;
    245 
    246   if (receiver->IsJSGlobalObject()) {
    247     // Install a property cell.
    248     InternalizeName();
    249     auto cell = JSGlobalObject::EnsurePropertyCell(
    250         Handle<JSGlobalObject>::cast(receiver), name());
    251     DCHECK(cell->value()->IsTheHole());
    252     transition_ = cell;
    253   } else if (!transition->is_dictionary_map()) {
    254     property_details_ = transition->GetLastDescriptorDetails();
    255     has_property_ = true;
    256   }
    257 }
    258 
    259 
    260 void LookupIterator::ApplyTransitionToDataProperty() {
    261   DCHECK_EQ(TRANSITION, state_);
    262 
    263   Handle<JSObject> receiver = GetStoreTarget();
    264   if (receiver->IsJSGlobalObject()) return;
    265   holder_ = receiver;
    266   holder_map_ = transition_map();
    267   JSObject::MigrateToMap(receiver, holder_map_);
    268   ReloadPropertyInformation();
    269 }
    270 
    271 
    272 void LookupIterator::Delete() {
    273   Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
    274   if (IsElement()) {
    275     Handle<JSObject> object = Handle<JSObject>::cast(holder);
    276     ElementsAccessor* accessor = object->GetElementsAccessor();
    277     accessor->Delete(object, number_);
    278   } else {
    279     PropertyNormalizationMode mode = holder->map()->is_prototype_map()
    280                                          ? KEEP_INOBJECT_PROPERTIES
    281                                          : CLEAR_INOBJECT_PROPERTIES;
    282 
    283     if (holder->HasFastProperties()) {
    284       JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
    285                                     "DeletingProperty");
    286       holder_map_ = handle(holder->map(), isolate_);
    287       ReloadPropertyInformation();
    288     }
    289     // TODO(verwaest): Get rid of the name_ argument.
    290     JSReceiver::DeleteNormalizedProperty(holder, name_, number_);
    291     if (holder->IsJSObject()) {
    292       JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
    293     }
    294   }
    295 }
    296 
    297 
    298 void LookupIterator::TransitionToAccessorProperty(
    299     AccessorComponent component, Handle<Object> accessor,
    300     PropertyAttributes attributes) {
    301   DCHECK(!accessor->IsNull());
    302   // Can only be called when the receiver is a JSObject. JSProxy has to be
    303   // handled via a trap. Adding properties to primitive values is not
    304   // observable.
    305   Handle<JSObject> receiver = GetStoreTarget();
    306 
    307   if (!IsElement() && !receiver->map()->is_dictionary_map()) {
    308     holder_ = receiver;
    309     holder_map_ = Map::TransitionToAccessorProperty(
    310         handle(receiver->map(), isolate_), name_, component, accessor,
    311         attributes);
    312     JSObject::MigrateToMap(receiver, holder_map_);
    313 
    314     ReloadPropertyInformation();
    315 
    316     if (!holder_map_->is_dictionary_map()) return;
    317   }
    318 
    319   Handle<AccessorPair> pair;
    320   if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
    321     pair = Handle<AccessorPair>::cast(GetAccessors());
    322     // If the component and attributes are identical, nothing has to be done.
    323     if (pair->get(component) == *accessor) {
    324       if (property_details().attributes() == attributes) return;
    325     } else {
    326       pair = AccessorPair::Copy(pair);
    327       pair->set(component, *accessor);
    328     }
    329   } else {
    330     pair = factory()->NewAccessorPair();
    331     pair->set(component, *accessor);
    332   }
    333 
    334   TransitionToAccessorPair(pair, attributes);
    335 
    336 #if VERIFY_HEAP
    337   if (FLAG_verify_heap) {
    338     receiver->JSObjectVerify();
    339   }
    340 #endif
    341 }
    342 
    343 
    344 void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
    345                                               PropertyAttributes attributes) {
    346   Handle<JSObject> receiver = GetStoreTarget();
    347   holder_ = receiver;
    348 
    349   PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0,
    350                           PropertyCellType::kMutable);
    351 
    352   if (IsElement()) {
    353     // TODO(verwaest): Move code into the element accessor.
    354     Handle<SeededNumberDictionary> dictionary =
    355         JSObject::NormalizeElements(receiver);
    356 
    357     // We unconditionally pass used_as_prototype=false here because the call
    358     // to RequireSlowElements takes care of the required IC clearing and
    359     // we don't want to walk the heap twice.
    360     dictionary =
    361         SeededNumberDictionary::Set(dictionary, index_, pair, details, false);
    362     receiver->RequireSlowElements(*dictionary);
    363 
    364     if (receiver->HasSlowArgumentsElements()) {
    365       FixedArray* parameter_map = FixedArray::cast(receiver->elements());
    366       uint32_t length = parameter_map->length() - 2;
    367       if (number_ < length) {
    368         parameter_map->set(number_ + 2, heap()->the_hole_value());
    369       }
    370       FixedArray::cast(receiver->elements())->set(1, *dictionary);
    371     } else {
    372       receiver->set_elements(*dictionary);
    373     }
    374   } else {
    375     PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
    376                                          ? KEEP_INOBJECT_PROPERTIES
    377                                          : CLEAR_INOBJECT_PROPERTIES;
    378     // Normalize object to make this operation simple.
    379     JSObject::NormalizeProperties(receiver, mode, 0,
    380                                   "TransitionToAccessorPair");
    381 
    382     JSObject::SetNormalizedProperty(receiver, name_, pair, details);
    383     JSObject::ReoptimizeIfPrototype(receiver);
    384   }
    385 
    386   holder_map_ = handle(receiver->map(), isolate_);
    387   ReloadPropertyInformation();
    388 }
    389 
    390 
    391 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
    392   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
    393   return InternalHolderIsReceiverOrHiddenPrototype();
    394 }
    395 
    396 bool LookupIterator::InternalHolderIsReceiverOrHiddenPrototype() const {
    397   // Optimization that only works if configuration_ is not mutable.
    398   if (!check_prototype_chain()) return true;
    399   DisallowHeapAllocation no_gc;
    400   if (!receiver_->IsJSReceiver()) return false;
    401   Object* current = *receiver_;
    402   JSReceiver* holder = *holder_;
    403   // JSProxy do not occur as hidden prototypes.
    404   if (current->IsJSProxy()) {
    405     return JSReceiver::cast(current) == holder;
    406   }
    407   PrototypeIterator iter(isolate(), current,
    408                          PrototypeIterator::START_AT_RECEIVER);
    409   do {
    410     if (iter.GetCurrent<JSReceiver>() == holder) return true;
    411     DCHECK(!current->IsJSProxy());
    412     iter.Advance();
    413   } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
    414   return false;
    415 }
    416 
    417 
    418 Handle<Object> LookupIterator::FetchValue() const {
    419   Object* result = NULL;
    420   if (IsElement()) {
    421     Handle<JSObject> holder = GetHolder<JSObject>();
    422     // TODO(verwaest): Optimize.
    423     if (holder->IsStringObjectWithCharacterAt(index_)) {
    424       Handle<JSValue> js_value = Handle<JSValue>::cast(holder);
    425       Handle<String> string(String::cast(js_value->value()));
    426       return factory()->LookupSingleCharacterStringFromCode(
    427           String::Flatten(string)->Get(index_));
    428     }
    429 
    430     ElementsAccessor* accessor = holder->GetElementsAccessor();
    431     return accessor->Get(handle(holder->elements()), number_);
    432   } else if (holder_map_->IsJSGlobalObjectMap()) {
    433     Handle<JSObject> holder = GetHolder<JSObject>();
    434     result = holder->global_dictionary()->ValueAt(number_);
    435     DCHECK(result->IsPropertyCell());
    436     result = PropertyCell::cast(result)->value();
    437   } else if (holder_map_->is_dictionary_map()) {
    438     result = holder_->property_dictionary()->ValueAt(number_);
    439   } else if (property_details_.type() == v8::internal::DATA) {
    440     Handle<JSObject> holder = GetHolder<JSObject>();
    441     FieldIndex field_index = FieldIndex::ForDescriptor(*holder_map_, number_);
    442     return JSObject::FastPropertyAt(holder, property_details_.representation(),
    443                                     field_index);
    444   } else {
    445     result = holder_map_->instance_descriptors()->GetValue(number_);
    446   }
    447   return handle(result, isolate_);
    448 }
    449 
    450 
    451 int LookupIterator::GetAccessorIndex() const {
    452   DCHECK(has_property_);
    453   DCHECK(!holder_map_->is_dictionary_map());
    454   DCHECK_EQ(v8::internal::ACCESSOR_CONSTANT, property_details_.type());
    455   return descriptor_number();
    456 }
    457 
    458 
    459 int LookupIterator::GetConstantIndex() const {
    460   DCHECK(has_property_);
    461   DCHECK(!holder_map_->is_dictionary_map());
    462   DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
    463   DCHECK(!IsElement());
    464   return descriptor_number();
    465 }
    466 
    467 
    468 FieldIndex LookupIterator::GetFieldIndex() const {
    469   DCHECK(has_property_);
    470   DCHECK(!holder_map_->is_dictionary_map());
    471   DCHECK_EQ(v8::internal::DATA, property_details_.type());
    472   DCHECK(!IsElement());
    473   int index =
    474       holder_map_->instance_descriptors()->GetFieldIndex(descriptor_number());
    475   bool is_double = representation().IsDouble();
    476   return FieldIndex::ForPropertyIndex(*holder_map_, index, is_double);
    477 }
    478 
    479 
    480 Handle<HeapType> LookupIterator::GetFieldType() const {
    481   DCHECK(has_property_);
    482   DCHECK(!holder_map_->is_dictionary_map());
    483   DCHECK_EQ(v8::internal::DATA, property_details_.type());
    484   return handle(
    485       holder_map_->instance_descriptors()->GetFieldType(descriptor_number()),
    486       isolate_);
    487 }
    488 
    489 
    490 Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
    491   DCHECK(!IsElement());
    492   Handle<JSObject> holder = GetHolder<JSObject>();
    493   Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
    494   Object* value = global->global_dictionary()->ValueAt(dictionary_entry());
    495   DCHECK(value->IsPropertyCell());
    496   return handle(PropertyCell::cast(value));
    497 }
    498 
    499 
    500 Handle<Object> LookupIterator::GetAccessors() const {
    501   DCHECK_EQ(ACCESSOR, state_);
    502   return FetchValue();
    503 }
    504 
    505 
    506 Handle<Object> LookupIterator::GetDataValue() const {
    507   DCHECK_EQ(DATA, state_);
    508   Handle<Object> value = FetchValue();
    509   return value;
    510 }
    511 
    512 
    513 void LookupIterator::WriteDataValue(Handle<Object> value) {
    514   DCHECK_EQ(DATA, state_);
    515   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
    516   if (IsElement()) {
    517     Handle<JSObject> object = Handle<JSObject>::cast(holder);
    518     ElementsAccessor* accessor = object->GetElementsAccessor();
    519     accessor->Set(object->elements(), number_, *value);
    520   } else if (holder->IsJSGlobalObject()) {
    521     Handle<GlobalDictionary> property_dictionary =
    522         handle(JSObject::cast(*holder)->global_dictionary());
    523     PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value,
    524                              property_details_);
    525   } else if (holder_map_->is_dictionary_map()) {
    526     NameDictionary* property_dictionary = holder->property_dictionary();
    527     property_dictionary->ValueAtPut(dictionary_entry(), *value);
    528   } else if (property_details_.type() == v8::internal::DATA) {
    529     JSObject::cast(*holder)->WriteToField(descriptor_number(), *value);
    530   } else {
    531     DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
    532   }
    533 }
    534 
    535 
    536 bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) {
    537   DCHECK(exotic_index_state_ != ExoticIndexState::kNotExotic);
    538   if (exotic_index_state_ == ExoticIndexState::kExotic) return true;
    539   if (!InternalHolderIsReceiverOrHiddenPrototype()) {
    540     exotic_index_state_ = ExoticIndexState::kNotExotic;
    541     return false;
    542   }
    543   DCHECK(exotic_index_state_ == ExoticIndexState::kUninitialized);
    544   bool result = false;
    545   // Compute and cache result.
    546   if (IsElement()) {
    547     result = index_ >= JSTypedArray::cast(holder)->length_value();
    548   } else if (name()->IsString()) {
    549     Handle<String> name_string = Handle<String>::cast(name());
    550     if (name_string->length() != 0) {
    551       result = IsSpecialIndex(isolate_->unicode_cache(), *name_string);
    552     }
    553   }
    554   exotic_index_state_ =
    555       result ? ExoticIndexState::kExotic : ExoticIndexState::kNotExotic;
    556   return result;
    557 }
    558 
    559 
    560 void LookupIterator::InternalizeName() {
    561   if (name_->IsUniqueName()) return;
    562   name_ = factory()->InternalizeString(Handle<String>::cast(name_));
    563 }
    564 
    565 
    566 bool LookupIterator::HasInterceptor(Map* map) const {
    567   if (IsElement()) return map->has_indexed_interceptor();
    568   return map->has_named_interceptor();
    569 }
    570 
    571 
    572 bool LookupIterator::SkipInterceptor(JSObject* holder) {
    573   auto info = GetInterceptor(holder);
    574   // TODO(dcarney): check for symbol/can_intercept_symbols here as well.
    575   if (info->non_masking()) {
    576     switch (interceptor_state_) {
    577       case InterceptorState::kUninitialized:
    578         interceptor_state_ = InterceptorState::kSkipNonMasking;
    579       // Fall through.
    580       case InterceptorState::kSkipNonMasking:
    581         return true;
    582       case InterceptorState::kProcessNonMasking:
    583         return false;
    584     }
    585   }
    586   return interceptor_state_ == InterceptorState::kProcessNonMasking;
    587 }
    588 
    589 
    590 JSReceiver* LookupIterator::NextHolder(Map* map) {
    591   DisallowHeapAllocation no_gc;
    592   if (!map->prototype()->IsJSReceiver()) return NULL;
    593 
    594   JSReceiver* next = JSReceiver::cast(map->prototype());
    595   DCHECK(!next->map()->IsJSGlobalObjectMap() ||
    596          next->map()->is_hidden_prototype());
    597 
    598   if (!check_prototype_chain() &&
    599       !(check_hidden() && next->map()->is_hidden_prototype()) &&
    600       // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even
    601       // when not checking other hidden prototypes.
    602       !map->IsJSGlobalProxyMap()) {
    603     return NULL;
    604   }
    605 
    606   return next;
    607 }
    608 
    609 
    610 LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
    611                                                      JSReceiver* const holder) {
    612   STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
    613   DisallowHeapAllocation no_gc;
    614   if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
    615     return LookupNonMaskingInterceptorInHolder(map, holder);
    616   }
    617   switch (state_) {
    618     case NOT_FOUND:
    619       if (map->IsJSProxyMap()) {
    620         // Do not leak private property names.
    621         if (IsElement() || !name_->IsPrivate()) return JSPROXY;
    622       }
    623       if (map->is_access_check_needed() &&
    624           (IsElement() || !isolate_->IsInternallyUsedPropertyName(name_))) {
    625         return ACCESS_CHECK;
    626       }
    627     // Fall through.
    628     case ACCESS_CHECK:
    629       if (exotic_index_state_ != ExoticIndexState::kNotExotic &&
    630           holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) {
    631         return INTEGER_INDEXED_EXOTIC;
    632       }
    633       if (check_interceptor() && HasInterceptor(map) &&
    634           !SkipInterceptor(JSObject::cast(holder))) {
    635         // Do not leak private property names.
    636         if (!name_.is_null() && name_->IsPrivate()) return NOT_FOUND;
    637         return INTERCEPTOR;
    638       }
    639     // Fall through.
    640     case INTERCEPTOR:
    641       if (IsElement()) {
    642         // TODO(verwaest): Optimize.
    643         if (holder->IsStringObjectWithCharacterAt(index_)) {
    644           PropertyAttributes attributes =
    645               static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
    646           property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0,
    647                                               PropertyCellType::kNoCell);
    648         } else {
    649           JSObject* js_object = JSObject::cast(holder);
    650           if (js_object->elements() == isolate()->heap()->empty_fixed_array()) {
    651             return NOT_FOUND;
    652           }
    653 
    654           ElementsAccessor* accessor = js_object->GetElementsAccessor();
    655           FixedArrayBase* backing_store = js_object->elements();
    656           number_ =
    657               accessor->GetEntryForIndex(js_object, backing_store, index_);
    658           if (number_ == kMaxUInt32) return NOT_FOUND;
    659           property_details_ = accessor->GetDetails(backing_store, number_);
    660         }
    661       } else if (!map->is_dictionary_map()) {
    662         DescriptorArray* descriptors = map->instance_descriptors();
    663         int number = descriptors->SearchWithCache(*name_, map);
    664         if (number == DescriptorArray::kNotFound) return NOT_FOUND;
    665         number_ = static_cast<uint32_t>(number);
    666         property_details_ = descriptors->GetDetails(number_);
    667       } else if (map->IsJSGlobalObjectMap()) {
    668         GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
    669         int number = dict->FindEntry(name_);
    670         if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
    671         number_ = static_cast<uint32_t>(number);
    672         DCHECK(dict->ValueAt(number_)->IsPropertyCell());
    673         PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
    674         if (cell->value()->IsTheHole()) return NOT_FOUND;
    675         property_details_ = cell->property_details();
    676       } else {
    677         NameDictionary* dict = holder->property_dictionary();
    678         int number = dict->FindEntry(name_);
    679         if (number == NameDictionary::kNotFound) return NOT_FOUND;
    680         number_ = static_cast<uint32_t>(number);
    681         property_details_ = dict->DetailsAt(number_);
    682       }
    683       has_property_ = true;
    684       switch (property_details_.kind()) {
    685         case v8::internal::kData:
    686           return DATA;
    687         case v8::internal::kAccessor:
    688           return ACCESSOR;
    689       }
    690     case ACCESSOR:
    691     case DATA:
    692       return NOT_FOUND;
    693     case INTEGER_INDEXED_EXOTIC:
    694     case JSPROXY:
    695     case TRANSITION:
    696       UNREACHABLE();
    697   }
    698   UNREACHABLE();
    699   return state_;
    700 }
    701 
    702 
    703 LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder(
    704     Map* const map, JSReceiver* const holder) {
    705   switch (state_) {
    706     case NOT_FOUND:
    707       if (check_interceptor() && HasInterceptor(map) &&
    708           !SkipInterceptor(JSObject::cast(holder))) {
    709         return INTERCEPTOR;
    710       }
    711     // Fall through.
    712     default:
    713       return NOT_FOUND;
    714   }
    715   UNREACHABLE();
    716   return state_;
    717 }
    718 
    719 }  // namespace internal
    720 }  // namespace v8
    721