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