LCOV - code coverage report
Current view: top level - src - lookup.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 507 560 90.5 %
Date: 2019-01-20 Functions: 46 52 88.5 %

          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        4751 : LookupIterator LookupIterator::PropertyOrElement(
      22             :     Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      23             :     bool* success, Handle<JSReceiver> holder, Configuration configuration) {
      24        4751 :   uint32_t index = 0;
      25        9502 :   if (key->ToArrayIndex(&index)) {
      26        1881 :     *success = true;
      27        1881 :     return LookupIterator(isolate, receiver, index, holder, configuration);
      28             :   }
      29             : 
      30             :   Handle<Name> name;
      31        5740 :   *success = Object::ToName(isolate, key).ToHandle(&name);
      32        2870 :   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        2852 :   if (name->AsArrayIndex(&index)) {
      40         306 :     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         306 :     it.name_ = name;
      44         306 :     return it;
      45             :   }
      46             : 
      47        2546 :   return LookupIterator(receiver, name, holder, configuration);
      48             : }
      49             : 
      50             : // static
      51    39541521 : 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    39541521 :   uint32_t index = 0;
      58    79083064 :   if (key->ToArrayIndex(&index)) {
      59    33219845 :     *success = true;
      60    33219845 :     return LookupIterator(isolate, receiver, index, configuration);
      61             :   }
      62             : 
      63             :   Handle<Name> name;
      64    12643379 :   *success = Object::ToName(isolate, key).ToHandle(&name);
      65     6321687 :   if (!*success) {
      66             :     DCHECK(isolate->has_pending_exception());
      67             :     // Return an unusable dummy.
      68             :     return LookupIterator(isolate, receiver,
      69          49 :                           isolate->factory()->empty_string());
      70             :   }
      71             : 
      72     6321640 :   if (name->AsArrayIndex(&index)) {
      73      349636 :     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      349636 :     it.name_ = name;
      77      349636 :     return it;
      78             :   }
      79             : 
      80     5972002 :   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           0 :   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           0 :                     has_property);
     113             : 
     114           0 :   if (!transition_map->is_dictionary_map()) {
     115           0 :     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           0 :     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   191623953 : void LookupIterator::Start() {
     147             :   DisallowHeapAllocation no_gc;
     148             : 
     149   191623953 :   has_property_ = false;
     150   191623953 :   state_ = NOT_FOUND;
     151   191623953 :   holder_ = initial_holder_;
     152             : 
     153             :   JSReceiver holder = *holder_;
     154   191623965 :   Map map = holder->map();
     155             : 
     156   191623965 :   state_ = LookupInHolder<is_element>(map, holder);
     157   232132663 :   if (IsFound()) return;
     158             : 
     159   151115333 :   NextInternal<is_element>(map, holder);
     160             : }
     161             : 
     162             : template void LookupIterator::Start<true>();
     163             : template void LookupIterator::Start<false>();
     164             : 
     165    20539263 : void LookupIterator::Next() {
     166             :   DCHECK_NE(JSPROXY, state_);
     167             :   DCHECK_NE(TRANSITION, state_);
     168             :   DisallowHeapAllocation no_gc;
     169     7095400 :   has_property_ = false;
     170             : 
     171             :   JSReceiver holder = *holder_;
     172             :   Map map = holder->map();
     173             : 
     174     7095400 :   if (map->IsSpecialReceiverMap()) {
     175             :     state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
     176     6911879 :                          : LookupInSpecialHolder<false>(map, holder);
     177    14007279 :     if (IsFound()) return;
     178             :   }
     179             : 
     180      112200 :   IsElement() ? NextInternal<true>(map, holder)
     181    12951768 :               : NextInternal<false>(map, holder);
     182             : }
     183             : 
     184             : template <bool is_element>
     185   157647301 : void LookupIterator::NextInternal(Map map, JSReceiver holder) {
     186   187483867 :   do {
     187   332915327 :     JSReceiver maybe_holder = NextHolder(map);
     188   332915347 :     if (maybe_holder.is_null()) {
     189   145431483 :       if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
     190           0 :         RestartLookupForNonMaskingInterceptors<is_element>();
     191    60608718 :         return;
     192             :       }
     193   145431327 :       state_ = NOT_FOUND;
     194   235968689 :       if (holder != *holder_) holder_ = handle(holder, isolate_);
     195             :       return;
     196             :     }
     197             :     holder = maybe_holder;
     198   187483864 :     map = holder->map();
     199   187483864 :     state_ = LookupInHolder<is_element>(map, holder);
     200             :   } while (!IsFound());
     201             : 
     202    24431679 :   holder_ = handle(holder, isolate_);
     203             : }
     204             : 
     205             : template <bool is_element>
     206     1478655 : void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
     207     1478655 :   interceptor_state_ = interceptor_state;
     208     1478655 :   property_details_ = PropertyDetails::Empty();
     209     1478655 :   number_ = static_cast<uint32_t>(DescriptorArray::kNotFound);
     210     1478655 :   Start<is_element>();
     211     1478680 : }
     212             : 
     213             : template void LookupIterator::RestartInternal<true>(InterceptorState);
     214             : template void LookupIterator::RestartInternal<false>(InterceptorState);
     215             : 
     216             : // static
     217      369733 : 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      400410 :   if (index != kMaxUInt32 && receiver->IsString() &&
     222        3387 :       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        1301 :     Handle<JSFunction> constructor = isolate->string_function();
     226        1301 :     Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
     227        2602 :     Handle<JSValue>::cast(result)->set_value(*receiver);
     228        1301 :     return result;
     229             :   }
     230             :   auto root =
     231      736866 :       handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
     232      736868 :   if (root->IsNull(isolate)) {
     233           0 :     isolate->PushStackTraceAndDie(reinterpret_cast<void*>(receiver->ptr()));
     234             :   }
     235      368434 :   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     6003821 : bool LookupIterator::HasAccess() const {
     245             :   DCHECK_EQ(ACCESS_CHECK, state_);
     246             :   return isolate_->MayAccess(handle(isolate_->context(), isolate_),
     247    12007642 :                              GetHolder<JSObject>());
     248             : }
     249             : 
     250             : template <bool is_element>
     251    12010781 : void LookupIterator::ReloadPropertyInformation() {
     252    12010781 :   state_ = BEFORE_PROPERTY;
     253    12010781 :   interceptor_state_ = InterceptorState::kUninitialized;
     254    12010780 :   state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
     255             :   DCHECK(IsFound() || !holder_->HasFastProperties());
     256    12010782 : }
     257             : 
     258             : namespace {
     259             : 
     260        3252 : 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        3252 :   if (!holder->IsJSFunction()) return false;
     270             : 
     271             :   return std::any_of(
     272             :       std::begin(context_slots), std::end(context_slots),
     273        1348 :       [=](uint32_t slot) { return isolate->IsInAnyContext(holder, slot); });
     274             : }
     275             : 
     276             : }  // namespace
     277             : 
     278     4319574 : void LookupIterator::InternalUpdateProtector() {
     279     4319574 :   if (isolate_->bootstrapper()->IsActive()) return;
     280             : 
     281      134735 :   ReadOnlyRoots roots(heap());
     282      134735 :   if (*name_ == roots.constructor_string()) {
     283      251371 :     if (!isolate_->IsArraySpeciesLookupChainIntact() &&
     284       16365 :         !isolate_->IsPromiseSpeciesLookupChainIntact() &&
     285      130173 :         !isolate_->IsRegExpSpeciesLookupChainIntact() &&
     286        5068 :         !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
     287             :       return;
     288             :     }
     289             :     // Setting the constructor property could change an instance's @@species
     290      229938 :     if (holder_->IsJSArray()) {
     291         282 :       if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
     292             :       isolate_->CountUsage(
     293          95 :           v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
     294          95 :       isolate_->InvalidateArraySpeciesProtector();
     295          95 :       return;
     296      229374 :     } else if (holder_->IsJSPromise()) {
     297           5 :       if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
     298           5 :       isolate_->InvalidatePromiseSpeciesProtector();
     299           5 :       return;
     300      229364 :     } else if (holder_->IsJSRegExp()) {
     301           0 :       if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
     302           0 :       isolate_->InvalidateRegExpSpeciesProtector();
     303           0 :       return;
     304      229364 :     } else if (holder_->IsJSTypedArray()) {
     305          55 :       if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
     306          55 :       isolate_->InvalidateTypedArraySpeciesProtector();
     307          55 :       return;
     308             :     }
     309      114627 :     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       18600 :       if (isolate_->IsInAnyContext(*holder_,
     317       18600 :                                    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       18600 :       } else if (isolate_->IsInAnyContext(*holder_,
     323       18600 :                                           Context::PROMISE_PROTOTYPE_INDEX)) {
     324          81 :         if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
     325          25 :         isolate_->InvalidatePromiseSpeciesProtector();
     326       18438 :       } else if (isolate_->IsInAnyContext(*holder_,
     327       18438 :                                           Context::REGEXP_PROTOTYPE_INDEX)) {
     328          55 :         if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
     329          15 :         isolate_->InvalidateRegExpSpeciesProtector();
     330        9164 :       } else if (isolate_->IsInAnyContext(
     331             :                      holder_->map()->prototype(),
     332        9164 :                      Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
     333         623 :         if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
     334         135 :         isolate_->InvalidateTypedArraySpeciesProtector();
     335             :       }
     336             :     }
     337       14698 :   } else if (*name_ == roots.next_string()) {
     338        7582 :     if (isolate_->IsInAnyContext(
     339        7582 :             *holder_, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)) {
     340             :       // Setting the next property of %ArrayIteratorPrototype% also needs to
     341             :       // invalidate the array iterator protector.
     342         505 :       if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
     343          25 :       isolate_->InvalidateArrayIteratorProtector();
     344        6572 :     } else if (isolate_->IsInAnyContext(
     345        6572 :                    *holder_, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) {
     346          30 :       if (!isolate_->IsMapIteratorLookupChainIntact()) return;
     347          25 :       isolate_->InvalidateMapIteratorProtector();
     348        6512 :     } else if (isolate_->IsInAnyContext(
     349        6512 :                    *holder_, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX)) {
     350          30 :       if (!isolate_->IsSetIteratorLookupChainIntact()) return;
     351          25 :       isolate_->InvalidateSetIteratorProtector();
     352        3226 :     } else if (isolate_->IsInAnyContext(
     353             :                    *receiver_,
     354        3226 :                    Context::INITIAL_STRING_ITERATOR_PROTOTYPE_INDEX)) {
     355             :       // Setting the next property of %StringIteratorPrototype% invalidates the
     356             :       // string iterator protector.
     357           5 :       if (!isolate_->IsStringIteratorLookupChainIntact()) return;
     358           5 :       isolate_->InvalidateStringIteratorProtector();
     359             :     }
     360       10907 :   } else if (*name_ == roots.species_symbol()) {
     361        6841 :     if (!isolate_->IsArraySpeciesLookupChainIntact() &&
     362         121 :         !isolate_->IsPromiseSpeciesLookupChainIntact() &&
     363        3360 :         !isolate_->IsRegExpSpeciesLookupChainIntact() &&
     364           0 :         !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
     365             :       return;
     366             :     }
     367             :     // Setting the Symbol.species property of any Array, Promise or TypedArray
     368             :     // constructor invalidates the @@species protector
     369        3360 :     if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
     370          45 :       if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
     371             :       isolate_->CountUsage(
     372          25 :           v8::Isolate::UseCounterFeature::kArraySpeciesModified);
     373          25 :       isolate_->InvalidateArraySpeciesProtector();
     374        6630 :     } else if (isolate_->IsInAnyContext(*holder_,
     375        6630 :                                         Context::PROMISE_FUNCTION_INDEX)) {
     376          45 :       if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
     377          25 :       isolate_->InvalidatePromiseSpeciesProtector();
     378        6540 :     } else if (isolate_->IsInAnyContext(*holder_,
     379        6540 :                                         Context::REGEXP_FUNCTION_INDEX)) {
     380          18 :       if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
     381          10 :       isolate_->InvalidateRegExpSpeciesProtector();
     382        3252 :     } else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
     383         110 :       if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
     384          55 :       isolate_->InvalidateTypedArraySpeciesProtector();
     385             :     }
     386        7547 :   } else if (*name_ == roots.is_concat_spreadable_symbol()) {
     387         864 :     if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
     388          65 :     isolate_->InvalidateIsConcatSpreadableProtector();
     389        6683 :   } else if (*name_ == roots.iterator_symbol()) {
     390        6496 :     if (holder_->IsJSArray()) {
     391         783 :       if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
     392          80 :       isolate_->InvalidateArrayIteratorProtector();
     393        4930 :     } else if (isolate_->IsInAnyContext(
     394        4930 :                    *holder_, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX)) {
     395          50 :       if (isolate_->IsMapIteratorLookupChainIntact()) {
     396          30 :         isolate_->InvalidateMapIteratorProtector();
     397             :       }
     398          50 :       if (isolate_->IsSetIteratorLookupChainIntact()) {
     399          30 :         isolate_->InvalidateSetIteratorProtector();
     400             :       }
     401        4830 :     } else if (isolate_->IsInAnyContext(*holder_,
     402        4830 :                                         Context::INITIAL_SET_PROTOTYPE_INDEX)) {
     403          15 :       if (!isolate_->IsSetIteratorLookupChainIntact()) return;
     404          10 :       isolate_->InvalidateSetIteratorProtector();
     405        2400 :     } else if (isolate_->IsInAnyContext(
     406        2400 :                    *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          24 :       if (!isolate_->IsStringIteratorLookupChainIntact()) return;
     412          20 :       isolate_->InvalidateStringIteratorProtector();
     413             :     }
     414        3435 :   } else if (*name_ == roots.resolve_string()) {
     415        1747 :     if (!isolate_->IsPromiseResolveLookupChainIntact()) return;
     416             :     // Setting the "resolve" property on any %Promise% intrinsic object
     417             :     // invalidates the Promise.resolve protector.
     418        1747 :     if (isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX)) {
     419           0 :       isolate_->InvalidatePromiseResolveProtector();
     420             :     }
     421        1688 :   } else if (*name_ == roots.then_string()) {
     422        1688 :     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        3386 :     if (holder_->IsJSPromise() ||
     431             :         isolate_->IsInAnyContext(*holder_,
     432        4463 :                                  Context::INITIAL_OBJECT_PROTOTYPE_INDEX) ||
     433        2209 :         isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) {
     434         105 :       isolate_->InvalidatePromiseThenProtector();
     435             :     }
     436             :   }
     437             : }
     438             : 
     439    33927705 : 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    20006800 :   if (holder->IsJSProxy()) return;
     448             : 
     449     6672517 :   Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
     450             : 
     451     6672516 :   if (IsElement()) {
     452      908265 :     ElementsKind kind = holder_obj->GetElementsKind();
     453      908265 :     ElementsKind to = value->OptimalElementsKind();
     454      908266 :     if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
     455             :     to = GetMoreGeneralElementsKind(kind, to);
     456             : 
     457      908266 :     if (kind != to) {
     458       18624 :       JSObject::TransitionElementsKind(holder_obj, to);
     459             :     }
     460             : 
     461             :     // Copy the backing store if it is copy-on-write.
     462      908264 :     if (IsSmiOrObjectElementsKind(to)) {
     463      176386 :       JSObject::EnsureWritableFastElements(holder_obj);
     464             :     }
     465             :     return;
     466             :   }
     467             : 
     468    11528500 :   if (holder_obj->IsJSGlobalObject()) {
     469             :     Handle<GlobalDictionary> dictionary(
     470     8997906 :         JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
     471             :     Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()),
     472     8997906 :                               isolate());
     473     4498953 :     property_details_ = cell->property_details();
     474             :     PropertyCell::PrepareForValue(isolate(), dictionary, dictionary_entry(),
     475     4498953 :                                   value, property_details_);
     476             :     return;
     477             :   }
     478     1265296 :   if (!holder_obj->HasFastProperties()) return;
     479             : 
     480             :   PropertyConstness new_constness = PropertyConstness::kConst;
     481             :   if (FLAG_track_constant_fields) {
     482             :     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             :       if (!IsConstFieldValueEqualTo(*value))
     487             :         new_constness = PropertyConstness::kMutable;
     488             :     }
     489             :   } else {
     490             :     new_constness = PropertyConstness::kMutable;
     491             :   }
     492             : 
     493     1202365 :   Handle<Map> old_map(holder_obj->map(), isolate_);
     494             :   Handle<Map> new_map = Map::PrepareForDataProperty(
     495     1202370 :       isolate(), old_map, descriptor_number(), new_constness, value);
     496             : 
     497     1202368 :   if (old_map.is_identical_to(new_map)) {
     498             :     // Update the property details if the representation was None.
     499     2381887 :     if (constness() != new_constness || representation().IsNone()) {
     500             :       property_details_ =
     501      182105 :           new_map->instance_descriptors()->GetDetails(descriptor_number());
     502             :     }
     503             :     return;
     504             :   }
     505             : 
     506       10830 :   JSObject::MigrateToMap(holder_obj, new_map);
     507       10830 :   ReloadPropertyInformation<false>();
     508             : }
     509             : 
     510             : 
     511       37333 : void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
     512      147937 :                                              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       74666 :   if (holder->IsJSProxy()) {
     520             :     DCHECK(name()->IsPrivate());
     521       37333 :     return;
     522             :   }
     523             : 
     524       37333 :   Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
     525       37333 :   if (IsElement()) {
     526             :     DCHECK(!holder_obj->HasFixedTypedArrayElements());
     527             :     DCHECK(attributes != NONE || !holder_obj->HasFastElements());
     528       38728 :     Handle<FixedArrayBase> elements(holder_obj->elements(), isolate());
     529       38728 :     holder_obj->GetElementsAccessor()->Reconfigure(holder_obj, elements,
     530       19364 :                                                    number_, value, attributes);
     531       19364 :     ReloadPropertyInformation<true>();
     532       17969 :   } else if (holder_obj->HasFastProperties()) {
     533       16395 :     Handle<Map> old_map(holder_obj->map(), isolate_);
     534             :     Handle<Map> new_map = Map::ReconfigureExistingProperty(
     535       16395 :         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       16395 :                                     PropertyConstness::kMutable, value);
     541       16395 :     JSObject::MigrateToMap(holder_obj, new_map);
     542       16395 :     ReloadPropertyInformation<false>();
     543             :   }
     544             : 
     545       55302 :   if (!IsElement() && !holder_obj->HasFastProperties()) {
     546             :     PropertyDetails details(kData, attributes, PropertyCellType::kMutable);
     547        2039 :     if (holder_obj->map()->is_prototype_map() &&
     548        2495 :         (property_details_.attributes() & READ_ONLY) == 0 &&
     549         456 :         (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        3148 :     if (holder_obj->IsJSGlobalObject()) {
     556             :       Handle<GlobalDictionary> dictionary(
     557         860 :           JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
     558             : 
     559             :       Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
     560         430 :           isolate(), dictionary, dictionary_entry(), value, details);
     561         430 :       cell->set_value(*value);
     562         430 :       property_details_ = cell->property_details();
     563             :     } else {
     564        2288 :       Handle<NameDictionary> dictionary(holder_obj->property_dictionary(),
     565        1144 :                                         isolate());
     566             :       PropertyDetails original_details =
     567        1144 :           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        2288 :       dictionary->SetEntry(isolate(), dictionary_entry(), *name(), *value,
     572        3432 :                            details);
     573        1144 :       property_details_ = details;
     574             :     }
     575        1574 :     state_ = DATA;
     576             :   }
     577             : 
     578       37333 :   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    34138864 : void LookupIterator::PrepareTransitionToDataProperty(
     590             :     Handle<JSReceiver> receiver, Handle<Object> value,
     591    41901865 :     PropertyAttributes attributes, StoreOrigin store_origin) {
     592             :   DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate());
     593             :   DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
     594    34138864 :   if (state_ == TRANSITION) return;
     595             : 
     596    67327514 :   if (!IsElement() && name()->IsPrivate()) {
     597     2541156 :     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    33663752 :   Handle<Map> map(receiver->map(), isolate_);
     607             : 
     608             :   // Dictionary maps can always have additional data properties.
     609    33663755 :   if (map->is_dictionary_map()) {
     610    11294971 :     state_ = TRANSITION;
     611    11294970 :     if (map->IsJSGlobalObjectMap()) {
     612             :       // Install a property cell.
     613     8238110 :       Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
     614             :       int entry;
     615             :       Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
     616     8238111 :           global, name(), PropertyCellType::kUninitialized, &entry);
     617             :       Handle<GlobalDictionary> dictionary(global->global_dictionary(),
     618    24714342 :                                           isolate_);
     619             :       DCHECK(cell->value()->IsTheHole(isolate_));
     620             :       DCHECK(!value->IsTheHole(isolate_));
     621     8238115 :       transition_ = cell;
     622             :       // Assign an enumeration index to the property and update
     623             :       // SetNextEnumerationIndex.
     624     8238114 :       int index = dictionary->NextEnumerationIndex();
     625     8238114 :       dictionary->SetNextEnumerationIndex(index + 1);
     626             :       property_details_ = PropertyDetails(
     627     8238113 :           kData, attributes, PropertyCellType::kUninitialized, index);
     628             :       PropertyCellType new_type =
     629     8238113 :           PropertyCell::UpdatedType(isolate(), cell, value, property_details_);
     630     8238117 :       property_details_ = property_details_.set_cell_type(new_type);
     631    16476235 :       cell->set_property_details(property_details_);
     632     8238118 :       number_ = entry;
     633     8238118 :       has_property_ = true;
     634             :     } else {
     635             :       // Don't set enumeration index (it will be set during value store).
     636             :       property_details_ =
     637     3056860 :           PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
     638     3056860 :       transition_ = map;
     639             :     }
     640             :     return;
     641             :   }
     642             : 
     643             :   Handle<Map> transition =
     644             :       Map::TransitionToDataProperty(isolate_, map, name_, value, attributes,
     645    22368812 :                                     kDefaultFieldConstness, store_origin);
     646    22368777 :   state_ = TRANSITION;
     647    22368777 :   transition_ = transition;
     648             : 
     649    22368790 :   if (transition->is_dictionary_map()) {
     650             :     // Don't set enumeration index (it will be set during value store).
     651             :     property_details_ =
     652       25615 :         PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
     653             :   } else {
     654    22343179 :     property_details_ = transition->GetLastDescriptorDetails();
     655    22343185 :     has_property_ = true;
     656             :   }
     657             : }
     658             : 
     659    33663194 : void LookupIterator::ApplyTransitionToDataProperty(
     660      563355 :     Handle<JSReceiver> receiver) {
     661             :   DCHECK_EQ(TRANSITION, state_);
     662             : 
     663             :   DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
     664    33663194 :   holder_ = receiver;
     665    67326428 :   if (receiver->IsJSGlobalObject()) {
     666     8237567 :     JSObject::InvalidatePrototypeChains(receiver->map());
     667     8237563 :     state_ = DATA;
     668    33663236 :     return;
     669             :   }
     670             :   Handle<Map> transition = transition_map();
     671    50851324 :   bool simple_transition = transition->GetBackPointer() == receiver->map();
     672             : 
     673    53175044 :   if (configuration_ == DEFAULT && !transition->is_dictionary_map() &&
     674    26361574 :       !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      563355 :         Map::GetOrCreatePrototypeChainValidityCell(transition, isolate());
     679      563361 :     transition->set_prototype_validity_cell(*validity_cell);
     680             :   }
     681             : 
     682    50851329 :   if (!receiver->IsJSProxy()) {
     683    25425620 :     JSObject::MigrateToMap(Handle<JSObject>::cast(receiver), transition);
     684             :   }
     685             : 
     686    25425658 :   if (simple_transition) {
     687    11461099 :     int number = transition->LastAdded();
     688    11461101 :     number_ = static_cast<uint32_t>(number);
     689    11461106 :     property_details_ = transition->GetLastDescriptorDetails();
     690    11461114 :     state_ = DATA;
     691    13964562 :   } else if (receiver->map()->is_dictionary_map()) {
     692             :     Handle<NameDictionary> dictionary(receiver->property_dictionary(),
     693     9247425 :                                       isolate_);
     694             :     int entry;
     695     3645037 :     if (receiver->map()->is_prototype_map() && receiver->IsJSObject()) {
     696      281281 :       JSObject::InvalidatePrototypeChains(receiver->map());
     697             :     }
     698             :     dictionary = NameDictionary::Add(isolate(), dictionary, name(),
     699             :                                      isolate_->factory()->uninitialized_value(),
     700     6164950 :                                      property_details_, &entry);
     701     6164950 :     receiver->SetProperties(*dictionary);
     702             :     // Reload details containing proper enumeration index value.
     703     6164950 :     property_details_ = dictionary->DetailsAt(entry);
     704     3082475 :     number_ = entry;
     705     3082475 :     has_property_ = true;
     706     3082475 :     state_ = DATA;
     707             : 
     708             :   } else {
     709    10882085 :     ReloadPropertyInformation<false>();
     710             :   }
     711             : }
     712             : 
     713             : 
     714      315372 : void LookupIterator::Delete() {
     715      157686 :   Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
     716      157686 :   if (IsElement()) {
     717      103411 :     Handle<JSObject> object = Handle<JSObject>::cast(holder);
     718      103411 :     ElementsAccessor* accessor = object->GetElementsAccessor();
     719      103411 :     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             :         isolate_, is_prototype_map
     725             :                       ? RuntimeCallCounterId::kPrototypeObject_DeleteProperty
     726       54275 :                       : RuntimeCallCounterId::kObject_DeleteProperty);
     727             : 
     728             :     PropertyNormalizationMode mode =
     729       54275 :         is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
     730             : 
     731       54275 :     if (holder->HasFastProperties()) {
     732             :       JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
     733       40555 :                                     "DeletingProperty");
     734       40555 :       ReloadPropertyInformation<false>();
     735             :     }
     736       54275 :     JSReceiver::DeleteNormalizedProperty(holder, number_);
     737      108550 :     if (holder->IsJSObject()) {
     738       54269 :       JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
     739             :     }
     740             :   }
     741      157686 :   state_ = NOT_FOUND;
     742      157686 : }
     743             : 
     744      768782 : void LookupIterator::TransitionToAccessorProperty(
     745             :     Handle<Object> getter, Handle<Object> setter,
     746     2809104 :     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      768782 :   Handle<JSObject> receiver = GetStoreTarget<JSObject>();
     752     1510004 :   if (!IsElement() && name()->IsPrivate()) {
     753           5 :     attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
     754             :   }
     755             : 
     756     1510003 :   if (!IsElement() && !receiver->map()->is_dictionary_map()) {
     757      727725 :     Handle<Map> old_map(receiver->map(), isolate_);
     758             : 
     759      727726 :     if (!holder_.is_identical_to(receiver)) {
     760           0 :       holder_ = receiver;
     761           0 :       state_ = NOT_FOUND;
     762      727726 :     } else if (state_ == INTERCEPTOR) {
     763          37 :       LookupInRegularHolder<false>(*old_map, *holder_);
     764             :     }
     765             :     int descriptor =
     766      727725 :         IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound;
     767             : 
     768             :     Handle<Map> new_map = Map::TransitionToAccessorProperty(
     769      727725 :         isolate_, old_map, name_, descriptor, getter, setter, attributes);
     770     1455454 :     bool simple_transition = new_map->GetBackPointer() == receiver->map();
     771      727727 :     JSObject::MigrateToMap(receiver, new_map);
     772             : 
     773      727727 :     if (simple_transition) {
     774       19568 :       int number = new_map->LastAdded();
     775       19568 :       number_ = static_cast<uint32_t>(number);
     776       19568 :       property_details_ = new_map->GetLastDescriptorDetails();
     777       19568 :       state_ = ACCESSOR;
     778       19568 :       return;
     779             :     }
     780             : 
     781      708159 :     ReloadPropertyInformation<false>();
     782      708159 :     if (!new_map->is_dictionary_map()) return;
     783             :   }
     784             : 
     785             :   Handle<AccessorPair> pair;
     786      294016 :   if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
     787       10899 :     pair = Handle<AccessorPair>::cast(GetAccessors());
     788             :     // If the component and attributes are identical, nothing has to be done.
     789       10899 :     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       10872 :       pair = AccessorPair::Copy(isolate(), pair);
     796       10872 :       pair->SetComponents(*getter, *setter);
     797             :     }
     798             :   } else {
     799      261021 :     pair = factory()->NewAccessorPair();
     800      261021 :     pair->SetComponents(*getter, *setter);
     801             :   }
     802             : 
     803      271920 :   TransitionToAccessorPair(pair, attributes);
     804             : 
     805             : #if VERIFY_HEAP
     806             :   if (FLAG_verify_heap) {
     807             :     receiver->JSObjectVerify(isolate());
     808             :   }
     809             : #endif
     810             : }
     811             : 
     812             : 
     813      333396 : void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
     814      333468 :                                               PropertyAttributes attributes) {
     815      333396 :   Handle<JSObject> receiver = GetStoreTarget<JSObject>();
     816      333396 :   holder_ = receiver;
     817             : 
     818             :   PropertyDetails details(kAccessor, attributes, PropertyCellType::kMutable);
     819             : 
     820      333396 :   if (IsElement()) {
     821             :     // TODO(verwaest): Move code into the element accessor.
     822       27574 :     isolate_->CountUsage(v8::Isolate::kIndexAccessor);
     823       27574 :     Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(receiver);
     824             : 
     825             :     dictionary = NumberDictionary::Set(isolate_, dictionary, index_, pair,
     826       27574 :                                        receiver, details);
     827       27574 :     receiver->RequireSlowElements(*dictionary);
     828             : 
     829       55148 :     if (receiver->HasSlowArgumentsElements()) {
     830         198 :       FixedArray parameter_map = FixedArray::cast(receiver->elements());
     831          99 :       uint32_t length = parameter_map->length() - 2;
     832          99 :       if (number_ < length) {
     833         144 :         parameter_map->set(number_ + 2, ReadOnlyRoots(heap()).the_hole_value());
     834             :       }
     835         297 :       FixedArray::cast(receiver->elements())->set(1, *dictionary);
     836             :     } else {
     837       54950 :       receiver->set_elements(*dictionary);
     838             :     }
     839             : 
     840       27574 :     ReloadPropertyInformation<true>();
     841             :   } else {
     842             :     PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES;
     843      305822 :     if (receiver->map()->is_prototype_map()) {
     844       13207 :       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      305822 :                                   "TransitionToAccessorPair");
     851             : 
     852      305822 :     JSObject::SetNormalizedProperty(receiver, name_, pair, details);
     853      305822 :     JSObject::ReoptimizeIfPrototype(receiver);
     854             : 
     855      305822 :     ReloadPropertyInformation<false>();
     856             :   }
     857      333396 : }
     858             : 
     859         339 : bool LookupIterator::HolderIsReceiver() const {
     860             :   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
     861             :   // Optimization that only works if configuration_ is not mutable.
     862         339 :   if (!check_prototype_chain()) return true;
     863             :   return *receiver_ == *holder_;
     864             : }
     865             : 
     866     4994932 : bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
     867             :   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
     868             :   // Optimization that only works if configuration_ is not mutable.
     869     4987426 :   if (!check_prototype_chain()) return true;
     870             :   DisallowHeapAllocation no_gc;
     871     4972982 :   if (*receiver_ == *holder_) return true;
     872      402976 :   if (!receiver_->IsJSReceiver()) return false;
     873             :   JSReceiver current = JSReceiver::cast(*receiver_);
     874      199473 :   JSReceiver object = *holder_;
     875      199473 :   if (!current->map()->has_hidden_prototype()) return false;
     876             :   // JSProxy do not occur as hidden prototypes.
     877        7506 :   if (object->IsJSProxy()) return false;
     878             :   PrototypeIterator iter(isolate(), current, kStartAtPrototype,
     879             :                          PrototypeIterator::END_AT_NON_HIDDEN);
     880        8008 :   while (!iter.IsAtEnd()) {
     881       15012 :     if (iter.GetCurrent<JSReceiver>() == object) return true;
     882         502 :     iter.Advance();
     883             :   }
     884             :   return false;
     885             : }
     886             : 
     887             : 
     888    29544790 : Handle<Object> LookupIterator::FetchValue() const {
     889             :   Object result;
     890    29544790 :   if (IsElement()) {
     891             :     Handle<JSObject> holder = GetHolder<JSObject>();
     892     5965633 :     ElementsAccessor* accessor = holder->GetElementsAccessor();
     893     5965633 :     return accessor->Get(holder, number_);
     894    47158334 :   } else if (holder_->IsJSGlobalObject()) {
     895             :     Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
     896    21201306 :     result = holder->global_dictionary()->ValueAt(number_);
     897    16512078 :   } else if (!holder_->HasFastProperties()) {
     898     1814434 :     result = holder_->property_dictionary()->ValueAt(number_);
     899    15604859 :   } else if (property_details_.location() == kField) {
     900             :     DCHECK_EQ(kData, property_details_.kind());
     901             :     Handle<JSObject> holder = GetHolder<JSObject>();
     902    10917282 :     FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
     903             :     return JSObject::FastPropertyAt(holder, property_details_.representation(),
     904     5458643 :                                     field_index);
     905             :   } else {
     906    20292432 :     result = holder_->map()->instance_descriptors()->GetStrongValue(number_);
     907             :   }
     908    18120533 :   return handle(result, isolate_);
     909             : }
     910             : 
     911           0 : 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           0 :   FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
     918           0 :   if (property_details_.representation().IsDouble()) {
     919           0 :     if (!value->IsNumber()) return false;
     920             :     uint64_t bits;
     921           0 :     if (holder->IsUnboxedDoubleField(field_index)) {
     922             :       bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
     923             :     } else {
     924           0 :       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           0 :     if (bits == kHoleNanInt64) {
     934             :       // Uninitialized double field.
     935             :       return true;
     936             :     }
     937           0 :     return bit_cast<double>(bits) == value->Number();
     938             :   } else {
     939           0 :     Object current_value = holder->RawFastPropertyAt(field_index);
     940           0 :     return current_value->IsUninitialized(isolate()) || current_value == value;
     941             :   }
     942             : }
     943             : 
     944      165689 : 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      165689 :   return descriptor_number();
     950             : }
     951             : 
     952      284238 : 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      284238 :   return descriptor_number();
     958             : }
     959             : 
     960             : 
     961      421271 : 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      421271 :   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      728841 : FieldIndex LookupIterator::GetFieldIndex() const {
     982             :   DCHECK(has_property_);
     983             :   DCHECK(holder_->HasFastProperties());
     984             :   DCHECK_EQ(kField, property_details_.location());
     985             :   DCHECK(!IsElement());
     986      728845 :   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    12315938 : Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
    1000             :   DCHECK(!IsElement());
    1001             :   Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
    1002    12315944 :   return handle(holder->global_dictionary()->CellAt(dictionary_entry()),
    1003    24631887 :                 isolate_);
    1004             : }
    1005             : 
    1006             : 
    1007     2466481 : Handle<Object> LookupIterator::GetAccessors() const {
    1008             :   DCHECK_EQ(ACCESSOR, state_);
    1009     3184738 :   return FetchValue();
    1010             : }
    1011             : 
    1012             : 
    1013    26360058 : Handle<Object> LookupIterator::GetDataValue() const {
    1014             :   DCHECK_EQ(DATA, state_);
    1015    26360058 :   Handle<Object> value = FetchValue();
    1016    26360060 :   return value;
    1017             : }
    1018             : 
    1019    38598164 : void LookupIterator::WriteDataValue(Handle<Object> value,
    1020    66498405 :                                     bool initializing_store) {
    1021             :   DCHECK_EQ(DATA, state_);
    1022             :   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
    1023    38598185 :   if (IsElement()) {
    1024      927627 :     Handle<JSObject> object = Handle<JSObject>::cast(holder);
    1025      927628 :     ElementsAccessor* accessor = object->GetElementsAccessor();
    1026     1855259 :     accessor->Set(object, number_, *value);
    1027    37670556 :   } else if (holder->HasFastProperties()) {
    1028    23396220 :     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             :       JSObject::cast(*holder)->WriteToField(descriptor_number(),
    1035    13625874 :                                             property_details_, *value);
    1036             :     } else {
    1037             :       DCHECK_EQ(kDescriptor, property_details_.location());
    1038             :       DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
    1039             :     }
    1040    28548690 :   } else if (holder->IsJSGlobalObject()) {
    1041             :     GlobalDictionary dictionary =
    1042    11133305 :         JSGlobalObject::cast(*holder)->global_dictionary();
    1043    11133306 :     dictionary->CellAt(dictionary_entry())->set_value(*value);
    1044             :   } else {
    1045             :     DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
    1046     3141039 :     NameDictionary dictionary = holder->property_dictionary();
    1047             :     dictionary->ValueAtPut(dictionary_entry(), *value);
    1048             :   }
    1049    38598197 : }
    1050             : 
    1051             : template <bool is_element>
    1052      914561 : bool LookupIterator::SkipInterceptor(JSObject holder) {
    1053      914561 :   auto info = GetInterceptor<is_element>(holder);
    1054     1210990 :   if (!is_element && name_->IsSymbol() && !info->can_intercept_symbols()) {
    1055             :     return true;
    1056             :   }
    1057      914549 :   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      914135 :   return interceptor_state_ == InterceptorState::kProcessNonMasking;
    1069             : }
    1070             : 
    1071   566903334 : JSReceiver LookupIterator::NextHolder(Map map) {
    1072             :   DisallowHeapAllocation no_gc;
    1073   665830678 :   if (map->prototype() == ReadOnlyRoots(heap()).null_value()) {
    1074    98927344 :     return JSReceiver();
    1075             :   }
    1076   233988014 :   if (!check_prototype_chain() && !map->has_hidden_prototype()) {
    1077    46504147 :     return JSReceiver();
    1078             :   }
    1079             :   return JSReceiver::cast(map->prototype());
    1080             : }
    1081             : 
    1082    84799314 : LookupIterator::State LookupIterator::NotFound(JSReceiver const holder) const {
    1083             :   DCHECK(!IsElement());
    1084    84982904 :   if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
    1085             : 
    1086       83800 :   Handle<String> name_string = Handle<String>::cast(name_);
    1087       83800 :   if (name_string->length() == 0) return NOT_FOUND;
    1088             : 
    1089       83800 :   return IsSpecialIndex(*name_string) ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
    1090             : }
    1091             : 
    1092             : namespace {
    1093             : 
    1094             : template <bool is_element>
    1095             : bool HasInterceptor(Map map) {
    1096             :   return is_element ? map->has_indexed_interceptor()
    1097             :                     : map->has_named_interceptor();
    1098             : }
    1099             : 
    1100             : }  // namespace
    1101             : 
    1102             : template <bool is_element>
    1103    50466112 : LookupIterator::State LookupIterator::LookupInSpecialHolder(
    1104             :     Map const map, JSReceiver const holder) {
    1105             :   STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
    1106    50466112 :   switch (state_) {
    1107             :     case NOT_FOUND:
    1108    43544296 :       if (map->IsJSProxyMap()) {
    1109      317445 :         if (is_element || !name_->IsPrivate()) return JSPROXY;
    1110             :       }
    1111    43216539 :       if (map->is_access_check_needed()) {
    1112     8288380 :         if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
    1113             :       }
    1114             :       V8_FALLTHROUGH;
    1115             :     case ACCESS_CHECK:
    1116    65791993 :       if (check_interceptor() && HasInterceptor<is_element>(map) &&
    1117      914561 :           !SkipInterceptor<is_element>(JSObject::cast(holder))) {
    1118      605225 :         if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
    1119             :       }
    1120             :       V8_FALLTHROUGH;
    1121             :     case INTERCEPTOR:
    1122    40609522 :       if (!is_element && map->IsJSGlobalObjectMap()) {
    1123             :         GlobalDictionary dict =
    1124    33742165 :             JSGlobalObject::cast(holder)->global_dictionary();
    1125    33742168 :         int number = dict->FindEntry(isolate(), name_);
    1126    67484301 :         if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
    1127    16492554 :         number_ = static_cast<uint32_t>(number);
    1128    16492554 :         PropertyCell cell = dict->CellAt(number_);
    1129    32985108 :         if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
    1130    16458791 :         property_details_ = cell->property_details();
    1131    16458790 :         has_property_ = true;
    1132    16458790 :         switch (property_details_.kind()) {
    1133             :           case v8::internal::kData:
    1134             :             return DATA;
    1135             :           case v8::internal::kAccessor:
    1136       40608 :             return ACCESSOR;
    1137             :         }
    1138             :       }
    1139     7187087 :       return LookupInRegularHolder<is_element>(map, holder);
    1140             :     case ACCESSOR:
    1141             :     case DATA:
    1142             :       return NOT_FOUND;
    1143             :     case INTEGER_INDEXED_EXOTIC:
    1144             :     case JSPROXY:
    1145             :     case TRANSITION:
    1146           0 :       UNREACHABLE();
    1147             :   }
    1148           0 :   UNREACHABLE();
    1149             : }
    1150             : 
    1151             : template <bool is_element>
    1152   354751475 : LookupIterator::State LookupIterator::LookupInRegularHolder(
    1153             :     Map const map, JSReceiver const holder) {
    1154             :   DisallowHeapAllocation no_gc;
    1155   354751475 :   if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
    1156             :     return NOT_FOUND;
    1157             :   }
    1158             : 
    1159             :   if (is_element) {
    1160   238708135 :     JSObject js_object = JSObject::cast(holder);
    1161   238708135 :     ElementsAccessor* accessor = js_object->GetElementsAccessor();
    1162   238708136 :     FixedArrayBase backing_store = js_object->elements();
    1163   238708135 :     number_ =
    1164   238708136 :         accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
    1165   238708135 :     if (number_ == kMaxUInt32) {
    1166   231023676 :       return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
    1167             :     }
    1168     7684461 :     property_details_ = accessor->GetDetails(js_object, number_);
    1169   116043242 :   } else if (!map->is_dictionary_map()) {
    1170   110783491 :     DescriptorArray descriptors = map->instance_descriptors();
    1171   110783509 :     int number = descriptors->SearchWithCache(isolate_, *name_, map);
    1172   110783590 :     if (number == DescriptorArray::kNotFound) return NotFound(holder);
    1173    29979692 :     number_ = static_cast<uint32_t>(number);
    1174    29979692 :     property_details_ = descriptors->GetDetails(number_);
    1175             :   } else {
    1176             :     DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
    1177     5259750 :     NameDictionary dict = holder->property_dictionary();
    1178     5259750 :     int number = dict->FindEntry(isolate(), name_);
    1179     5259750 :     if (number == NameDictionary::kNotFound) return NotFound(holder);
    1180     1264312 :     number_ = static_cast<uint32_t>(number);
    1181     1264312 :     property_details_ = dict->DetailsAt(number_);
    1182             :   }
    1183    38928465 :   has_property_ = true;
    1184    38928465 :   switch (property_details_.kind()) {
    1185             :     case v8::internal::kData:
    1186             :       return DATA;
    1187             :     case v8::internal::kAccessor:
    1188     2953771 :       return ACCESSOR;
    1189             :   }
    1190             : 
    1191           0 :   UNREACHABLE();
    1192             : }
    1193             : 
    1194        1398 : Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
    1195        1102 :     const {
    1196             :   DCHECK_EQ(ACCESS_CHECK, state_);
    1197             :   DisallowHeapAllocation no_gc;
    1198             :   AccessCheckInfo access_check_info =
    1199        1398 :       AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
    1200        1398 :   if (!access_check_info.is_null()) {
    1201             :     Object interceptor = IsElement() ? access_check_info->indexed_interceptor()
    1202        1102 :                                      : access_check_info->named_interceptor();
    1203        1102 :     if (interceptor != Object()) {
    1204         290 :       return handle(InterceptorInfo::cast(interceptor), isolate_);
    1205             :     }
    1206             :   }
    1207        1253 :   return Handle<InterceptorInfo>();
    1208             : }
    1209             : 
    1210     3395598 : bool LookupIterator::TryLookupCachedProperty() {
    1211      348484 :   return state() == LookupIterator::ACCESSOR &&
    1212     4091908 :          GetAccessors()->IsAccessorPair() && LookupCachedProperty();
    1213             : }
    1214             : 
    1215     1043559 : bool LookupIterator::LookupCachedProperty() {
    1216             :   DCHECK_EQ(state(), LookupIterator::ACCESSOR);
    1217             :   DCHECK(GetAccessors()->IsAccessorPair());
    1218             : 
    1219      347826 :   AccessorPair accessor_pair = AccessorPair::cast(*GetAccessors());
    1220      347826 :   Handle<Object> getter(accessor_pair->getter(), isolate());
    1221             :   MaybeHandle<Name> maybe_name =
    1222      347826 :       FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
    1223      347826 :   if (maybe_name.is_null()) return false;
    1224             : 
    1225             :   // We have found a cached property! Modify the iterator accordingly.
    1226          81 :   name_ = maybe_name.ToHandleChecked();
    1227          81 :   Restart();
    1228          81 :   CHECK_EQ(state(), LookupIterator::DATA);
    1229             :   return true;
    1230             : }
    1231             : 
    1232             : }  // namespace internal
    1233      183867 : }  // namespace v8

Generated by: LCOV version 1.10