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
PropertyOrElement(Isolate * isolate,Handle<Object> receiver,Handle<Object> key,bool * success,Handle<JSReceiver> holder,Configuration configuration)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
PropertyOrElement(Isolate * isolate,Handle<Object> receiver,Handle<Object> key,bool * success,Configuration configuration)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
ForTransitionHandler(Isolate * isolate,Handle<Object> receiver,Handle<Name> name,Handle<Object> value,MaybeHandle<Map> maybe_transition_map)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 
LookupIterator(Isolate * isolate,Handle<Object> receiver,Handle<Name> name,Handle<Map> transition_map,PropertyDetails details,bool has_property)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>
Start()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 
Next()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>
NextInternal(Map * map,JSReceiver * holder)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>
RestartInternal(InterceptorState interceptor_state)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
GetRootForNonJSReceiver(Isolate * isolate,Handle<Object> receiver,uint32_t index)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 
GetReceiverMap() const236 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 
HasAccess() const241 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>
ReloadPropertyInformation()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 
IsTypedArrayFunctionInAnyContext(Isolate * isolate,JSReceiver * holder)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 
InternalUpdateProtector()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 
PrepareForDataProperty(Handle<Object> value)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 
ReconfigureDataProperty(Handle<Object> value,PropertyAttributes attributes)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.
PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,Handle<Object> value,PropertyAttributes attributes,Object::StoreFromKeyed store_mode)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 
ApplyTransitionToDataProperty(Handle<JSReceiver> receiver)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 
Delete()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 
TransitionToAccessorProperty(Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)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 
TransitionToAccessorPair(Handle<Object> pair,PropertyAttributes attributes)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 
HolderIsReceiver() const806 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 
HolderIsReceiverOrHiddenPrototype() const813 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 
FetchValue() const835 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 
IsConstFieldValueEqualTo(Object * value) const858 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 
GetFieldDescriptorIndex() const891 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 
GetAccessorIndex() const899 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 
GetConstantIndex() const908 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 
GetFieldOwnerMap() const918 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 
GetFieldIndex() const928 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 
GetFieldType() const936 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 
GetPropertyCell() const946 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 
GetAccessors() const954 Handle<Object> LookupIterator::GetAccessors() const {
955   DCHECK_EQ(ACCESSOR, state_);
956   return FetchValue();
957 }
958 
959 
GetDataValue() const960 Handle<Object> LookupIterator::GetDataValue() const {
961   DCHECK_EQ(DATA, state_);
962   Handle<Object> value = FetchValue();
963   return value;
964 }
965 
WriteDataValue(Handle<Object> value,bool initializing_store)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>
SkipInterceptor(JSObject * holder)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 
NextHolder(Map * map)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 
NotFound(JSReceiver * const holder) const1025 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>
HasInterceptor(Map * map)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>
LookupInSpecialHolder(Map * const map,JSReceiver * const holder)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>
LookupInRegularHolder(Map * const map,JSReceiver * const holder)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 
GetInterceptorForFailedAccessCheck() const1139 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 
TryLookupCachedProperty()1155 bool LookupIterator::TryLookupCachedProperty() {
1156   return state() == LookupIterator::ACCESSOR &&
1157          GetAccessors()->IsAccessorPair() && LookupCachedProperty();
1158 }
1159 
LookupCachedProperty()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