LCOV - code coverage report
Current view: top level - src - lookup.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 480 519 92.5 %
Date: 2019-04-18 Functions: 45 51 88.2 %

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

Generated by: LCOV version 1.10