LCOV - code coverage report
Current view: top level - src - lookup.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 479 519 92.3 %
Date: 2019-03-21 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        4722 : LookupIterator LookupIterator::PropertyOrElement(
      22             :     Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      23             :     bool* success, Handle<JSReceiver> holder, Configuration configuration) {
      24        4722 :   uint32_t index = 0;
      25        9444 :   if (key->ToArrayIndex(&index)) {
      26        1881 :     *success = true;
      27        1881 :     return LookupIterator(isolate, receiver, index, holder, configuration);
      28             :   }
      29             : 
      30             :   Handle<Name> name;
      31        5682 :   *success = Object::ToName(isolate, key).ToHandle(&name);
      32        2841 :   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        2823 :   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    38473006 : 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    38473006 :   uint32_t index = 0;
      58    76946012 :   if (key->ToArrayIndex(&index)) {
      59    32152279 :     *success = true;
      60    32152279 :     return LookupIterator(isolate, receiver, index, configuration);
      61             :   }
      62             : 
      63             :   Handle<Name> name;
      64    12641458 :   *success = Object::ToName(isolate, key).ToHandle(&name);
      65     6320731 :   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     6320681 :   if (name->AsArrayIndex(&index)) {
      73      349019 :     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      349019 :     it.name_ = name;
      77      349019 :     return it;
      78             :   }
      79             : 
      80     5971663 :   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           0 :       !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   181445953 : void LookupIterator::Start() {
     147             :   DisallowHeapAllocation no_gc;
     148             : 
     149   181445953 :   has_property_ = false;
     150   181445953 :   state_ = NOT_FOUND;
     151   181445953 :   holder_ = initial_holder_;
     152             : 
     153             :   JSReceiver holder = *holder_;
     154   181445953 :   Map map = holder->map();
     155             : 
     156   181445953 :   state_ = LookupInHolder<is_element>(map, holder);
     157   221124957 :   if (IsFound()) return;
     158             : 
     159   141767129 :   NextInternal<is_element>(map, holder);
     160             : }
     161             : 
     162             : template void LookupIterator::Start<true>();
     163             : template void LookupIterator::Start<false>();
     164             : 
     165     7167099 : void LookupIterator::Next() {
     166             :   DCHECK_NE(JSPROXY, state_);
     167             :   DCHECK_NE(TRANSITION, state_);
     168             :   DisallowHeapAllocation no_gc;
     169     7167099 :   has_property_ = false;
     170             : 
     171             :   JSReceiver holder = *holder_;
     172             :   Map map = holder->map();
     173             : 
     174     7167099 :   if (map->IsSpecialReceiverMap()) {
     175             :     state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
     176     6984470 :                          : LookupInSpecialHolder<false>(map, holder);
     177     6984470 :     if (IsFound()) return;
     178             :   }
     179             : 
     180      119957 :   IsElement() ? NextInternal<true>(map, holder)
     181    13088775 :               : NextInternal<false>(map, holder);
     182             : }
     183             : 
     184             : template <bool is_element>
     185   148371470 : void LookupIterator::NextInternal(Map map, JSReceiver holder) {
     186   176276545 :   do {
     187   315431609 :     JSReceiver maybe_holder = NextHolder(map);
     188   315431618 :     if (maybe_holder.is_null()) {
     189   139155107 :       if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
     190         156 :         RestartLookupForNonMaskingInterceptors<is_element>();
     191         156 :         return;
     192             :       }
     193   139154951 :       state_ = NOT_FOUND;
     194   225419741 :       if (holder != *holder_) holder_ = handle(holder, isolate_);
     195             :       return;
     196             :     }
     197             :     holder = maybe_holder;
     198   176276511 :     map = holder->map();
     199   176276511 :     state_ = LookupInHolder<is_element>(map, holder);
     200             :   } while (!IsFound());
     201             : 
     202    18432811 :   holder_ = handle(holder, isolate_);
     203             : }
     204             : 
     205             : template <bool is_element>
     206     1419657 : void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
     207     1419657 :   interceptor_state_ = interceptor_state;
     208     1419657 :   property_details_ = PropertyDetails::Empty();
     209     1419657 :   number_ = static_cast<uint32_t>(DescriptorArray::kNotFound);
     210     1419657 :   Start<is_element>();
     211     1419664 : }
     212             : 
     213             : template void LookupIterator::RestartInternal<true>(InterceptorState);
     214             : template void LookupIterator::RestartInternal<false>(InterceptorState);
     215             : 
     216             : // static
     217      370346 : 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      387525 :   if (index != kMaxUInt32 && receiver->IsString() &&
     222        3462 :       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        1387 :     Handle<JSFunction> constructor = isolate->string_function();
     226        1387 :     Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
     227        1387 :     Handle<JSValue>::cast(result)->set_value(*receiver);
     228        1387 :     return result;
     229             :   }
     230             :   auto root =
     231      737918 :       handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
     232      368959 :   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     6039117 : bool LookupIterator::HasAccess() const {
     245             :   DCHECK_EQ(ACCESS_CHECK, state_);
     246    12078234 :   return isolate_->MayAccess(handle(isolate_->context(), isolate_),
     247     6039117 :                              GetHolder<JSObject>());
     248             : }
     249             : 
     250             : template <bool is_element>
     251    11635879 : void LookupIterator::ReloadPropertyInformation() {
     252    11635879 :   state_ = BEFORE_PROPERTY;
     253    11635879 :   interceptor_state_ = InterceptorState::kUninitialized;
     254    11635879 :   state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
     255             :   DCHECK(IsFound() || !holder_->HasFastProperties());
     256    11635917 : }
     257             : 
     258             : namespace {
     259             : 
     260        3251 : 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        3251 :   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     4092302 : void LookupIterator::InternalUpdateProtector() {
     279     4092302 :   if (isolate_->bootstrapper()->IsActive()) return;
     280             : 
     281             :   ReadOnlyRoots roots(heap());
     282      134498 :   if (*name_ == roots.constructor_string()) {
     283      131112 :     if (!isolate_->IsArraySpeciesLookupChainIntact() &&
     284        5116 :         !isolate_->IsPromiseSpeciesLookupChainIntact() &&
     285      124999 :         !isolate_->IsRegExpSpeciesLookupChainIntact() &&
     286             :         !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
     287             :       return;
     288             :     }
     289             :     // Setting the constructor property could change an instance's @@species
     290      114767 :     if (holder_->IsJSArray()) {
     291         552 :       if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
     292             :       isolate_->CountUsage(
     293          93 :           v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
     294          93 :       isolate_->InvalidateArraySpeciesProtector();
     295          93 :       return;
     296      114491 :     } else if (holder_->IsJSPromise()) {
     297          28 :       if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
     298          10 :       isolate_->InvalidatePromiseSpeciesProtector();
     299          10 :       return;
     300      114477 :     } else if (holder_->IsJSRegExp()) {
     301           0 :       if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
     302           0 :       isolate_->InvalidateRegExpSpeciesProtector();
     303           0 :       return;
     304      114477 :     } else if (holder_->IsJSTypedArray()) {
     305         110 :       if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
     306          55 :       isolate_->InvalidateTypedArraySpeciesProtector();
     307          55 :       return;
     308             :     }
     309      114422 :     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        9030 :       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        9030 :       } else if (isolate_->IsInAnyContext(*holder_,
     323             :                                           Context::PROMISE_PROTOTYPE_INDEX)) {
     324         162 :         if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
     325          25 :         isolate_->InvalidatePromiseSpeciesProtector();
     326        8949 :       } else if (isolate_->IsInAnyContext(*holder_,
     327             :                                           Context::REGEXP_PROTOTYPE_INDEX)) {
     328         110 :         if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
     329          15 :         isolate_->InvalidateRegExpSpeciesProtector();
     330        8894 :       } else if (isolate_->IsInAnyContext(
     331             :                      holder_->map()->prototype(),
     332             :                      Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
     333        1202 :         if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
     334         135 :         isolate_->InvalidateTypedArraySpeciesProtector();
     335             :       }
     336             :     }
     337       14615 :   } else if (*name_ == roots.next_string()) {
     338        3750 :     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        3249 :     } else if (isolate_->IsInAnyContext(
     345             :                    *holder_, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) {
     346          60 :       if (!isolate_->IsMapIteratorLookupChainIntact()) return;
     347          25 :       isolate_->InvalidateMapIteratorProtector();
     348        3219 :     } else if (isolate_->IsInAnyContext(
     349             :                    *holder_, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX)) {
     350          60 :       if (!isolate_->IsSetIteratorLookupChainIntact()) return;
     351          25 :       isolate_->InvalidateSetIteratorProtector();
     352        3189 :     } 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       10865 :   } else if (*name_ == roots.species_symbol()) {
     361        3478 :     if (!isolate_->IsArraySpeciesLookupChainIntact() &&
     362           0 :         !isolate_->IsPromiseSpeciesLookupChainIntact() &&
     363        3358 :         !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        3358 :     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        3313 :     } else if (isolate_->IsInAnyContext(*holder_,
     375             :                                         Context::PROMISE_FUNCTION_INDEX)) {
     376          88 :       if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
     377          24 :       isolate_->InvalidatePromiseSpeciesProtector();
     378        3269 :     } else if (isolate_->IsInAnyContext(*holder_,
     379             :                                         Context::REGEXP_FUNCTION_INDEX)) {
     380          36 :       if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
     381          10 :       isolate_->InvalidateRegExpSpeciesProtector();
     382        3251 :     } else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
     383         220 :       if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
     384          55 :       isolate_->InvalidateTypedArraySpeciesProtector();
     385             :     }
     386        7507 :   } else if (*name_ == roots.is_concat_spreadable_symbol()) {
     387         868 :     if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
     388          65 :     isolate_->InvalidateIsConcatSpreadableProtector();
     389        6639 :   } else if (*name_ == roots.iterator_symbol()) {
     390        3225 :     if (holder_->IsJSArray()) {
     391        1552 :       if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
     392          83 :       isolate_->InvalidateArrayIteratorProtector();
     393        2449 :     } 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        2399 :     } else if (isolate_->IsInAnyContext(*holder_,
     402             :                                         Context::INITIAL_SET_PROTOTYPE_INDEX)) {
     403          30 :       if (!isolate_->IsSetIteratorLookupChainIntact()) return;
     404          10 :       isolate_->InvalidateSetIteratorProtector();
     405        2384 :     } 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     7450623 : 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    14895849 :   if (holder->IsJSProxy()) return;
     448             : 
     449             :   Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
     450             : 
     451     7450595 :   if (IsElement()) {
     452      923586 :     ElementsKind kind = holder_obj->GetElementsKind();
     453      923586 :     ElementsKind to = value->OptimalElementsKind();
     454      923586 :     if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
     455             :     to = GetMoreGeneralElementsKind(kind, to);
     456             : 
     457      923586 :     if (kind != to) {
     458       18514 :       JSObject::TransitionElementsKind(holder_obj, to);
     459             :     }
     460             : 
     461             :     // Copy the backing store if it is copy-on-write.
     462      923585 :     if (IsSmiOrObjectElementsKind(to)) {
     463      189794 :       JSObject::EnsureWritableFastElements(holder_obj);
     464             :     }
     465             :     return;
     466             :   }
     467             : 
     468     6527009 :   if (holder_obj->IsJSGlobalObject()) {
     469             :     Handle<GlobalDictionary> dictionary(
     470     9245266 :         JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
     471             :     Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()),
     472             :                               isolate());
     473     4622633 :     property_details_ = cell->property_details();
     474             :     PropertyCell::PrepareForValue(isolate(), dictionary, dictionary_entry(),
     475     4622633 :                                   value, property_details_);
     476             :     return;
     477             :   }
     478     1904376 :   if (!holder_obj->HasFastProperties()) return;
     479             : 
     480             :   PropertyConstness new_constness = PropertyConstness::kConst;
     481             :   if (FLAG_track_constant_fields) {
     482     1893255 :     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     1112299 :       if (!IsConstFieldValueEqualTo(*value))
     487             :         new_constness = PropertyConstness::kMutable;
     488             :     }
     489             :   } else {
     490             :     new_constness = PropertyConstness::kMutable;
     491             :   }
     492             : 
     493     1893255 :   Handle<Map> old_map(holder_obj->map(), isolate_);
     494             :   Handle<Map> new_map = Map::PrepareForDataProperty(
     495     1893255 :       isolate(), old_map, descriptor_number(), new_constness, value);
     496             : 
     497     1893256 :   if (old_map.is_identical_to(new_map)) {
     498             :     // Update the property details if the representation was None.
     499     2937985 :     if (constness() != new_constness || representation().IsNone()) {
     500             :       property_details_ =
     501     1016127 :           new_map->instance_descriptors()->GetDetails(descriptor_number());
     502             :     }
     503             :     return;
     504             :   }
     505             : 
     506        5398 :   JSObject::MigrateToMap(holder_obj, new_map);
     507        5398 :   ReloadPropertyInformation<false>();
     508             : }
     509             : 
     510             : 
     511       38560 : 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       38560 :   if (holder->IsJSProxy()) {
     520             :     DCHECK(name()->IsPrivate());
     521             :     return;
     522             :   }
     523             : 
     524             :   Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
     525       38560 :   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       19200 :   } else if (holder_obj->HasFastProperties()) {
     533       17637 :     Handle<Map> old_map(holder_obj->map(), isolate_);
     534             :     Handle<Map> new_map = Map::ReconfigureExistingProperty(
     535       17637 :         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       17637 :                                     PropertyConstness::kMutable, value);
     541       17637 :     JSObject::MigrateToMap(holder_obj, new_map);
     542       17637 :     ReloadPropertyInformation<false>();
     543             :   }
     544             : 
     545       57760 :   if (!IsElement() && !holder_obj->HasFastProperties()) {
     546             :     PropertyDetails details(kData, attributes, PropertyCellType::kMutable);
     547        2018 :     if (holder_obj->map()->is_prototype_map() &&
     548        2464 :         (property_details_.attributes() & READ_ONLY) == 0 &&
     549         446 :         (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        1563 :     if (holder_obj->IsJSGlobalObject()) {
     556             :       Handle<GlobalDictionary> dictionary(
     557         840 :           JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
     558             : 
     559             :       Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
     560         420 :           isolate(), dictionary, dictionary_entry(), value, details);
     561         420 :       cell->set_value(*value);
     562         420 :       property_details_ = cell->property_details();
     563             :     } else {
     564        2286 :       Handle<NameDictionary> dictionary(holder_obj->property_dictionary(),
     565        1143 :                                         isolate());
     566             :       PropertyDetails original_details =
     567        1143 :           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        3429 :       dictionary->SetEntry(isolate(), dictionary_entry(), *name(), *value,
     572        1143 :                            details);
     573        1143 :       property_details_ = details;
     574             :     }
     575        1563 :     state_ = DATA;
     576             :   }
     577             : 
     578       38560 :   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    33109418 : 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    33109418 :   if (state_ == TRANSITION) return;
     595             : 
     596    65227973 :   if (!IsElement() && name()->IsPrivate()) {
     597     2688265 :     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    32613982 :   Handle<Map> map(receiver->map(), isolate_);
     607             : 
     608             :   // Dictionary maps can always have additional data properties.
     609    32613994 :   if (map->is_dictionary_map()) {
     610    10429691 :     state_ = TRANSITION;
     611    10429691 :     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     8222052 :           global, name(), PropertyCellType::kUninitialized, &entry);
     617             :       Handle<GlobalDictionary> dictionary(global->global_dictionary(),
     618    24666135 :                                           isolate_);
     619             :       DCHECK(cell->value()->IsTheHole(isolate_));
     620             :       DCHECK(!value->IsTheHole(isolate_));
     621     8222045 :       transition_ = cell;
     622             :       // Assign an enumeration index to the property and update
     623             :       // SetNextEnumerationIndex.
     624             :       int index = dictionary->NextEnumerationIndex();
     625     8222044 :       dictionary->SetNextEnumerationIndex(index + 1);
     626             :       property_details_ = PropertyDetails(
     627     8222044 :           kData, attributes, PropertyCellType::kUninitialized, index);
     628             :       PropertyCellType new_type =
     629     8222044 :           PropertyCell::UpdatedType(isolate(), cell, value, property_details_);
     630     8222042 :       property_details_ = property_details_.set_cell_type(new_type);
     631    16444087 :       cell->set_property_details(property_details_);
     632     8222045 :       number_ = entry;
     633     8222045 :       has_property_ = true;
     634             :     } else {
     635             :       // Don't set enumeration index (it will be set during value store).
     636             :       property_details_ =
     637     2207639 :           PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
     638     2207639 :       transition_ = map;
     639             :     }
     640             :     return;
     641             :   }
     642             : 
     643             :   Handle<Map> transition =
     644    22184303 :       Map::TransitionToDataProperty(isolate_, map, name_, value, attributes,
     645    22184303 :                                     kDefaultFieldConstness, store_origin);
     646    22184264 :   state_ = TRANSITION;
     647    22184264 :   transition_ = transition;
     648             : 
     649    22184264 :   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    22163933 :     property_details_ = transition->GetLastDescriptorDetails();
     655    22163937 :     has_property_ = true;
     656             :   }
     657             : }
     658             : 
     659    32613398 : void LookupIterator::ApplyTransitionToDataProperty(
     660             :     Handle<JSReceiver> receiver) {
     661             :   DCHECK_EQ(TRANSITION, state_);
     662             : 
     663             :   DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
     664    32613398 :   holder_ = receiver;
     665    32613398 :   if (receiver->IsJSGlobalObject()) {
     666     8221493 :     JSObject::InvalidatePrototypeChains(receiver->map());
     667     8221501 :     state_ = DATA;
     668             :     return;
     669             :   }
     670             :   Handle<Map> transition = transition_map();
     671    48783822 :   bool simple_transition = transition->GetBackPointer() == receiver->map();
     672             : 
     673    51230920 :   if (configuration_ == DEFAULT && !transition->is_dictionary_map() &&
     674    25401531 :       !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      594082 :         Map::GetOrCreatePrototypeChainValidityCell(transition, isolate());
     679      594081 :     transition->set_prototype_validity_cell(*validity_cell);
     680             :   }
     681             : 
     682    24391915 :   if (!receiver->IsJSProxy()) {
     683    24391859 :     JSObject::MigrateToMap(Handle<JSObject>::cast(receiver), transition);
     684             :   }
     685             : 
     686    24391939 :   if (simple_transition) {
     687             :     int number = transition->LastAdded();
     688    12419340 :     number_ = static_cast<uint32_t>(number);
     689    12419340 :     property_details_ = transition->GetLastDescriptorDetails();
     690    12419338 :     state_ = DATA;
     691    11972599 :   } else if (receiver->map()->is_dictionary_map()) {
     692             :     Handle<NameDictionary> dictionary(receiver->property_dictionary(),
     693     6683910 :                                       isolate_);
     694             :     int entry;
     695     2507419 :     if (receiver->map()->is_prototype_map() && receiver->IsJSObject()) {
     696      279449 :       JSObject::InvalidatePrototypeChains(receiver->map());
     697             :     }
     698             :     dictionary = NameDictionary::Add(isolate(), dictionary, name(),
     699     2227970 :                                      isolate_->factory()->uninitialized_value(),
     700     2227970 :                                      property_details_, &entry);
     701     4455940 :     receiver->SetProperties(*dictionary);
     702             :     // Reload details containing proper enumeration index value.
     703     4455940 :     property_details_ = dictionary->DetailsAt(entry);
     704     2227970 :     number_ = entry;
     705     2227970 :     has_property_ = true;
     706     2227970 :     state_ = DATA;
     707             : 
     708             :   } else {
     709     9744629 :     ReloadPropertyInformation<false>();
     710             :   }
     711             : }
     712             : 
     713             : 
     714      157812 : void LookupIterator::Delete() {
     715             :   Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
     716      157812 :   if (IsElement()) {
     717             :     Handle<JSObject> object = Handle<JSObject>::cast(holder);
     718      103514 :     ElementsAccessor* accessor = object->GetElementsAccessor();
     719      103514 :     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       54298 :         isolate_, is_prototype_map
     725             :                       ? RuntimeCallCounterId::kPrototypeObject_DeleteProperty
     726      108596 :                       : RuntimeCallCounterId::kObject_DeleteProperty);
     727             : 
     728             :     PropertyNormalizationMode mode =
     729       54298 :         is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
     730             : 
     731       54298 :     if (holder->HasFastProperties()) {
     732             :       JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
     733       40576 :                                     "DeletingProperty");
     734       40576 :       ReloadPropertyInformation<false>();
     735             :     }
     736       54298 :     JSReceiver::DeleteNormalizedProperty(holder, number_);
     737       54298 :     if (holder->IsJSObject()) {
     738       54292 :       JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
     739             :     }
     740             :   }
     741      157812 :   state_ = NOT_FOUND;
     742      157812 : }
     743             : 
     744     1534356 : 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     1534356 :   Handle<JSObject> receiver = GetStoreTarget<JSObject>();
     752     3041298 :   if (!IsElement() && name()->IsPrivate()) {
     753          16 :     attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
     754             :   }
     755             : 
     756     3041302 :   if (!IsElement() && !receiver->map()->is_dictionary_map()) {
     757     1492964 :     Handle<Map> old_map(receiver->map(), isolate_);
     758             : 
     759     1492962 :     if (!holder_.is_identical_to(receiver)) {
     760           0 :       holder_ = receiver;
     761           0 :       state_ = NOT_FOUND;
     762     1492962 :     } else if (state_ == INTERCEPTOR) {
     763          37 :       LookupInRegularHolder<false>(*old_map, *holder_);
     764             :     }
     765             :     int descriptor =
     766     1492964 :         IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound;
     767             : 
     768             :     Handle<Map> new_map = Map::TransitionToAccessorProperty(
     769     1492964 :         isolate_, old_map, name_, descriptor, getter, setter, attributes);
     770     2985938 :     bool simple_transition = new_map->GetBackPointer() == receiver->map();
     771     1492969 :     JSObject::MigrateToMap(receiver, new_map);
     772             : 
     773     1492972 :     if (simple_transition) {
     774             :       int number = new_map->LastAdded();
     775       19787 :       number_ = static_cast<uint32_t>(number);
     776       19787 :       property_details_ = new_map->GetLastDescriptorDetails();
     777       19787 :       state_ = ACCESSOR;
     778       19787 :       return;
     779             :     }
     780             : 
     781     1473185 :     ReloadPropertyInformation<false>();
     782     1473186 :     if (!new_map->is_dictionary_map()) return;
     783             :   }
     784             : 
     785             :   Handle<AccessorPair> pair;
     786      283323 :   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      261362 :     pair = factory()->NewAccessorPair();
     800      261362 :     pair->SetComponents(*getter, *setter);
     801             :   }
     802             : 
     803      272269 :   TransitionToAccessorPair(pair, attributes);
     804             : 
     805             : #if VERIFY_HEAP
     806             :   if (FLAG_verify_heap) {
     807             :     receiver->JSObjectVerify(isolate());
     808             :   }
     809             : #endif
     810             : }
     811             : 
     812             : 
     813      335124 : void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
     814             :                                               PropertyAttributes attributes) {
     815      335124 :   Handle<JSObject> receiver = GetStoreTarget<JSObject>();
     816      335124 :   holder_ = receiver;
     817             : 
     818             :   PropertyDetails details(kAccessor, attributes, PropertyCellType::kMutable);
     819             : 
     820      335124 :   if (IsElement()) {
     821             :     // TODO(verwaest): Move code into the element accessor.
     822       27423 :     isolate_->CountUsage(v8::Isolate::kIndexAccessor);
     823       27423 :     Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(receiver);
     824             : 
     825       27423 :     dictionary = NumberDictionary::Set(isolate_, dictionary, index_, pair,
     826       27423 :                                        receiver, details);
     827       27423 :     receiver->RequireSlowElements(*dictionary);
     828             : 
     829       54846 :     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       54648 :       receiver->set_elements(*dictionary);
     838             :     }
     839             : 
     840       27423 :     ReloadPropertyInformation<true>();
     841             :   } else {
     842             :     PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES;
     843      307701 :     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      307701 :                                   "TransitionToAccessorPair");
     851             : 
     852      307701 :     JSObject::SetNormalizedProperty(receiver, name_, pair, details);
     853      307701 :     JSObject::ReoptimizeIfPrototype(receiver);
     854             : 
     855      307701 :     ReloadPropertyInformation<false>();
     856             :   }
     857      335124 : }
     858             : 
     859       28940 : bool LookupIterator::HolderIsReceiver() const {
     860             :   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
     861             :   // Optimization that only works if configuration_ is not mutable.
     862       28940 :   if (!check_prototype_chain()) return true;
     863             :   return *receiver_ == *holder_;
     864             : }
     865             : 
     866     5418742 : bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
     867             :   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
     868             :   // Optimization that only works if configuration_ is not mutable.
     869     5418742 :   if (!check_prototype_chain()) return true;
     870             :   DisallowHeapAllocation no_gc;
     871     5402993 :   if (*receiver_ == *holder_) return true;
     872      201381 :   if (!receiver_->IsJSReceiver()) return false;
     873             :   JSReceiver current = JSReceiver::cast(*receiver_);
     874             :   JSReceiver object = *holder_;
     875      199366 :   if (!current->map()->has_hidden_prototype()) return false;
     876             :   // JSProxy do not occur as hidden prototypes.
     877        7534 :   if (object->IsJSProxy()) return false;
     878             :   PrototypeIterator iter(isolate(), current, kStartAtPrototype,
     879             :                          PrototypeIterator::END_AT_NON_HIDDEN);
     880        8526 :   while (!iter.IsAtEnd()) {
     881        7534 :     if (iter.GetCurrent<JSReceiver>() == object) return true;
     882         496 :     iter.Advance();
     883             :   }
     884             :   return false;
     885             : }
     886             : 
     887             : 
     888    25888875 : Handle<Object> LookupIterator::FetchValue() const {
     889             :   Object result;
     890    25888875 :   if (IsElement()) {
     891             :     Handle<JSObject> holder = GetHolder<JSObject>();
     892     5677236 :     ElementsAccessor* accessor = holder->GetElementsAccessor();
     893     5677236 :     return accessor->Get(holder, number_);
     894    20211639 :   } else if (holder_->IsJSGlobalObject()) {
     895             :     Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
     896    14374880 :     result = holder->global_dictionary()->ValueAt(number_);
     897    13024199 :   } else if (!holder_->HasFastProperties()) {
     898     1330628 :     result = holder_->property_dictionary()->ValueAt(number_);
     899    12358900 :   } else if (property_details_.location() == kField) {
     900             :     DCHECK_EQ(kData, property_details_.kind());
     901             :     Handle<JSObject> holder = GetHolder<JSObject>();
     902    19587296 :     FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
     903             :     return JSObject::FastPropertyAt(holder, property_details_.representation(),
     904     9793646 :                                     field_index);
     905             :   } else {
     906     5130504 :     result = holder_->map()->instance_descriptors()->GetStrongValue(number_);
     907             :   }
     908    10418011 :   return handle(result, isolate_);
     909             : }
     910             : 
     911     1112296 : 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     2224592 :   FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
     918     1112300 :   if (property_details_.representation().IsDouble()) {
     919        1428 :     if (!value->IsNumber()) return false;
     920             :     uint64_t bits;
     921             :     if (holder->IsUnboxedDoubleField(field_index)) {
     922             :       bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
     923             :     } else {
     924        1330 :       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        1330 :     if (bits == kHoleNanInt64) {
     934             :       // Uninitialized double field.
     935             :       return true;
     936             :     }
     937         556 :     return bit_cast<double>(bits) == value->Number();
     938             :   } else {
     939     1110872 :     Object current_value = holder->RawFastPropertyAt(field_index);
     940     1110870 :     return current_value->IsUninitialized(isolate()) || current_value == value;
     941             :   }
     942             : }
     943             : 
     944      506819 : int LookupIterator::GetFieldDescriptorIndex() const {
     945             :   DCHECK(has_property_);
     946             :   DCHECK(holder_->HasFastProperties());
     947             :   DCHECK_EQ(kField, property_details_.location());
     948             :   DCHECK_EQ(kData, property_details_.kind());
     949      506819 :   return descriptor_number();
     950             : }
     951             : 
     952      291140 : int LookupIterator::GetAccessorIndex() const {
     953             :   DCHECK(has_property_);
     954             :   DCHECK(holder_->HasFastProperties());
     955             :   DCHECK_EQ(kDescriptor, property_details_.location());
     956             :   DCHECK_EQ(kAccessor, property_details_.kind());
     957      291140 :   return descriptor_number();
     958             : }
     959             : 
     960             : 
     961           0 : int LookupIterator::GetConstantIndex() const {
     962             :   DCHECK(has_property_);
     963             :   DCHECK(holder_->HasFastProperties());
     964             :   DCHECK_EQ(kDescriptor, property_details_.location());
     965             :   DCHECK_EQ(kData, property_details_.kind());
     966             :   DCHECK(!FLAG_track_constant_fields);
     967             :   DCHECK(!IsElement());
     968           0 :   return descriptor_number();
     969             : }
     970             : 
     971           0 : Handle<Map> LookupIterator::GetFieldOwnerMap() const {
     972             :   DCHECK(has_property_);
     973             :   DCHECK(holder_->HasFastProperties());
     974             :   DCHECK_EQ(kField, property_details_.location());
     975             :   DCHECK(!IsElement());
     976           0 :   Map holder_map = holder_->map();
     977             :   return handle(holder_map->FindFieldOwner(isolate(), descriptor_number()),
     978           0 :                 isolate_);
     979             : }
     980             : 
     981     1481126 : FieldIndex LookupIterator::GetFieldIndex() const {
     982             :   DCHECK(has_property_);
     983             :   DCHECK(holder_->HasFastProperties());
     984             :   DCHECK_EQ(kField, property_details_.location());
     985             :   DCHECK(!IsElement());
     986     1481126 :   return FieldIndex::ForDescriptor(holder_->map(), descriptor_number());
     987             : }
     988             : 
     989           0 : Handle<FieldType> LookupIterator::GetFieldType() const {
     990             :   DCHECK(has_property_);
     991             :   DCHECK(holder_->HasFastProperties());
     992             :   DCHECK_EQ(kField, property_details_.location());
     993             :   return handle(
     994           0 :       holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()),
     995           0 :       isolate_);
     996             : }
     997             : 
     998             : 
     999     5691847 : Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
    1000             :   DCHECK(!IsElement());
    1001             :   Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
    1002    11383696 :   return handle(holder->global_dictionary()->CellAt(dictionary_entry()),
    1003    11383696 :                 isolate_);
    1004             : }
    1005             : 
    1006             : 
    1007     2477067 : Handle<Object> LookupIterator::GetAccessors() const {
    1008             :   DCHECK_EQ(ACCESSOR, state_);
    1009     3207910 :   return FetchValue();
    1010             : }
    1011             : 
    1012             : 
    1013    22680976 : Handle<Object> LookupIterator::GetDataValue() const {
    1014             :   DCHECK_EQ(DATA, state_);
    1015    22680976 :   Handle<Object> value = FetchValue();
    1016    22680967 :   return value;
    1017             : }
    1018             : 
    1019    37993265 : void LookupIterator::WriteDataValue(Handle<Object> value,
    1020             :                                     bool initializing_store) {
    1021             :   DCHECK_EQ(DATA, state_);
    1022             :   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
    1023    37993265 :   if (IsElement()) {
    1024             :     Handle<JSObject> object = Handle<JSObject>::cast(holder);
    1025      942946 :     ElementsAccessor* accessor = object->GetElementsAccessor();
    1026     1885892 :     accessor->Set(object, number_, *value);
    1027    37050319 :   } else if (holder->HasFastProperties()) {
    1028    23635915 :     if (property_details_.location() == kField) {
    1029             :       // Check that in case of VariableMode::kConst field the existing value is
    1030             :       // equal to |value|.
    1031             :       DCHECK_IMPLIES(!initializing_store && property_details_.constness() ==
    1032             :                                                 PropertyConstness::kConst,
    1033             :                      IsConstFieldValueEqualTo(*value));
    1034    47271837 :       JSObject::cast(*holder)->WriteToField(descriptor_number(),
    1035    23635923 :                                             property_details_, *value);
    1036             :     } else {
    1037             :       DCHECK_EQ(kDescriptor, property_details_.location());
    1038             :       DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
    1039             :     }
    1040    13414423 :   } else if (holder->IsJSGlobalObject()) {
    1041             :     GlobalDictionary dictionary =
    1042    11178641 :         JSGlobalObject::cast(*holder)->global_dictionary();
    1043    11178637 :     dictionary->CellAt(dictionary_entry())->set_value(*value);
    1044             :   } else {
    1045             :     DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
    1046     2235782 :     NameDictionary dictionary = holder->property_dictionary();
    1047             :     dictionary->ValueAtPut(dictionary_entry(), *value);
    1048             :   }
    1049    37993268 : }
    1050             : 
    1051             : template <bool is_element>
    1052      969214 : bool LookupIterator::SkipInterceptor(JSObject holder) {
    1053             :   auto info = GetInterceptor<is_element>(holder);
    1054      649191 :   if (!is_element && name_->IsSymbol() && !info->can_intercept_symbols()) {
    1055             :     return true;
    1056             :   }
    1057      969202 :   if (info->non_masking()) {
    1058         414 :     switch (interceptor_state_) {
    1059             :       case InterceptorState::kUninitialized:
    1060         258 :         interceptor_state_ = InterceptorState::kSkipNonMasking;
    1061             :         V8_FALLTHROUGH;
    1062             :       case InterceptorState::kSkipNonMasking:
    1063             :         return true;
    1064             :       case InterceptorState::kProcessNonMasking:
    1065             :         return false;
    1066             :     }
    1067             :   }
    1068      968788 :   return interceptor_state_ == InterceptorState::kProcessNonMasking;
    1069             : }
    1070             : 
    1071   315431646 : JSReceiver LookupIterator::NextHolder(Map map) {
    1072             :   DisallowHeapAllocation no_gc;
    1073   315431646 :   if (map->prototype() == ReadOnlyRoots(heap()).null_value()) {
    1074    94614202 :     return JSReceiver();
    1075             :   }
    1076   267695654 :   if (!check_prototype_chain() && !map->has_hidden_prototype()) {
    1077    44540935 :     return JSReceiver();
    1078             :   }
    1079             :   return JSReceiver::cast(map->prototype());
    1080             : }
    1081             : 
    1082    71368573 : LookupIterator::State LookupIterator::NotFound(JSReceiver const holder) const {
    1083             :   DCHECK(!IsElement());
    1084    71587813 :   if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
    1085      101634 :   return IsSpecialIndex(String::cast(*name_)) ? INTEGER_INDEXED_EXOTIC
    1086      101634 :                                               : NOT_FOUND;
    1087             : }
    1088             : 
    1089             : namespace {
    1090             : 
    1091             : template <bool is_element>
    1092             : bool HasInterceptor(Map map) {
    1093             :   return is_element ? map->has_indexed_interceptor()
    1094             :                     : map->has_named_interceptor();
    1095             : }
    1096             : 
    1097             : }  // namespace
    1098             : 
    1099             : template <bool is_element>
    1100    49620768 : LookupIterator::State LookupIterator::LookupInSpecialHolder(
    1101             :     Map const map, JSReceiver const holder) {
    1102             :   STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
    1103    49620768 :   switch (state_) {
    1104             :     case NOT_FOUND:
    1105    42626367 :       if (map->IsJSProxyMap()) {
    1106      372445 :         if (is_element || !name_->IsPrivate()) return JSPROXY;
    1107             :       }
    1108    42243682 :       if (map->is_access_check_needed()) {
    1109     8339556 :         if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
    1110             :       }
    1111             :       V8_FALLTHROUGH;
    1112             :     case ACCESS_CHECK:
    1113    63913120 :       if (check_interceptor() && HasInterceptor<is_element>(map) &&
    1114      969214 :           !SkipInterceptor<is_element>(JSObject::cast(holder))) {
    1115      648863 :         if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
    1116             :       }
    1117             :       V8_FALLTHROUGH;
    1118             :     case INTERCEPTOR:
    1119    39594922 :       if (!is_element && map->IsJSGlobalObjectMap()) {
    1120             :         GlobalDictionary dict =
    1121    32666468 :             JSGlobalObject::cast(holder)->global_dictionary();
    1122    32666466 :         int number = dict->FindEntry(isolate(), name_);
    1123    65332903 :         if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
    1124    15898525 :         number_ = static_cast<uint32_t>(number);
    1125             :         PropertyCell cell = dict->CellAt(number_);
    1126    31797052 :         if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
    1127    15864820 :         property_details_ = cell->property_details();
    1128    15864820 :         has_property_ = true;
    1129    15864820 :         switch (property_details_.kind()) {
    1130             :           case v8::internal::kData:
    1131             :             return DATA;
    1132             :           case v8::internal::kAccessor:
    1133       40742 :             return ACCESSOR;
    1134             :         }
    1135             :       }
    1136     7256705 :       return LookupInRegularHolder<is_element>(map, holder);
    1137             :     case ACCESSOR:
    1138             :     case DATA:
    1139             :       return NOT_FOUND;
    1140             :     case INTEGER_INDEXED_EXOTIC:
    1141             :     case JSPROXY:
    1142             :     case TRANSITION:
    1143           0 :       UNREACHABLE();
    1144             :   }
    1145           0 :   UNREACHABLE();
    1146             : }
    1147             : 
    1148             : template <bool is_element>
    1149   333978618 : LookupIterator::State LookupIterator::LookupInRegularHolder(
    1150             :     Map const map, JSReceiver const holder) {
    1151             :   DisallowHeapAllocation no_gc;
    1152   333978618 :   if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
    1153             :     return NOT_FOUND;
    1154             :   }
    1155             : 
    1156             :   if (is_element) {
    1157   234864295 :     JSObject js_object = JSObject::cast(holder);
    1158   234864295 :     ElementsAccessor* accessor = js_object->GetElementsAccessor();
    1159   234864295 :     FixedArrayBase backing_store = js_object->elements();
    1160   234864295 :     number_ =
    1161   234864295 :         accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
    1162   234864295 :     if (number_ == kMaxUInt32) {
    1163   227453260 :       return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
    1164             :     }
    1165     7411035 :     property_details_ = accessor->GetDetails(js_object, number_);
    1166    99114535 :   } else if (!map->is_dictionary_map()) {
    1167    95177952 :     DescriptorArray descriptors = map->instance_descriptors();
    1168    95177952 :     int number = descriptors->SearchWithCache(isolate_, *name_, map);
    1169    95177976 :     if (number == DescriptorArray::kNotFound) return NotFound(holder);
    1170    26752207 :     number_ = static_cast<uint32_t>(number);
    1171    26752207 :     property_details_ = descriptors->GetDetails(number_);
    1172             :   } else {
    1173             :     DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
    1174     3936583 :     NameDictionary dict = holder->property_dictionary();
    1175     3936583 :     int number = dict->FindEntry(isolate(), name_);
    1176     3936583 :     if (number == NameDictionary::kNotFound) return NotFound(holder);
    1177      993761 :     number_ = static_cast<uint32_t>(number);
    1178      993761 :     property_details_ = dict->DetailsAt(number_);
    1179             :   }
    1180    35157006 :   has_property_ = true;
    1181    35157006 :   switch (property_details_.kind()) {
    1182             :     case v8::internal::kData:
    1183             :       return DATA;
    1184             :     case v8::internal::kAccessor:
    1185     3738802 :       return ACCESSOR;
    1186             :   }
    1187             : 
    1188           0 :   UNREACHABLE();
    1189             : }
    1190             : 
    1191        1403 : Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
    1192             :     const {
    1193             :   DCHECK_EQ(ACCESS_CHECK, state_);
    1194             :   DisallowHeapAllocation no_gc;
    1195             :   AccessCheckInfo access_check_info =
    1196        1403 :       AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
    1197        1403 :   if (!access_check_info.is_null()) {
    1198             :     Object interceptor = IsElement() ? access_check_info->indexed_interceptor()
    1199        1102 :                                      : access_check_info->named_interceptor();
    1200        1102 :     if (interceptor != Object()) {
    1201         145 :       return handle(InterceptorInfo::cast(interceptor), isolate_);
    1202             :     }
    1203             :   }
    1204        1258 :   return Handle<InterceptorInfo>();
    1205             : }
    1206             : 
    1207     2388763 : bool LookupIterator::TryLookupCachedProperty() {
    1208      354698 :   return state() == LookupIterator::ACCESSOR &&
    1209     2742947 :          GetAccessors()->IsAccessorPair() && LookupCachedProperty();
    1210             : }
    1211             : 
    1212      354184 : bool LookupIterator::LookupCachedProperty() {
    1213             :   DCHECK_EQ(state(), LookupIterator::ACCESSOR);
    1214             :   DCHECK(GetAccessors()->IsAccessorPair());
    1215             : 
    1216             :   AccessorPair accessor_pair = AccessorPair::cast(*GetAccessors());
    1217             :   Handle<Object> getter(accessor_pair->getter(), isolate());
    1218             :   MaybeHandle<Name> maybe_name =
    1219      354184 :       FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
    1220      354185 :   if (maybe_name.is_null()) return false;
    1221             : 
    1222             :   // We have found a cached property! Modify the iterator accordingly.
    1223          78 :   name_ = maybe_name.ToHandleChecked();
    1224          78 :   Restart();
    1225          78 :   CHECK_EQ(state(), LookupIterator::DATA);
    1226             :   return true;
    1227             : }
    1228             : 
    1229             : }  // namespace internal
    1230      120216 : }  // namespace v8

Generated by: LCOV version 1.10