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/field-type.h"
     11 #include "src/isolate-inl.h"
     12 #include "src/objects/hash-table-inl.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 // static
     18 LookupIterator LookupIterator::PropertyOrElement(
     19     Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
     20     bool* success, Handle<JSReceiver> holder, Configuration configuration) {
     21   uint32_t index = 0;
     22   if (key->ToArrayIndex(&index)) {
     23     *success = true;
     24     return LookupIterator(isolate, receiver, index, holder, configuration);
     25   }
     26 
     27   Handle<Name> name;
     28   *success = Object::ToName(isolate, key).ToHandle(&name);
     29   if (!*success) {
     30     DCHECK(isolate->has_pending_exception());
     31     // Return an unusable dummy.
     32     return LookupIterator(isolate, receiver,
     33                           isolate->factory()->empty_string());
     34   }
     35 
     36   if (name->AsArrayIndex(&index)) {
     37     LookupIterator it(isolate, receiver, index, holder, 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, holder, configuration);
     45 }
     46 
     47 // static
     48 LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
     49                                                  Handle<Object> receiver,
     50                                                  Handle<Object> key,
     51                                                  bool* success,
     52                                                  Configuration configuration) {
     53   // TODO(mslekova): come up with better way to avoid duplication
     54   uint32_t index = 0;
     55   if (key->ToArrayIndex(&index)) {
     56     *success = true;
     57     return LookupIterator(isolate, receiver, index, configuration);
     58   }
     59 
     60   Handle<Name> name;
     61   *success = Object::ToName(isolate, key).ToHandle(&name);
     62   if (!*success) {
     63     DCHECK(isolate->has_pending_exception());
     64     // Return an unusable dummy.
     65     return LookupIterator(isolate, receiver,
     66                           isolate->factory()->empty_string());
     67   }
     68 
     69   if (name->AsArrayIndex(&index)) {
     70     LookupIterator it(isolate, receiver, index, configuration);
     71     // Here we try to avoid having to rebuild the string later
     72     // by storing it on the indexed LookupIterator.
     73     it.name_ = name;
     74     return it;
     75   }
     76 
     77   return LookupIterator(isolate, receiver, name, configuration);
     78 }
     79 
     80 // TODO(ishell): Consider removing this way of LookupIterator creation.
     81 // static
     82 LookupIterator LookupIterator::ForTransitionHandler(
     83     Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
     84     Handle<Object> value, MaybeHandle<Map> maybe_transition_map) {
     85   Handle<Map> transition_map;
     86   if (!maybe_transition_map.ToHandle(&transition_map) ||
     87       !transition_map->IsPrototypeValidityCellValid()) {
     88     // This map is not a valid transition handler, so full lookup is required.
     89     return LookupIterator(isolate, receiver, name);
     90   }
     91 
     92   PropertyDetails details = PropertyDetails::Empty();
     93   bool has_property;
     94   if (transition_map->is_dictionary_map()) {
     95     details = PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
     96     has_property = false;
     97   } else {
     98     details = transition_map->GetLastDescriptorDetails();
     99     has_property = true;
    100   }
    101 #ifdef DEBUG
    102   if (name->IsPrivate()) {
    103     DCHECK_EQ(DONT_ENUM, details.attributes());
    104   } else {
    105     DCHECK_EQ(NONE, details.attributes());
    106   }
    107 #endif
    108   LookupIterator it(isolate, receiver, name, transition_map, details,
    109                     has_property);
    110 
    111   if (!transition_map->is_dictionary_map()) {
    112     int descriptor_number = transition_map->LastAdded();
    113     Handle<Map> new_map =
    114         Map::PrepareForDataProperty(isolate, transition_map, descriptor_number,
    115                                     PropertyConstness::kConst, value);
    116     // Reload information; this is no-op if nothing changed.
    117     it.property_details_ =
    118         new_map->instance_descriptors()->GetDetails(descriptor_number);
    119     it.transition_ = new_map;
    120   }
    121   return it;
    122 }
    123 
    124 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
    125                                Handle<Name> name, Handle<Map> transition_map,
    126                                PropertyDetails details, bool has_property)
    127     : configuration_(DEFAULT),
    128       state_(TRANSITION),
    129       has_property_(has_property),
    130       interceptor_state_(InterceptorState::kUninitialized),
    131       property_details_(details),
    132       isolate_(isolate),
    133       name_(name),
    134       transition_(transition_map),
    135       receiver_(receiver),
    136       initial_holder_(GetRoot(isolate, receiver)),
    137       index_(kMaxUInt32),
    138       number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
    139   holder_ = initial_holder_;
    140 }
    141 
    142 template <bool is_element>
    143 void LookupIterator::Start() {
    144   DisallowHeapAllocation no_gc;
    145 
    146   has_property_ = false;
    147   state_ = NOT_FOUND;
    148   holder_ = initial_holder_;
    149 
    150   JSReceiver* holder = *holder_;
    151   Map* map = holder->map();
    152 
    153   state_ = LookupInHolder<is_element>(map, holder);
    154   if (IsFound()) return;
    155 
    156   NextInternal<is_element>(map, holder);
    157 }
    158 
    159 template void LookupIterator::Start<true>();
    160 template void LookupIterator::Start<false>();
    161 
    162 void LookupIterator::Next() {
    163   DCHECK_NE(JSPROXY, state_);
    164   DCHECK_NE(TRANSITION, state_);
    165   DisallowHeapAllocation no_gc;
    166   has_property_ = false;
    167 
    168   JSReceiver* holder = *holder_;
    169   Map* map = holder->map();
    170 
    171   if (map->IsSpecialReceiverMap()) {
    172     state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
    173                          : LookupInSpecialHolder<false>(map, holder);
    174     if (IsFound()) return;
    175   }
    176 
    177   IsElement() ? NextInternal<true>(map, holder)
    178               : NextInternal<false>(map, holder);
    179 }
    180 
    181 template <bool is_element>
    182 void LookupIterator::NextInternal(Map* map, JSReceiver* holder) {
    183   do {
    184     JSReceiver* maybe_holder = NextHolder(map);
    185     if (maybe_holder == nullptr) {
    186       if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
    187         RestartLookupForNonMaskingInterceptors<is_element>();
    188         return;
    189       }
    190       state_ = NOT_FOUND;
    191       if (holder != *holder_) holder_ = handle(holder, isolate_);
    192       return;
    193     }
    194     holder = maybe_holder;
    195     map = holder->map();
    196     state_ = LookupInHolder<is_element>(map, holder);
    197   } while (!IsFound());
    198 
    199   holder_ = handle(holder, isolate_);
    200 }
    201 
    202 template <bool is_element>
    203 void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
    204   interceptor_state_ = interceptor_state;
    205   property_details_ = PropertyDetails::Empty();
    206   number_ = static_cast<uint32_t>(DescriptorArray::kNotFound);
    207   Start<is_element>();
    208 }
    209 
    210 template void LookupIterator::RestartInternal<true>(InterceptorState);
    211 template void LookupIterator::RestartInternal<false>(InterceptorState);
    212 
    213 // static
    214 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
    215     Isolate* isolate, Handle<Object> receiver, uint32_t index) {
    216   // Strings are the only objects with properties (only elements) directly on
    217   // the wrapper. Hence we can skip generating the wrapper for all other cases.
    218   if (index != kMaxUInt32 && receiver->IsString() &&
    219       index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
    220     // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
    221     // context, ensuring that we don't leak it into JS?
    222     Handle<JSFunction> constructor = isolate->string_function();
    223     Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
    224     Handle<JSValue>::cast(result)->set_value(*receiver);
    225     return result;
    226   }
    227   auto root =
    228       handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
    229   if (root->IsNull(isolate)) {
    230     isolate->PushStackTraceAndDie(*receiver);
    231   }
    232   return Handle<JSReceiver>::cast(root);
    233 }
    234 
    235 
    236 Handle<Map> LookupIterator::GetReceiverMap() const {
    237   if (receiver_->IsNumber()) return factory()->heap_number_map();
    238   return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
    239 }
    240 
    241 bool LookupIterator::HasAccess() const {
    242   DCHECK_EQ(ACCESS_CHECK, state_);
    243   return isolate_->MayAccess(handle(isolate_->context(), isolate_),
    244                              GetHolder<JSObject>());
    245 }
    246 
    247 template <bool is_element>
    248 void LookupIterator::ReloadPropertyInformation() {
    249   state_ = BEFORE_PROPERTY;
    250   interceptor_state_ = InterceptorState::kUninitialized;
    251   state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
    252   DCHECK(IsFound() || !holder_->HasFastProperties());
    253 }
    254 
    255 namespace {
    256 
    257 bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver* holder) {
    258   static uint32_t context_slots[] = {
    259 #define TYPED_ARRAY_CONTEXT_SLOTS(Type, type, TYPE, ctype) \
    260   Context::TYPE##_ARRAY_FUN_INDEX,
    261 
    262       TYPED_ARRAYS(TYPED_ARRAY_CONTEXT_SLOTS)
    263 #undef TYPED_ARRAY_CONTEXT_SLOTS
    264   };
    265 
    266   if (!holder->IsJSFunction()) return false;
    267 
    268   return std::any_of(
    269       std::begin(context_slots), std::end(context_slots),
    270       [=](uint32_t slot) { return isolate->IsInAnyContext(holder, slot); });
    271 }
    272 
    273 }  // namespace
    274 
    275 void LookupIterator::InternalUpdateProtector() {
    276   if (isolate_->bootstrapper()->IsActive()) return;
    277 
    278   ReadOnlyRoots roots(heap());
    279   if (*name_ == roots.constructor_string()) {
    280     if (!isolate_->IsArraySpeciesLookupChainIntact() &&
    281         !isolate_->IsTypedArraySpeciesLookupChainIntact() &&
    282         !isolate_->IsPromiseSpeciesLookupChainIntact())
    283       return;
    284     // Setting the constructor property could change an instance's @@species
    285     if (holder_->IsJSArray()) {
    286       if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
    287       isolate_->CountUsage(
    288           v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
    289       isolate_->InvalidateArraySpeciesProtector();
    290       return;
    291     } else if (holder_->IsJSPromise()) {
    292       if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
    293       isolate_->InvalidatePromiseSpeciesProtector();
    294       return;
    295     } else if (holder_->IsJSTypedArray()) {
    296       if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
    297       isolate_->InvalidateTypedArraySpeciesProtector();
    298       return;
    299     }
    300     if (holder_->map()->is_prototype_map()) {
    301       DisallowHeapAllocation no_gc;
    302       // Setting the constructor of Array.prototype, Promise.prototype or
    303       // %TypedArray%.prototype of any realm also needs to invalidate the
    304       // @@species protector.
    305       // For typed arrays, we check a prototype of this holder since TypedArrays
    306       // have different prototypes for each type, and their parent prototype is
    307       // pointing the same TYPED_ARRAY_PROTOTYPE.
    308       if (isolate_->IsInAnyContext(*holder_,
    309                                    Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
    310         if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
    311         isolate_->CountUsage(
    312             v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified);
    313         isolate_->InvalidateArraySpeciesProtector();
    314       } else if (isolate_->IsInAnyContext(*holder_,
    315                                           Context::PROMISE_PROTOTYPE_INDEX)) {
    316         if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
    317         isolate_->InvalidatePromiseSpeciesProtector();
    318       } else if (isolate_->IsInAnyContext(
    319                      holder_->map()->prototype(),
    320                      Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
    321         if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
    322         isolate_->InvalidateTypedArraySpeciesProtector();
    323       }
    324     }
    325   } else if (*name_ == roots.next_string()) {
    326     if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
    327     // Setting the next property of %ArrayIteratorPrototype% also needs to
    328     // invalidate the array iterator protector.
    329     if (isolate_->IsInAnyContext(
    330             *holder_, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)) {
    331       isolate_->InvalidateArrayIteratorProtector();
    332     }
    333   } else if (*name_ == roots.species_symbol()) {
    334     if (!isolate_->IsArraySpeciesLookupChainIntact() &&
    335         !isolate_->IsTypedArraySpeciesLookupChainIntact() &&
    336         !isolate_->IsPromiseSpeciesLookupChainIntact())
    337       return;
    338     // Setting the Symbol.species property of any Array, Promise or TypedArray
    339     // constructor invalidates the @@species protector
    340     if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
    341       if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
    342       isolate_->CountUsage(
    343           v8::Isolate::UseCounterFeature::kArraySpeciesModified);
    344       isolate_->InvalidateArraySpeciesProtector();
    345     } else if (isolate_->IsInAnyContext(*holder_,
    346                                         Context::PROMISE_FUNCTION_INDEX)) {
    347       if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
    348       isolate_->InvalidatePromiseSpeciesProtector();
    349     } else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
    350       if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
    351       isolate_->InvalidateTypedArraySpeciesProtector();
    352     }
    353   } else if (*name_ == roots.is_concat_spreadable_symbol()) {
    354     if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
    355     isolate_->InvalidateIsConcatSpreadableProtector();
    356   } else if (*name_ == roots.iterator_symbol()) {
    357     if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
    358     if (holder_->IsJSArray()) {
    359       isolate_->InvalidateArrayIteratorProtector();
    360     }
    361   } else if (*name_ == roots.resolve_string()) {
    362     if (!isolate_->IsPromiseResolveLookupChainIntact()) return;
    363     // Setting the "resolve" property on any %Promise% intrinsic object
    364     // invalidates the Promise.resolve protector.
    365     if (isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX)) {
    366       isolate_->InvalidatePromiseResolveProtector();
    367     }
    368   } else if (*name_ == roots.then_string()) {
    369     if (!isolate_->IsPromiseThenLookupChainIntact()) return;
    370     // Setting the "then" property on any JSPromise instance or on the
    371     // initial %PromisePrototype% invalidates the Promise#then protector.
    372     // Also setting the "then" property on the initial %ObjectPrototype%
    373     // invalidates the Promise#then protector, since we use this protector
    374     // to guard the fast-path in AsyncGeneratorResolve, where we can skip
    375     // the ResolvePromise step and go directly to FulfillPromise if we
    376     // know that the Object.prototype doesn't contain a "then" method.
    377     if (holder_->IsJSPromise() ||
    378         isolate_->IsInAnyContext(*holder_,
    379                                  Context::INITIAL_OBJECT_PROTOTYPE_INDEX) ||
    380         isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) {
    381       isolate_->InvalidatePromiseThenProtector();
    382     }
    383   }
    384 }
    385 
    386 void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
    387   DCHECK(state_ == DATA || state_ == ACCESSOR);
    388   DCHECK(HolderIsReceiverOrHiddenPrototype());
    389 
    390   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
    391   // JSProxy does not have fast properties so we do an early return.
    392   DCHECK_IMPLIES(holder->IsJSProxy(), !holder->HasFastProperties());
    393   DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
    394   if (holder->IsJSProxy()) return;
    395 
    396   Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
    397 
    398   if (IsElement()) {
    399     ElementsKind kind = holder_obj->GetElementsKind();
    400     ElementsKind to = value->OptimalElementsKind();
    401     if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
    402     to = GetMoreGeneralElementsKind(kind, to);
    403 
    404     if (kind != to) {
    405       JSObject::TransitionElementsKind(holder_obj, to);
    406     }
    407 
    408     // Copy the backing store if it is copy-on-write.
    409     if (IsSmiOrObjectElementsKind(to)) {
    410       JSObject::EnsureWritableFastElements(holder_obj);
    411     }
    412     return;
    413   }
    414 
    415   if (holder_obj->IsJSGlobalObject()) {
    416     Handle<GlobalDictionary> dictionary(
    417         JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
    418     Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()),
    419                               isolate());
    420     property_details_ = cell->property_details();
    421     PropertyCell::PrepareForValue(isolate(), dictionary, dictionary_entry(),
    422                                   value, property_details_);
    423     return;
    424   }
    425   if (!holder_obj->HasFastProperties()) return;
    426 
    427   PropertyConstness new_constness = PropertyConstness::kConst;
    428   if (FLAG_track_constant_fields) {
    429     if (constness() == PropertyConstness::kConst) {
    430       DCHECK_EQ(kData, property_details_.kind());
    431       // Check that current value matches new value otherwise we should make
    432       // the property mutable.
    433       if (!IsConstFieldValueEqualTo(*value))
    434         new_constness = PropertyConstness::kMutable;
    435     }
    436   } else {
    437     new_constness = PropertyConstness::kMutable;
    438   }
    439 
    440   Handle<Map> old_map(holder_obj->map(), isolate_);
    441   Handle<Map> new_map = Map::PrepareForDataProperty(
    442       isolate(), old_map, descriptor_number(), new_constness, value);
    443 
    444   if (old_map.is_identical_to(new_map)) {
    445     // Update the property details if the representation was None.
    446     if (constness() != new_constness || representation().IsNone()) {
    447       property_details_ =
    448           new_map->instance_descriptors()->GetDetails(descriptor_number());
    449     }
    450     return;
    451   }
    452 
    453   JSObject::MigrateToMap(holder_obj, new_map);
    454   ReloadPropertyInformation<false>();
    455 }
    456 
    457 
    458 void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
    459                                              PropertyAttributes attributes) {
    460   DCHECK(state_ == DATA || state_ == ACCESSOR);
    461   DCHECK(HolderIsReceiverOrHiddenPrototype());
    462 
    463   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
    464 
    465   // Property details can never change for private fields.
    466   if (holder->IsJSProxy()) {
    467     DCHECK(name()->IsPrivate());
    468     return;
    469   }
    470 
    471   Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
    472   if (IsElement()) {
    473     DCHECK(!holder_obj->HasFixedTypedArrayElements());
    474     DCHECK(attributes != NONE || !holder_obj->HasFastElements());
    475     Handle<FixedArrayBase> elements(holder_obj->elements(), isolate());
    476     holder_obj->GetElementsAccessor()->Reconfigure(holder_obj, elements,
    477                                                    number_, value, attributes);
    478     ReloadPropertyInformation<true>();
    479   } else if (holder_obj->HasFastProperties()) {
    480     Handle<Map> old_map(holder_obj->map(), isolate_);
    481     Handle<Map> new_map = Map::ReconfigureExistingProperty(
    482         isolate_, old_map, descriptor_number(), i::kData, attributes);
    483     // Force mutable to avoid changing constant value by reconfiguring
    484     // kData -> kAccessor -> kData.
    485     new_map =
    486         Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(),
    487                                     PropertyConstness::kMutable, value);
    488     JSObject::MigrateToMap(holder_obj, new_map);
    489     ReloadPropertyInformation<false>();
    490   }
    491 
    492   if (!IsElement() && !holder_obj->HasFastProperties()) {
    493     PropertyDetails details(kData, attributes, PropertyCellType::kMutable);
    494     if (holder_obj->map()->is_prototype_map() &&
    495         (property_details_.attributes() & READ_ONLY) == 0 &&
    496         (attributes & READ_ONLY) != 0) {
    497       // Invalidate prototype validity cell when a property is reconfigured
    498       // from writable to read-only as this may invalidate transitioning store
    499       // IC handlers.
    500       JSObject::InvalidatePrototypeChains(holder->map());
    501     }
    502     if (holder_obj->IsJSGlobalObject()) {
    503       Handle<GlobalDictionary> dictionary(
    504           JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
    505 
    506       Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
    507           isolate(), dictionary, dictionary_entry(), value, details);
    508       cell->set_value(*value);
    509       property_details_ = cell->property_details();
    510     } else {
    511       Handle<NameDictionary> dictionary(holder_obj->property_dictionary(),
    512                                         isolate());
    513       PropertyDetails original_details =
    514           dictionary->DetailsAt(dictionary_entry());
    515       int enumeration_index = original_details.dictionary_index();
    516       DCHECK_GT(enumeration_index, 0);
    517       details = details.set_index(enumeration_index);
    518       dictionary->SetEntry(isolate(), dictionary_entry(), *name(), *value,
    519                            details);
    520       property_details_ = details;
    521     }
    522     state_ = DATA;
    523   }
    524 
    525   WriteDataValue(value, true);
    526 
    527 #if VERIFY_HEAP
    528   if (FLAG_verify_heap) {
    529     holder->HeapObjectVerify(isolate());
    530   }
    531 #endif
    532 }
    533 
    534 // Can only be called when the receiver is a JSObject. JSProxy has to be handled
    535 // via a trap. Adding properties to primitive values is not observable.
    536 void LookupIterator::PrepareTransitionToDataProperty(
    537     Handle<JSReceiver> receiver, Handle<Object> value,
    538     PropertyAttributes attributes, Object::StoreFromKeyed store_mode) {
    539   DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate());
    540   DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
    541   if (state_ == TRANSITION) return;
    542 
    543   if (!IsElement() && name()->IsPrivate()) {
    544     attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
    545   }
    546 
    547   DCHECK(state_ != LookupIterator::ACCESSOR ||
    548          (GetAccessors()->IsAccessorInfo() &&
    549           AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
    550   DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
    551   DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
    552 
    553   Handle<Map> map(receiver->map(), isolate_);
    554 
    555   // Dictionary maps can always have additional data properties.
    556   if (map->is_dictionary_map()) {
    557     state_ = TRANSITION;
    558     if (map->IsJSGlobalObjectMap()) {
    559       // Install a property cell.
    560       Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
    561       int entry;
    562       Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
    563           global, name(), PropertyCellType::kUninitialized, &entry);
    564       Handle<GlobalDictionary> dictionary(global->global_dictionary(),
    565                                           isolate_);
    566       DCHECK(cell->value()->IsTheHole(isolate_));
    567       DCHECK(!value->IsTheHole(isolate_));
    568       transition_ = cell;
    569       // Assign an enumeration index to the property and update
    570       // SetNextEnumerationIndex.
    571       int index = dictionary->NextEnumerationIndex();
    572       dictionary->SetNextEnumerationIndex(index + 1);
    573       property_details_ = PropertyDetails(
    574           kData, attributes, PropertyCellType::kUninitialized, index);
    575       PropertyCellType new_type =
    576           PropertyCell::UpdatedType(isolate(), cell, value, property_details_);
    577       property_details_ = property_details_.set_cell_type(new_type);
    578       cell->set_property_details(property_details_);
    579       number_ = entry;
    580       has_property_ = true;
    581     } else {
    582       // Don't set enumeration index (it will be set during value store).
    583       property_details_ =
    584           PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
    585       transition_ = map;
    586     }
    587     return;
    588   }
    589 
    590   Handle<Map> transition =
    591       Map::TransitionToDataProperty(isolate_, map, name_, value, attributes,
    592                                     kDefaultFieldConstness, store_mode);
    593   state_ = TRANSITION;
    594   transition_ = transition;
    595 
    596   if (transition->is_dictionary_map()) {
    597     // Don't set enumeration index (it will be set during value store).
    598     property_details_ =
    599         PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
    600   } else {
    601     property_details_ = transition->GetLastDescriptorDetails();
    602     has_property_ = true;
    603   }
    604 }
    605 
    606 void LookupIterator::ApplyTransitionToDataProperty(
    607     Handle<JSReceiver> receiver) {
    608   DCHECK_EQ(TRANSITION, state_);
    609 
    610   DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
    611   holder_ = receiver;
    612   if (receiver->IsJSGlobalObject()) {
    613     JSObject::InvalidatePrototypeChains(receiver->map());
    614     state_ = DATA;
    615     return;
    616   }
    617   Handle<Map> transition = transition_map();
    618   bool simple_transition = transition->GetBackPointer() == receiver->map();
    619 
    620   if (configuration_ == DEFAULT && !transition->is_dictionary_map() &&
    621       !transition->IsPrototypeValidityCellValid()) {
    622     // Only LookupIterator instances with DEFAULT (full prototype chain)
    623     // configuration can produce valid transition handler maps.
    624     Handle<Object> validity_cell =
    625         Map::GetOrCreatePrototypeChainValidityCell(transition, isolate());
    626     transition->set_prototype_validity_cell(*validity_cell);
    627   }
    628 
    629   if (!receiver->IsJSProxy()) {
    630     JSObject::MigrateToMap(Handle<JSObject>::cast(receiver), transition);
    631   }
    632 
    633   if (simple_transition) {
    634     int number = transition->LastAdded();
    635     number_ = static_cast<uint32_t>(number);
    636     property_details_ = transition->GetLastDescriptorDetails();
    637     state_ = DATA;
    638   } else if (receiver->map()->is_dictionary_map()) {
    639     Handle<NameDictionary> dictionary(receiver->property_dictionary(),
    640                                       isolate_);
    641     int entry;
    642     if (receiver->map()->is_prototype_map() && receiver->IsJSObject()) {
    643       JSObject::InvalidatePrototypeChains(receiver->map());
    644     }
    645     dictionary = NameDictionary::Add(isolate(), dictionary, name(),
    646                                      isolate_->factory()->uninitialized_value(),
    647                                      property_details_, &entry);
    648     receiver->SetProperties(*dictionary);
    649     // Reload details containing proper enumeration index value.
    650     property_details_ = dictionary->DetailsAt(entry);
    651     number_ = entry;
    652     has_property_ = true;
    653     state_ = DATA;
    654 
    655   } else {
    656     ReloadPropertyInformation<false>();
    657   }
    658 }
    659 
    660 
    661 void LookupIterator::Delete() {
    662   Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
    663   if (IsElement()) {
    664     Handle<JSObject> object = Handle<JSObject>::cast(holder);
    665     ElementsAccessor* accessor = object->GetElementsAccessor();
    666     accessor->Delete(object, number_);
    667   } else {
    668     DCHECK(!name()->IsPrivateField());
    669     bool is_prototype_map = holder->map()->is_prototype_map();
    670     RuntimeCallTimerScope stats_scope(
    671         isolate_, is_prototype_map
    672                       ? RuntimeCallCounterId::kPrototypeObject_DeleteProperty
    673                       : RuntimeCallCounterId::kObject_DeleteProperty);
    674 
    675     PropertyNormalizationMode mode =
    676         is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
    677 
    678     if (holder->HasFastProperties()) {
    679       JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
    680                                     "DeletingProperty");
    681       ReloadPropertyInformation<false>();
    682     }
    683     JSReceiver::DeleteNormalizedProperty(holder, number_);
    684     if (holder->IsJSObject()) {
    685       JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
    686     }
    687   }
    688   state_ = NOT_FOUND;
    689 }
    690 
    691 void LookupIterator::TransitionToAccessorProperty(
    692     Handle<Object> getter, Handle<Object> setter,
    693     PropertyAttributes attributes) {
    694   DCHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
    695   // Can only be called when the receiver is a JSObject. JSProxy has to be
    696   // handled via a trap. Adding properties to primitive values is not
    697   // observable.
    698   Handle<JSObject> receiver = GetStoreTarget<JSObject>();
    699   if (!IsElement() && name()->IsPrivate()) {
    700     attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
    701   }
    702 
    703   if (!IsElement() && !receiver->map()->is_dictionary_map()) {
    704     Handle<Map> old_map(receiver->map(), isolate_);
    705 
    706     if (!holder_.is_identical_to(receiver)) {
    707       holder_ = receiver;
    708       state_ = NOT_FOUND;
    709     } else if (state_ == INTERCEPTOR) {
    710       LookupInRegularHolder<false>(*old_map, *holder_);
    711     }
    712     int descriptor =
    713         IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound;
    714 
    715     Handle<Map> new_map = Map::TransitionToAccessorProperty(
    716         isolate_, old_map, name_, descriptor, getter, setter, attributes);
    717     bool simple_transition = new_map->GetBackPointer() == receiver->map();
    718     JSObject::MigrateToMap(receiver, new_map);
    719 
    720     if (simple_transition) {
    721       int number = new_map->LastAdded();
    722       number_ = static_cast<uint32_t>(number);
    723       property_details_ = new_map->GetLastDescriptorDetails();
    724       state_ = ACCESSOR;
    725       return;
    726     }
    727 
    728     ReloadPropertyInformation<false>();
    729     if (!new_map->is_dictionary_map()) return;
    730   }
    731 
    732   Handle<AccessorPair> pair;
    733   if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
    734     pair = Handle<AccessorPair>::cast(GetAccessors());
    735     // If the component and attributes are identical, nothing has to be done.
    736     if (pair->Equals(*getter, *setter)) {
    737       if (property_details().attributes() == attributes) {
    738         if (!IsElement()) JSObject::ReoptimizeIfPrototype(receiver);
    739         return;
    740       }
    741     } else {
    742       pair = AccessorPair::Copy(isolate(), pair);
    743       pair->SetComponents(*getter, *setter);
    744     }
    745   } else {
    746     pair = factory()->NewAccessorPair();
    747     pair->SetComponents(*getter, *setter);
    748   }
    749 
    750   TransitionToAccessorPair(pair, attributes);
    751 
    752 #if VERIFY_HEAP
    753   if (FLAG_verify_heap) {
    754     receiver->JSObjectVerify(isolate());
    755   }
    756 #endif
    757 }
    758 
    759 
    760 void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
    761                                               PropertyAttributes attributes) {
    762   Handle<JSObject> receiver = GetStoreTarget<JSObject>();
    763   holder_ = receiver;
    764 
    765   PropertyDetails details(kAccessor, attributes, PropertyCellType::kMutable);
    766 
    767   if (IsElement()) {
    768     // TODO(verwaest): Move code into the element accessor.
    769     isolate_->CountUsage(v8::Isolate::kIndexAccessor);
    770     Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(receiver);
    771 
    772     dictionary = NumberDictionary::Set(isolate_, dictionary, index_, pair,
    773                                        receiver, details);
    774     receiver->RequireSlowElements(*dictionary);
    775 
    776     if (receiver->HasSlowArgumentsElements()) {
    777       FixedArray* parameter_map = FixedArray::cast(receiver->elements());
    778       uint32_t length = parameter_map->length() - 2;
    779       if (number_ < length) {
    780         parameter_map->set(number_ + 2, ReadOnlyRoots(heap()).the_hole_value());
    781       }
    782       FixedArray::cast(receiver->elements())->set(1, *dictionary);
    783     } else {
    784       receiver->set_elements(*dictionary);
    785     }
    786 
    787     ReloadPropertyInformation<true>();
    788   } else {
    789     PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES;
    790     if (receiver->map()->is_prototype_map()) {
    791       JSObject::InvalidatePrototypeChains(receiver->map());
    792       mode = KEEP_INOBJECT_PROPERTIES;
    793     }
    794 
    795     // Normalize object to make this operation simple.
    796     JSObject::NormalizeProperties(receiver, mode, 0,
    797                                   "TransitionToAccessorPair");
    798 
    799     JSObject::SetNormalizedProperty(receiver, name_, pair, details);
    800     JSObject::ReoptimizeIfPrototype(receiver);
    801 
    802     ReloadPropertyInformation<false>();
    803   }
    804 }
    805 
    806 bool LookupIterator::HolderIsReceiver() const {
    807   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
    808   // Optimization that only works if configuration_ is not mutable.
    809   if (!check_prototype_chain()) return true;
    810   return *receiver_ == *holder_;
    811 }
    812 
    813 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
    814   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
    815   // Optimization that only works if configuration_ is not mutable.
    816   if (!check_prototype_chain()) return true;
    817   DisallowHeapAllocation no_gc;
    818   if (*receiver_ == *holder_) return true;
    819   if (!receiver_->IsJSReceiver()) return false;
    820   JSReceiver* current = JSReceiver::cast(*receiver_);
    821   JSReceiver* object = *holder_;
    822   if (!current->map()->has_hidden_prototype()) return false;
    823   // JSProxy do not occur as hidden prototypes.
    824   if (object->IsJSProxy()) return false;
    825   PrototypeIterator iter(isolate(), current, kStartAtPrototype,
    826                          PrototypeIterator::END_AT_NON_HIDDEN);
    827   while (!iter.IsAtEnd()) {
    828     if (iter.GetCurrent<JSReceiver>() == object) return true;
    829     iter.Advance();
    830   }
    831   return false;
    832 }
    833 
    834 
    835 Handle<Object> LookupIterator::FetchValue() const {
    836   Object* result = nullptr;
    837   if (IsElement()) {
    838     Handle<JSObject> holder = GetHolder<JSObject>();
    839     ElementsAccessor* accessor = holder->GetElementsAccessor();
    840     return accessor->Get(holder, number_);
    841   } else if (holder_->IsJSGlobalObject()) {
    842     Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
    843     result = holder->global_dictionary()->ValueAt(number_);
    844   } else if (!holder_->HasFastProperties()) {
    845     result = holder_->property_dictionary()->ValueAt(number_);
    846   } else if (property_details_.location() == kField) {
    847     DCHECK_EQ(kData, property_details_.kind());
    848     Handle<JSObject> holder = GetHolder<JSObject>();
    849     FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
    850     return JSObject::FastPropertyAt(holder, property_details_.representation(),
    851                                     field_index);
    852   } else {
    853     result = holder_->map()->instance_descriptors()->GetStrongValue(number_);
    854   }
    855   return handle(result, isolate_);
    856 }
    857 
    858 bool LookupIterator::IsConstFieldValueEqualTo(Object* value) const {
    859   DCHECK(!IsElement());
    860   DCHECK(holder_->HasFastProperties());
    861   DCHECK_EQ(kField, property_details_.location());
    862   DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
    863   Handle<JSObject> holder = GetHolder<JSObject>();
    864   FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
    865   if (property_details_.representation().IsDouble()) {
    866     if (!value->IsNumber()) return false;
    867     uint64_t bits;
    868     if (holder->IsUnboxedDoubleField(field_index)) {
    869       bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
    870     } else {
    871       Object* current_value = holder->RawFastPropertyAt(field_index);
    872       DCHECK(current_value->IsMutableHeapNumber());
    873       bits = MutableHeapNumber::cast(current_value)->value_as_bits();
    874     }
    875     // Use bit representation of double to to check for hole double, since
    876     // manipulating the signaling NaN used for the hole in C++, e.g. with
    877     // bit_cast or value(), will change its value on ia32 (the x87 stack is
    878     // used to return values and stores to the stack silently clear the
    879     // signalling bit).
    880     if (bits == kHoleNanInt64) {
    881       // Uninitialized double field.
    882       return true;
    883     }
    884     return bit_cast<double>(bits) == value->Number();
    885   } else {
    886     Object* current_value = holder->RawFastPropertyAt(field_index);
    887     return current_value->IsUninitialized(isolate()) || current_value == value;
    888   }
    889 }
    890 
    891 int LookupIterator::GetFieldDescriptorIndex() const {
    892   DCHECK(has_property_);
    893   DCHECK(holder_->HasFastProperties());
    894   DCHECK_EQ(kField, property_details_.location());
    895   DCHECK_EQ(kData, property_details_.kind());
    896   return descriptor_number();
    897 }
    898 
    899 int LookupIterator::GetAccessorIndex() const {
    900   DCHECK(has_property_);
    901   DCHECK(holder_->HasFastProperties());
    902   DCHECK_EQ(kDescriptor, property_details_.location());
    903   DCHECK_EQ(kAccessor, property_details_.kind());
    904   return descriptor_number();
    905 }
    906 
    907 
    908 int LookupIterator::GetConstantIndex() const {
    909   DCHECK(has_property_);
    910   DCHECK(holder_->HasFastProperties());
    911   DCHECK_EQ(kDescriptor, property_details_.location());
    912   DCHECK_EQ(kData, property_details_.kind());
    913   DCHECK(!FLAG_track_constant_fields);
    914   DCHECK(!IsElement());
    915   return descriptor_number();
    916 }
    917 
    918 Handle<Map> LookupIterator::GetFieldOwnerMap() const {
    919   DCHECK(has_property_);
    920   DCHECK(holder_->HasFastProperties());
    921   DCHECK_EQ(kField, property_details_.location());
    922   DCHECK(!IsElement());
    923   Map* holder_map = holder_->map();
    924   return handle(holder_map->FindFieldOwner(isolate(), descriptor_number()),
    925                 isolate_);
    926 }
    927 
    928 FieldIndex LookupIterator::GetFieldIndex() const {
    929   DCHECK(has_property_);
    930   DCHECK(holder_->HasFastProperties());
    931   DCHECK_EQ(kField, property_details_.location());
    932   DCHECK(!IsElement());
    933   return FieldIndex::ForDescriptor(holder_->map(), descriptor_number());
    934 }
    935 
    936 Handle<FieldType> LookupIterator::GetFieldType() const {
    937   DCHECK(has_property_);
    938   DCHECK(holder_->HasFastProperties());
    939   DCHECK_EQ(kField, property_details_.location());
    940   return handle(
    941       holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()),
    942       isolate_);
    943 }
    944 
    945 
    946 Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
    947   DCHECK(!IsElement());
    948   Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
    949   return handle(holder->global_dictionary()->CellAt(dictionary_entry()),
    950                 isolate_);
    951 }
    952 
    953 
    954 Handle<Object> LookupIterator::GetAccessors() const {
    955   DCHECK_EQ(ACCESSOR, state_);
    956   return FetchValue();
    957 }
    958 
    959 
    960 Handle<Object> LookupIterator::GetDataValue() const {
    961   DCHECK_EQ(DATA, state_);
    962   Handle<Object> value = FetchValue();
    963   return value;
    964 }
    965 
    966 void LookupIterator::WriteDataValue(Handle<Object> value,
    967                                     bool initializing_store) {
    968   DCHECK_EQ(DATA, state_);
    969   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
    970   if (IsElement()) {
    971     Handle<JSObject> object = Handle<JSObject>::cast(holder);
    972     ElementsAccessor* accessor = object->GetElementsAccessor();
    973     accessor->Set(object, number_, *value);
    974   } else if (holder->HasFastProperties()) {
    975     if (property_details_.location() == kField) {
    976       // Check that in case of VariableMode::kConst field the existing value is
    977       // equal to |value|.
    978       DCHECK_IMPLIES(!initializing_store && property_details_.constness() ==
    979                                                 PropertyConstness::kConst,
    980                      IsConstFieldValueEqualTo(*value));
    981       JSObject::cast(*holder)->WriteToField(descriptor_number(),
    982                                             property_details_, *value);
    983     } else {
    984       DCHECK_EQ(kDescriptor, property_details_.location());
    985       DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
    986     }
    987   } else if (holder->IsJSGlobalObject()) {
    988     GlobalDictionary* dictionary =
    989         JSGlobalObject::cast(*holder)->global_dictionary();
    990     dictionary->CellAt(dictionary_entry())->set_value(*value);
    991   } else {
    992     DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
    993     NameDictionary* dictionary = holder->property_dictionary();
    994     dictionary->ValueAtPut(dictionary_entry(), *value);
    995   }
    996 }
    997 
    998 template <bool is_element>
    999 bool LookupIterator::SkipInterceptor(JSObject* holder) {
   1000   auto info = GetInterceptor<is_element>(holder);
   1001   if (!is_element && name_->IsSymbol() && !info->can_intercept_symbols()) {
   1002     return true;
   1003   }
   1004   if (info->non_masking()) {
   1005     switch (interceptor_state_) {
   1006       case InterceptorState::kUninitialized:
   1007         interceptor_state_ = InterceptorState::kSkipNonMasking;
   1008         V8_FALLTHROUGH;
   1009       case InterceptorState::kSkipNonMasking:
   1010         return true;
   1011       case InterceptorState::kProcessNonMasking:
   1012         return false;
   1013     }
   1014   }
   1015   return interceptor_state_ == InterceptorState::kProcessNonMasking;
   1016 }
   1017 
   1018 JSReceiver* LookupIterator::NextHolder(Map* map) {
   1019   DisallowHeapAllocation no_gc;
   1020   if (map->prototype() == ReadOnlyRoots(heap()).null_value()) return nullptr;
   1021   if (!check_prototype_chain() && !map->has_hidden_prototype()) return nullptr;
   1022   return JSReceiver::cast(map->prototype());
   1023 }
   1024 
   1025 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const {
   1026   DCHECK(!IsElement());
   1027   if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
   1028 
   1029   Handle<String> name_string = Handle<String>::cast(name_);
   1030   if (name_string->length() == 0) return NOT_FOUND;
   1031 
   1032   return IsSpecialIndex(isolate_->unicode_cache(), *name_string)
   1033              ? INTEGER_INDEXED_EXOTIC
   1034              : NOT_FOUND;
   1035 }
   1036 
   1037 namespace {
   1038 
   1039 template <bool is_element>
   1040 bool HasInterceptor(Map* map) {
   1041   return is_element ? map->has_indexed_interceptor()
   1042                     : map->has_named_interceptor();
   1043 }
   1044 
   1045 }  // namespace
   1046 
   1047 template <bool is_element>
   1048 LookupIterator::State LookupIterator::LookupInSpecialHolder(
   1049     Map* const map, JSReceiver* const holder) {
   1050   STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
   1051   switch (state_) {
   1052     case NOT_FOUND:
   1053       if (map->IsJSProxyMap()) {
   1054         if (is_element || !name_->IsPrivate()) return JSPROXY;
   1055       }
   1056       if (map->is_access_check_needed()) {
   1057         if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
   1058       }
   1059       V8_FALLTHROUGH;
   1060     case ACCESS_CHECK:
   1061       if (check_interceptor() && HasInterceptor<is_element>(map) &&
   1062           !SkipInterceptor<is_element>(JSObject::cast(holder))) {
   1063         if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
   1064       }
   1065       V8_FALLTHROUGH;
   1066     case INTERCEPTOR:
   1067       if (!is_element && map->IsJSGlobalObjectMap()) {
   1068         GlobalDictionary* dict =
   1069             JSGlobalObject::cast(holder)->global_dictionary();
   1070         int number = dict->FindEntry(isolate(), name_);
   1071         if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
   1072         number_ = static_cast<uint32_t>(number);
   1073         PropertyCell* cell = dict->CellAt(number_);
   1074         if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
   1075         property_details_ = cell->property_details();
   1076         has_property_ = true;
   1077         switch (property_details_.kind()) {
   1078           case v8::internal::kData:
   1079             return DATA;
   1080           case v8::internal::kAccessor:
   1081             return ACCESSOR;
   1082         }
   1083       }
   1084       return LookupInRegularHolder<is_element>(map, holder);
   1085     case ACCESSOR:
   1086     case DATA:
   1087       return NOT_FOUND;
   1088     case INTEGER_INDEXED_EXOTIC:
   1089     case JSPROXY:
   1090     case TRANSITION:
   1091       UNREACHABLE();
   1092   }
   1093   UNREACHABLE();
   1094 }
   1095 
   1096 template <bool is_element>
   1097 LookupIterator::State LookupIterator::LookupInRegularHolder(
   1098     Map* const map, JSReceiver* const holder) {
   1099   DisallowHeapAllocation no_gc;
   1100   if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
   1101     return NOT_FOUND;
   1102   }
   1103 
   1104   if (is_element) {
   1105     JSObject* js_object = JSObject::cast(holder);
   1106     ElementsAccessor* accessor = js_object->GetElementsAccessor();
   1107     FixedArrayBase* backing_store = js_object->elements();
   1108     number_ =
   1109         accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
   1110     if (number_ == kMaxUInt32) {
   1111       return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
   1112     }
   1113     property_details_ = accessor->GetDetails(js_object, number_);
   1114   } else if (!map->is_dictionary_map()) {
   1115     DescriptorArray* descriptors = map->instance_descriptors();
   1116     int number = descriptors->SearchWithCache(isolate_, *name_, map);
   1117     if (number == DescriptorArray::kNotFound) return NotFound(holder);
   1118     number_ = static_cast<uint32_t>(number);
   1119     property_details_ = descriptors->GetDetails(number_);
   1120   } else {
   1121     DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
   1122     NameDictionary* dict = holder->property_dictionary();
   1123     int number = dict->FindEntry(isolate(), name_);
   1124     if (number == NameDictionary::kNotFound) return NotFound(holder);
   1125     number_ = static_cast<uint32_t>(number);
   1126     property_details_ = dict->DetailsAt(number_);
   1127   }
   1128   has_property_ = true;
   1129   switch (property_details_.kind()) {
   1130     case v8::internal::kData:
   1131       return DATA;
   1132     case v8::internal::kAccessor:
   1133       return ACCESSOR;
   1134   }
   1135 
   1136   UNREACHABLE();
   1137 }
   1138 
   1139 Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
   1140     const {
   1141   DCHECK_EQ(ACCESS_CHECK, state_);
   1142   DisallowHeapAllocation no_gc;
   1143   AccessCheckInfo* access_check_info =
   1144       AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
   1145   if (access_check_info) {
   1146     Object* interceptor = IsElement() ? access_check_info->indexed_interceptor()
   1147                                       : access_check_info->named_interceptor();
   1148     if (interceptor) {
   1149       return handle(InterceptorInfo::cast(interceptor), isolate_);
   1150     }
   1151   }
   1152   return Handle<InterceptorInfo>();
   1153 }
   1154 
   1155 bool LookupIterator::TryLookupCachedProperty() {
   1156   return state() == LookupIterator::ACCESSOR &&
   1157          GetAccessors()->IsAccessorPair() && LookupCachedProperty();
   1158 }
   1159 
   1160 bool LookupIterator::LookupCachedProperty() {
   1161   DCHECK_EQ(state(), LookupIterator::ACCESSOR);
   1162   DCHECK(GetAccessors()->IsAccessorPair());
   1163 
   1164   AccessorPair* accessor_pair = AccessorPair::cast(*GetAccessors());
   1165   Handle<Object> getter(accessor_pair->getter(), isolate());
   1166   MaybeHandle<Name> maybe_name =
   1167       FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
   1168   if (maybe_name.is_null()) return false;
   1169 
   1170   // We have found a cached property! Modify the iterator accordingly.
   1171   name_ = maybe_name.ToHandleChecked();
   1172   Restart();
   1173   CHECK_EQ(state(), LookupIterator::DATA);
   1174   return true;
   1175 }
   1176 
   1177 }  // namespace internal
   1178 }  // namespace v8
   1179