LCOV - code coverage report
Current view: top level - src - lookup.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 355 381 93.2 %
Date: 2017-04-26 Functions: 40 44 90.9 %

          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/deoptimizer.h"
       9             : #include "src/elements.h"
      10             : #include "src/field-type.h"
      11             : #include "src/isolate-inl.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16             : // static
      17   120305360 : LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
      18             :                                                  Handle<Object> receiver,
      19             :                                                  Handle<Object> key,
      20             :                                                  bool* success,
      21             :                                                  Configuration configuration) {
      22   120305360 :   uint32_t index = 0;
      23   120305361 :   if (key->ToArrayIndex(&index)) {
      24    37363910 :     *success = true;
      25    37363910 :     return LookupIterator(isolate, receiver, index, configuration);
      26             :   }
      27             : 
      28             :   Handle<Name> name;
      29   165882901 :   *success = Object::ToName(isolate, key).ToHandle(&name);
      30    82941450 :   if (!*success) {
      31             :     DCHECK(isolate->has_pending_exception());
      32             :     // Return an unusable dummy.
      33          49 :     return LookupIterator(receiver, isolate->factory()->empty_string());
      34             :   }
      35             : 
      36    82941401 :   if (name->AsArrayIndex(&index)) {
      37      397269 :     LookupIterator it(isolate, receiver, index, configuration);
      38             :     // Here we try to avoid having to rebuild the string later
      39             :     // by storing it on the indexed LookupIterator.
      40      397269 :     it.name_ = name;
      41      397269 :     return it;
      42             :   }
      43             : 
      44    82544129 :   return LookupIterator(receiver, name, configuration);
      45             : }
      46             : 
      47             : template <bool is_element>
      48   486874270 : void LookupIterator::Start() {
      49             :   DisallowHeapAllocation no_gc;
      50             : 
      51   486874270 :   has_property_ = false;
      52   486874270 :   state_ = NOT_FOUND;
      53   486874270 :   holder_ = initial_holder_;
      54             : 
      55             :   JSReceiver* holder = *holder_;
      56             :   Map* map = holder->map();
      57             : 
      58   486874270 :   state_ = LookupInHolder<is_element>(map, holder);
      59   973748466 :   if (IsFound()) return;
      60             : 
      61   262551337 :   NextInternal<is_element>(map, holder);
      62             : }
      63             : 
      64             : template void LookupIterator::Start<true>();
      65             : template void LookupIterator::Start<false>();
      66             : 
      67    28568048 : void LookupIterator::Next() {
      68             :   DCHECK_NE(JSPROXY, state_);
      69             :   DCHECK_NE(TRANSITION, state_);
      70             :   DisallowHeapAllocation no_gc;
      71     9741730 :   has_property_ = false;
      72             : 
      73             :   JSReceiver* holder = *holder_;
      74             :   Map* map = holder->map();
      75             : 
      76     9741730 :   if (map->IsSpecialReceiverMap()) {
      77             :     state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
      78     9741697 :                          : LookupInSpecialHolder<false>(map, holder);
      79    19483427 :     if (IsFound()) return;
      80             :   }
      81             : 
      82       83650 :   IsElement() ? NextInternal<true>(map, holder)
      83    18085592 :               : NextInternal<false>(map, holder);
      84             : }
      85             : 
      86             : template <bool is_element>
      87   271635977 : void LookupIterator::NextInternal(Map* map, JSReceiver* holder) {
      88   312710701 :   do {
      89             :     JSReceiver* maybe_holder = NextHolder(map);
      90   553588200 :     if (maybe_holder == nullptr) {
      91   240877499 :       if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
      92         175 :         RestartLookupForNonMaskingInterceptors<is_element>();
      93         175 :         return;
      94             :       }
      95   240877324 :       state_ = NOT_FOUND;
      96   388407359 :       if (holder != *holder_) holder_ = handle(holder, isolate_);
      97             :       return;
      98             :     }
      99             :     holder = maybe_holder;
     100             :     map = holder->map();
     101   312710701 :     state_ = LookupInHolder<is_element>(map, holder);
     102             :   } while (!IsFound());
     103             : 
     104    61516956 :   holder_ = handle(holder, isolate_);
     105             : }
     106             : 
     107             : template <bool is_element>
     108     5420846 : void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
     109     5420846 :   interceptor_state_ = interceptor_state;
     110     5420846 :   property_details_ = PropertyDetails::Empty();
     111     5420846 :   number_ = static_cast<uint32_t>(DescriptorArray::kNotFound);
     112     5420846 :   Start<is_element>();
     113     5420846 : }
     114             : 
     115             : template void LookupIterator::RestartInternal<true>(InterceptorState);
     116             : template void LookupIterator::RestartInternal<false>(InterceptorState);
     117             : 
     118             : // static
     119      252579 : Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
     120             :     Isolate* isolate, Handle<Object> receiver, uint32_t index) {
     121             :   // Strings are the only objects with properties (only elements) directly on
     122             :   // the wrapper. Hence we can skip generating the wrapper for all other cases.
     123      282435 :   if (index != kMaxUInt32 && receiver->IsString() &&
     124        6576 :       index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
     125             :     // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
     126             :     // context, ensuring that we don't leak it into JS?
     127        1705 :     Handle<JSFunction> constructor = isolate->string_function();
     128        1705 :     Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
     129        1705 :     Handle<JSValue>::cast(result)->set_value(*receiver);
     130        1705 :     return result;
     131             :   }
     132             :   auto root =
     133      250874 :       handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
     134      250874 :   if (root->IsNull(isolate)) {
     135             :     unsigned int magic = 0xbbbbbbbb;
     136           0 :     isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
     137             :   }
     138             :   return Handle<JSReceiver>::cast(root);
     139             : }
     140             : 
     141             : 
     142           0 : Handle<Map> LookupIterator::GetReceiverMap() const {
     143           0 :   if (receiver_->IsNumber()) return factory()->heap_number_map();
     144           0 :   return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
     145             : }
     146             : 
     147     8675572 : bool LookupIterator::HasAccess() const {
     148             :   DCHECK_EQ(ACCESS_CHECK, state_);
     149             :   return isolate_->MayAccess(handle(isolate_->context()),
     150    17351144 :                              GetHolder<JSObject>());
     151             : }
     152             : 
     153             : template <bool is_element>
     154     7255357 : void LookupIterator::ReloadPropertyInformation() {
     155     7255357 :   state_ = BEFORE_PROPERTY;
     156     7255357 :   interceptor_state_ = InterceptorState::kUninitialized;
     157     7255357 :   state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
     158             :   DCHECK(IsFound() || !holder_->HasFastProperties());
     159     7255359 : }
     160             : 
     161     4933310 : void LookupIterator::InternalUpdateProtector() {
     162     4933310 :   if (isolate_->bootstrapper()->IsActive()) return;
     163             : 
     164      246207 :   if (*name_ == heap()->constructor_string()) {
     165      226176 :     if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
     166             :     // Setting the constructor property could change an instance's @@species
     167      210463 :     if (holder_->IsJSArray()) {
     168             :       isolate_->CountUsage(
     169          50 :           v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
     170          50 :       isolate_->InvalidateArraySpeciesProtector();
     171      210413 :     } else if (holder_->map()->is_prototype_map()) {
     172             :       DisallowHeapAllocation no_gc;
     173             :       // Setting the constructor of Array.prototype of any realm also needs
     174             :       // to invalidate the species protector
     175       63747 :       if (isolate_->IsInAnyContext(*holder_,
     176       63747 :                                    Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
     177             :         isolate_->CountUsage(v8::Isolate::UseCounterFeature::
     178           0 :                                  kArrayPrototypeConstructorModified);
     179           0 :         isolate_->InvalidateArraySpeciesProtector();
     180             :       }
     181             :     }
     182       20031 :   } else if (*name_ == heap()->species_symbol()) {
     183        4318 :     if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
     184             :     // Setting the Symbol.species property of any Array constructor invalidates
     185             :     // the species protector
     186        4234 :     if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
     187             :       isolate_->CountUsage(
     188          25 :           v8::Isolate::UseCounterFeature::kArraySpeciesModified);
     189          25 :       isolate_->InvalidateArraySpeciesProtector();
     190             :     }
     191       15713 :   } else if (*name_ == heap()->is_concat_spreadable_symbol()) {
     192        1280 :     if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
     193          69 :     isolate_->InvalidateIsConcatSpreadableProtector();
     194       14433 :   } else if (*name_ == heap()->iterator_symbol()) {
     195       14433 :     if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
     196       12417 :     if (holder_->IsJSArray()) {
     197          61 :       isolate_->InvalidateArrayIteratorProtector();
     198             :     }
     199             :   }
     200             : }
     201             : 
     202    31585664 : void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
     203             :   DCHECK(state_ == DATA || state_ == ACCESSOR);
     204             :   DCHECK(HolderIsReceiverOrHiddenPrototype());
     205             : 
     206             :   Handle<JSObject> holder = GetHolder<JSObject>();
     207             : 
     208    15910094 :   if (IsElement()) {
     209             :     ElementsKind kind = holder->GetElementsKind();
     210     1343849 :     ElementsKind to = value->OptimalElementsKind();
     211     1343849 :     if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
     212             :     to = GetMoreGeneralElementsKind(kind, to);
     213             : 
     214     1343849 :     if (kind != to) {
     215       27640 :       JSObject::TransitionElementsKind(holder, to);
     216             :     }
     217             : 
     218             :     // Copy the backing store if it is copy-on-write.
     219     1343849 :     if (IsFastSmiOrObjectElementsKind(to)) {
     220      132666 :       JSObject::EnsureWritableFastElements(holder);
     221             :     }
     222    15462536 :     return;
     223             :   }
     224             : 
     225    14566245 :   if (holder->IsJSGlobalObject()) {
     226             :     Handle<GlobalDictionary> dictionary(holder->global_dictionary());
     227             :     Handle<PropertyCell> cell(
     228     3063099 :         PropertyCell::cast(dictionary->ValueAt(dictionary_entry())));
     229             :     DCHECK(!cell->IsTheHole(isolate_));
     230     3063099 :     property_details_ = cell->property_details();
     231             :     PropertyCell::PrepareForValue(dictionary, dictionary_entry(), value,
     232     3063099 :                                   property_details_);
     233             :     return;
     234             :   }
     235    11503146 :   if (!holder->HasFastProperties()) return;
     236             : 
     237             :   PropertyConstness new_constness = kConst;
     238             :   if (FLAG_track_constant_fields) {
     239             :     if (constness() == kConst) {
     240             :       DCHECK_EQ(kData, property_details_.kind());
     241             :       // Check that current value matches new value otherwise we should make
     242             :       // the property mutable.
     243             :       if (!IsConstFieldValueEqualTo(*value)) new_constness = kMutable;
     244             :     }
     245             :   } else {
     246             :     new_constness = kMutable;
     247             :   }
     248             : 
     249     9145109 :   Handle<Map> old_map(holder->map(), isolate_);
     250             :   Handle<Map> new_map = Map::PrepareForDataProperty(
     251     9145109 :       old_map, descriptor_number(), new_constness, value);
     252             : 
     253     9145110 :   if (old_map.is_identical_to(new_map)) {
     254             :     // Update the property details if the representation was None.
     255    17393176 :     if (constness() != new_constness || representation().IsNone()) {
     256             :       property_details_ =
     257      404263 :           new_map->instance_descriptors()->GetDetails(descriptor_number());
     258             :     }
     259             :     return;
     260             :   }
     261             : 
     262      447559 :   JSObject::MigrateToMap(holder, new_map);
     263      447558 :   ReloadPropertyInformation<false>();
     264             : }
     265             : 
     266             : 
     267     1550241 : void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
     268     6136086 :                                              PropertyAttributes attributes) {
     269             :   DCHECK(state_ == DATA || state_ == ACCESSOR);
     270             :   DCHECK(HolderIsReceiverOrHiddenPrototype());
     271             :   Handle<JSObject> holder = GetHolder<JSObject>();
     272     1550241 :   if (IsElement()) {
     273             :     DCHECK(!holder->HasFixedTypedArrayElements());
     274             :     DCHECK(attributes != NONE || !holder->HasFastElements());
     275             :     Handle<FixedArrayBase> elements(holder->elements());
     276       32183 :     holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
     277       32183 :                                                attributes);
     278       32183 :     ReloadPropertyInformation<true>();
     279     1518058 :   } else if (holder->HasFastProperties()) {
     280     1515893 :     Handle<Map> old_map(holder->map(), isolate_);
     281             :     Handle<Map> new_map = Map::ReconfigureExistingProperty(
     282     1515892 :         old_map, descriptor_number(), i::kData, attributes);
     283             :     // Force mutable to avoid changing constant value by reconfiguring
     284             :     // kData -> kAccessor -> kData.
     285             :     new_map = Map::PrepareForDataProperty(new_map, descriptor_number(),
     286     1515894 :                                           kMutable, value);
     287     1515895 :     JSObject::MigrateToMap(holder, new_map);
     288     1515894 :     ReloadPropertyInformation<false>();
     289             :   }
     290             : 
     291     3068306 :   if (!IsElement() && !holder->HasFastProperties()) {
     292             :     PropertyDetails details(kData, attributes, 0, PropertyCellType::kMutable);
     293        2168 :     if (holder->IsJSGlobalObject()) {
     294             :       Handle<GlobalDictionary> dictionary(holder->global_dictionary());
     295             : 
     296             :       Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
     297         521 :           dictionary, dictionary_entry(), value, details);
     298         521 :       cell->set_value(*value);
     299         521 :       property_details_ = cell->property_details();
     300             :     } else {
     301             :       Handle<NameDictionary> dictionary(holder->property_dictionary());
     302             :       PropertyDetails original_details =
     303             :           dictionary->DetailsAt(dictionary_entry());
     304             :       int enumeration_index = original_details.dictionary_index();
     305             :       DCHECK(enumeration_index > 0);
     306             :       details = details.set_index(enumeration_index);
     307             :       dictionary->SetEntry(dictionary_entry(), name(), value, details);
     308        1647 :       property_details_ = details;
     309             :     }
     310        2168 :     state_ = DATA;
     311             :   }
     312             : 
     313     1550243 :   WriteDataValue(value, true);
     314             : 
     315             : #if VERIFY_HEAP
     316             :   if (FLAG_verify_heap) {
     317             :     holder->JSObjectVerify();
     318             :   }
     319             : #endif
     320     1550243 : }
     321             : 
     322             : // Can only be called when the receiver is a JSObject. JSProxy has to be handled
     323             : // via a trap. Adding properties to primitive values is not observable.
     324    53614893 : void LookupIterator::PrepareTransitionToDataProperty(
     325             :     Handle<JSObject> receiver, Handle<Object> value,
     326    52173026 :     PropertyAttributes attributes, Object::StoreFromKeyed store_mode) {
     327             :   DCHECK(receiver.is_identical_to(GetStoreTarget()));
     328    53614893 :   if (state_ == TRANSITION) return;
     329             : 
     330   104346060 :   if (!IsElement() && name()->IsPrivate()) {
     331     2808436 :     attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
     332             :   }
     333             : 
     334             :   DCHECK(state_ != LookupIterator::ACCESSOR ||
     335             :          (GetAccessors()->IsAccessorInfo() &&
     336             :           AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
     337             :   DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
     338             :   DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
     339             : 
     340    52173025 :   Handle<Map> map(receiver->map(), isolate_);
     341             : 
     342             :   // Dictionary maps can always have additional data properties.
     343    52173043 :   if (map->is_dictionary_map()) {
     344    21971442 :     state_ = TRANSITION;
     345    21971442 :     if (map->IsJSGlobalObjectMap()) {
     346             :       // Install a property cell.
     347             :       Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
     348             :       int entry;
     349             :       Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
     350     8833396 :           global, name(), PropertyCellType::kUninitialized, &entry);
     351             :       Handle<GlobalDictionary> dictionary(global->global_dictionary(),
     352     8833396 :                                           isolate_);
     353             :       DCHECK(cell->value()->IsTheHole(isolate_));
     354             :       DCHECK(!value->IsTheHole(isolate_));
     355     8833396 :       transition_ = cell;
     356             :       // Assign an enumeration index to the property and update
     357             :       // SetNextEnumerationIndex.
     358             :       int index = dictionary->NextEnumerationIndex();
     359     8833396 :       dictionary->SetNextEnumerationIndex(index + 1);
     360             :       property_details_ = PropertyDetails(kData, attributes, index,
     361     8833396 :                                           PropertyCellType::kUninitialized);
     362             :       PropertyCellType new_type =
     363     8833396 :           PropertyCell::UpdatedType(cell, value, property_details_);
     364     8833395 :       property_details_ = property_details_.set_cell_type(new_type);
     365             :       cell->set_property_details(property_details_);
     366     8833396 :       number_ = entry;
     367     8833396 :       has_property_ = true;
     368             :     } else {
     369             :       // Don't set enumeration index (it will be set during value store).
     370             :       property_details_ =
     371    13138046 :           PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell);
     372    13138046 :       transition_ = map;
     373             :     }
     374             :     return;
     375             :   }
     376             : 
     377             :   Handle<Map> transition = Map::TransitionToDataProperty(
     378    30201601 :       map, name_, value, attributes, kDefaultFieldConstness, store_mode);
     379    30201603 :   state_ = TRANSITION;
     380    30201603 :   transition_ = transition;
     381             : 
     382    30201603 :   if (transition->is_dictionary_map()) {
     383             :     // Don't set enumeration index (it will be set during value store).
     384             :     property_details_ =
     385      101209 :         PropertyDetails(kData, attributes, 0, PropertyCellType::kNoCell);
     386             :   } else {
     387    30100395 :     property_details_ = transition->GetLastDescriptorDetails();
     388    30100395 :     has_property_ = true;
     389             :   }
     390             : }
     391             : 
     392    52172281 : void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
     393             :   DCHECK_EQ(TRANSITION, state_);
     394             : 
     395             :   DCHECK(receiver.is_identical_to(GetStoreTarget()));
     396    52172281 :   holder_ = receiver;
     397    52172271 :   if (receiver->IsJSGlobalObject()) {
     398     8832630 :     state_ = DATA;
     399    52172274 :     return;
     400             :   }
     401             :   Handle<Map> transition = transition_map();
     402    43339641 :   bool simple_transition = transition->GetBackPointer() == receiver->map();
     403    43339639 :   JSObject::MigrateToMap(receiver, transition);
     404             : 
     405    43339643 :   if (simple_transition) {
     406             :     int number = transition->LastAdded();
     407    25880593 :     number_ = static_cast<uint32_t>(number);
     408    25880593 :     property_details_ = transition->GetLastDescriptorDetails();
     409    25880593 :     state_ = DATA;
     410    17459050 :   } else if (receiver->map()->is_dictionary_map()) {
     411             :     Handle<NameDictionary> dictionary(receiver->property_dictionary(),
     412    13239255 :                                       isolate_);
     413             :     int entry;
     414             :     dictionary = NameDictionary::Add(dictionary, name(),
     415             :                                      isolate_->factory()->uninitialized_value(),
     416    26478510 :                                      property_details_, &entry);
     417    13239255 :     receiver->set_properties(*dictionary);
     418             :     // Reload details containing proper enumeration index value.
     419    26478510 :     property_details_ = dictionary->DetailsAt(entry);
     420    13239255 :     number_ = entry;
     421    13239255 :     has_property_ = true;
     422    13239255 :     state_ = DATA;
     423             : 
     424             :   } else {
     425     4219795 :     ReloadPropertyInformation<false>();
     426             :   }
     427             : }
     428             : 
     429             : 
     430     6341519 : void LookupIterator::Delete() {
     431             :   Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
     432     6341519 :   if (IsElement()) {
     433             :     Handle<JSObject> object = Handle<JSObject>::cast(holder);
     434      164144 :     ElementsAccessor* accessor = object->GetElementsAccessor();
     435      164144 :     accessor->Delete(object, number_);
     436             :   } else {
     437             :     bool is_prototype_map = holder->map()->is_prototype_map();
     438             :     RuntimeCallTimerScope stats_scope(
     439             :         isolate_, is_prototype_map
     440             :                       ? &RuntimeCallStats::PrototypeObject_DeleteProperty
     441     6177375 :                       : &RuntimeCallStats::Object_DeleteProperty);
     442             : 
     443             :     PropertyNormalizationMode mode =
     444     6177375 :         is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
     445             : 
     446     6177375 :     if (holder->HasFastProperties()) {
     447             :       JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
     448      188691 :                                     "DeletingProperty");
     449      188691 :       ReloadPropertyInformation<false>();
     450             :     }
     451             :     // TODO(verwaest): Get rid of the name_ argument.
     452     6177375 :     JSReceiver::DeleteNormalizedProperty(holder, name_, number_);
     453     6177375 :     if (holder->IsJSObject()) {
     454     6177368 :       JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
     455             :     }
     456             :   }
     457     6341519 :   state_ = NOT_FOUND;
     458     6341519 : }
     459             : 
     460      508193 : void LookupIterator::TransitionToAccessorProperty(
     461             :     Handle<Object> getter, Handle<Object> setter,
     462     1932076 :     PropertyAttributes attributes) {
     463             :   DCHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
     464             :   // Can only be called when the receiver is a JSObject. JSProxy has to be
     465             :   // handled via a trap. Adding properties to primitive values is not
     466             :   // observable.
     467      508193 :   Handle<JSObject> receiver = GetStoreTarget();
     468      977074 :   if (!IsElement() && name()->IsPrivate()) {
     469          14 :     attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
     470             :   }
     471             : 
     472      977074 :   if (!IsElement() && !receiver->map()->is_dictionary_map()) {
     473      434909 :     Handle<Map> old_map(receiver->map(), isolate_);
     474             : 
     475      434909 :     if (!holder_.is_identical_to(receiver)) {
     476           0 :       holder_ = receiver;
     477           0 :       state_ = NOT_FOUND;
     478      434909 :     } else if (state_ == INTERCEPTOR) {
     479          42 :       LookupInRegularHolder<false>(*old_map, *holder_);
     480             :     }
     481             :     int descriptor =
     482      434909 :         IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound;
     483             : 
     484             :     Handle<Map> new_map = Map::TransitionToAccessorProperty(
     485      434909 :         isolate_, old_map, name_, descriptor, getter, setter, attributes);
     486      434910 :     bool simple_transition = new_map->GetBackPointer() == receiver->map();
     487      434910 :     JSObject::MigrateToMap(receiver, new_map);
     488             : 
     489      434910 :     if (simple_transition) {
     490             :       int number = new_map->LastAdded();
     491       30015 :       number_ = static_cast<uint32_t>(number);
     492       30015 :       property_details_ = new_map->GetLastDescriptorDetails();
     493       30015 :       state_ = ACCESSOR;
     494       30015 :       return;
     495             :     }
     496             : 
     497      404895 :     ReloadPropertyInformation<false>();
     498      404895 :     if (!new_map->is_dictionary_map()) return;
     499             :   }
     500             : 
     501             :   Handle<AccessorPair> pair;
     502      266533 :   if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
     503             :     pair = Handle<AccessorPair>::cast(GetAccessors());
     504             :     // If the component and attributes are identical, nothing has to be done.
     505       17291 :     if (pair->Equals(*getter, *setter)) {
     506          44 :       if (property_details().attributes() == attributes) {
     507           0 :         if (!IsElement()) JSObject::ReoptimizeIfPrototype(receiver);
     508             :         return;
     509             :       }
     510             :     } else {
     511       17247 :       pair = AccessorPair::Copy(pair);
     512       17247 :       pair->SetComponents(*getter, *setter);
     513             :     }
     514             :   } else {
     515      231744 :     pair = factory()->NewAccessorPair();
     516      231744 :     pair->SetComponents(*getter, *setter);
     517             :   }
     518             : 
     519      249035 :   TransitionToAccessorPair(pair, attributes);
     520             : 
     521             : #if VERIFY_HEAP
     522             :   if (FLAG_verify_heap) {
     523             :     receiver->JSObjectVerify();
     524             :   }
     525             : #endif
     526             : }
     527             : 
     528             : 
     529      446342 : void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
     530      446400 :                                               PropertyAttributes attributes) {
     531      446342 :   Handle<JSObject> receiver = GetStoreTarget();
     532      446342 :   holder_ = receiver;
     533             : 
     534             :   PropertyDetails details(kAccessor, attributes, 0, PropertyCellType::kMutable);
     535             : 
     536      446342 :   if (IsElement()) {
     537             :     // TODO(verwaest): Move code into the element accessor.
     538             :     Handle<SeededNumberDictionary> dictionary =
     539       39328 :         JSObject::NormalizeElements(receiver);
     540             : 
     541             :     dictionary = SeededNumberDictionary::Set(dictionary, index_, pair, details,
     542       39328 :                                              receiver);
     543       39328 :     receiver->RequireSlowElements(*dictionary);
     544             : 
     545       39328 :     if (receiver->HasSlowArgumentsElements()) {
     546             :       FixedArray* parameter_map = FixedArray::cast(receiver->elements());
     547         102 :       uint32_t length = parameter_map->length() - 2;
     548         102 :       if (number_ < length) {
     549          58 :         parameter_map->set(number_ + 2, heap()->the_hole_value());
     550             :       }
     551         102 :       FixedArray::cast(receiver->elements())->set(1, *dictionary);
     552             :     } else {
     553       39226 :       receiver->set_elements(*dictionary);
     554             :     }
     555             : 
     556       39328 :     ReloadPropertyInformation<true>();
     557             :   } else {
     558             :     PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
     559             :                                          ? KEEP_INOBJECT_PROPERTIES
     560      407014 :                                          : CLEAR_INOBJECT_PROPERTIES;
     561             :     // Normalize object to make this operation simple.
     562             :     JSObject::NormalizeProperties(receiver, mode, 0,
     563      407014 :                                   "TransitionToAccessorPair");
     564             : 
     565      407014 :     JSObject::SetNormalizedProperty(receiver, name_, pair, details);
     566      407014 :     JSObject::ReoptimizeIfPrototype(receiver);
     567             : 
     568      407014 :     ReloadPropertyInformation<false>();
     569             :   }
     570      446342 : }
     571             : 
     572             : 
     573    15257120 : bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
     574             :   DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
     575             :   // Optimization that only works if configuration_ is not mutable.
     576    15247841 :   if (!check_prototype_chain()) return true;
     577             :   DisallowHeapAllocation no_gc;
     578    15224632 :   if (*receiver_ == *holder_) return true;
     579      440880 :   if (!receiver_->IsJSReceiver()) return false;
     580             :   JSReceiver* current = JSReceiver::cast(*receiver_);
     581             :   JSReceiver* object = *holder_;
     582      437717 :   if (!current->map()->has_hidden_prototype()) return false;
     583             :   // JSProxy do not occur as hidden prototypes.
     584        9279 :   if (object->IsJSProxy()) return false;
     585             :   PrototypeIterator iter(isolate(), current, kStartAtPrototype,
     586             :                          PrototypeIterator::END_AT_NON_HIDDEN);
     587        9889 :   while (!iter.IsAtEnd()) {
     588        9279 :     if (iter.GetCurrent<JSReceiver>() == object) return true;
     589         610 :     iter.Advance();
     590             :   }
     591             :   return false;
     592             : }
     593             : 
     594             : 
     595   191053823 : Handle<Object> LookupIterator::FetchValue() const {
     596             :   Object* result = NULL;
     597   191053823 :   if (IsElement()) {
     598             :     Handle<JSObject> holder = GetHolder<JSObject>();
     599    74015388 :     ElementsAccessor* accessor = holder->GetElementsAccessor();
     600    74015388 :     return accessor->Get(holder, number_);
     601   117038450 :   } else if (holder_->IsJSGlobalObject()) {
     602             :     Handle<JSObject> holder = GetHolder<JSObject>();
     603    14371256 :     result = holder->global_dictionary()->ValueAt(number_);
     604             :     DCHECK(result->IsPropertyCell());
     605             :     result = PropertyCell::cast(result)->value();
     606   109852822 :   } else if (!holder_->HasFastProperties()) {
     607     8067712 :     result = holder_->property_dictionary()->ValueAt(number_);
     608   105818969 :   } else if (property_details_.location() == kField) {
     609             :     DCHECK_EQ(kData, property_details_.kind());
     610             :     Handle<JSObject> holder = GetHolder<JSObject>();
     611   112391478 :     FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
     612             :     return JSObject::FastPropertyAt(holder, property_details_.representation(),
     613    56195739 :                                     field_index);
     614             :   } else {
     615    49623230 :     result = holder_->map()->instance_descriptors()->GetValue(number_);
     616             :   }
     617    60842714 :   return handle(result, isolate_);
     618             : }
     619             : 
     620           0 : bool LookupIterator::IsConstFieldValueEqualTo(Object* value) const {
     621             :   DCHECK(!IsElement());
     622             :   DCHECK(holder_->HasFastProperties());
     623             :   DCHECK_EQ(kField, property_details_.location());
     624             :   DCHECK_EQ(kConst, property_details_.constness());
     625             :   Handle<JSObject> holder = GetHolder<JSObject>();
     626           0 :   FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
     627           0 :   if (property_details_.representation().IsDouble()) {
     628           0 :     if (!value->IsNumber()) return false;
     629             :     uint64_t bits;
     630           0 :     if (holder->IsUnboxedDoubleField(field_index)) {
     631             :       bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
     632             :     } else {
     633           0 :       Object* current_value = holder->RawFastPropertyAt(field_index);
     634             :       DCHECK(current_value->IsMutableHeapNumber());
     635             :       bits = HeapNumber::cast(current_value)->value_as_bits();
     636             :     }
     637             :     // Use bit representation of double to to check for hole double, since
     638             :     // manipulating the signaling NaN used for the hole in C++, e.g. with
     639             :     // bit_cast or value(), will change its value on ia32 (the x87 stack is
     640             :     // used to return values and stores to the stack silently clear the
     641             :     // signalling bit).
     642           0 :     if (bits == kHoleNanInt64) {
     643             :       // Uninitialized double field.
     644             :       return true;
     645             :     }
     646           0 :     return bit_cast<double>(bits) == value->Number();
     647             :   } else {
     648           0 :     Object* current_value = holder->RawFastPropertyAt(field_index);
     649           0 :     return current_value->IsUninitialized(isolate()) || current_value == value;
     650             :   }
     651             : }
     652             : 
     653      329326 : int LookupIterator::GetFieldDescriptorIndex() const {
     654             :   DCHECK(has_property_);
     655             :   DCHECK(holder_->HasFastProperties());
     656             :   DCHECK_EQ(kField, property_details_.location());
     657             :   DCHECK_EQ(kData, property_details_.kind());
     658      329326 :   return descriptor_number();
     659             : }
     660             : 
     661      132444 : int LookupIterator::GetAccessorIndex() const {
     662             :   DCHECK(has_property_);
     663             :   DCHECK(holder_->HasFastProperties());
     664             :   DCHECK_EQ(kDescriptor, property_details_.location());
     665             :   DCHECK_EQ(kAccessor, property_details_.kind());
     666      132444 :   return descriptor_number();
     667             : }
     668             : 
     669             : 
     670     1380082 : int LookupIterator::GetConstantIndex() const {
     671             :   DCHECK(has_property_);
     672             :   DCHECK(holder_->HasFastProperties());
     673             :   DCHECK_EQ(kDescriptor, property_details_.location());
     674             :   DCHECK_EQ(kData, property_details_.kind());
     675             :   DCHECK(!FLAG_track_constant_fields);
     676             :   DCHECK(!IsElement());
     677     1380082 :   return descriptor_number();
     678             : }
     679             : 
     680           0 : Handle<Map> LookupIterator::GetFieldOwnerMap() const {
     681             :   DCHECK(has_property_);
     682             :   DCHECK(holder_->HasFastProperties());
     683             :   DCHECK_EQ(kField, property_details_.location());
     684             :   DCHECK(!IsElement());
     685             :   Map* holder_map = holder_->map();
     686           0 :   return handle(holder_map->FindFieldOwner(descriptor_number()), isolate_);
     687             : }
     688             : 
     689     4362538 : FieldIndex LookupIterator::GetFieldIndex() const {
     690             :   DCHECK(has_property_);
     691             :   DCHECK(holder_->HasFastProperties());
     692             :   DCHECK_EQ(kField, property_details_.location());
     693             :   DCHECK(!IsElement());
     694             :   Map* holder_map = holder_->map();
     695             :   int index =
     696             :       holder_map->instance_descriptors()->GetFieldIndex(descriptor_number());
     697             :   bool is_double = representation().IsDouble();
     698     2181270 :   return FieldIndex::ForPropertyIndex(holder_map, index, is_double);
     699             : }
     700             : 
     701           0 : Handle<FieldType> LookupIterator::GetFieldType() const {
     702             :   DCHECK(has_property_);
     703             :   DCHECK(holder_->HasFastProperties());
     704             :   DCHECK_EQ(kField, property_details_.location());
     705             :   return handle(
     706             :       holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()),
     707           0 :       isolate_);
     708             : }
     709             : 
     710             : 
     711     4721899 : Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
     712             :   DCHECK(!IsElement());
     713             :   Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
     714     4721899 :   Object* value = holder->global_dictionary()->ValueAt(dictionary_entry());
     715             :   DCHECK(value->IsPropertyCell());
     716     9443802 :   return handle(PropertyCell::cast(value), isolate_);
     717             : }
     718             : 
     719             : 
     720    14546571 : Handle<Object> LookupIterator::GetAccessors() const {
     721             :   DCHECK_EQ(ACCESSOR, state_);
     722    33332858 :   return FetchValue();
     723             : }
     724             : 
     725             : 
     726   157720956 : Handle<Object> LookupIterator::GetDataValue() const {
     727             :   DCHECK_EQ(DATA, state_);
     728   157720956 :   Handle<Object> value = FetchValue();
     729   157720935 :   return value;
     730             : }
     731             : 
     732    69223123 : void LookupIterator::WriteDataValue(Handle<Object> value,
     733   130340974 :                                     bool initializing_store) {
     734             :   DCHECK_EQ(DATA, state_);
     735             :   Handle<JSReceiver> holder = GetHolder<JSReceiver>();
     736    69223123 :   if (IsElement()) {
     737             :     Handle<JSObject> object = Handle<JSObject>::cast(holder);
     738     1376032 :     ElementsAccessor* accessor = object->GetElementsAccessor();
     739     2752064 :     accessor->Set(object, number_, *value);
     740    67847091 :   } else if (holder->HasFastProperties()) {
     741    40432007 :     if (property_details_.location() == kField) {
     742             :       // Check that in case of kConst field the existing value is equal to
     743             :       // |value|.
     744             :       DCHECK_IMPLIES(
     745             :           !initializing_store && property_details_.constness() == kConst,
     746             :           IsConstFieldValueEqualTo(*value));
     747             :       JSObject::cast(*holder)->WriteToField(descriptor_number(),
     748    33702755 :                                             property_details_, *value);
     749             :     } else {
     750             :       DCHECK_EQ(kDescriptor, property_details_.location());
     751             :       DCHECK_EQ(kConst, property_details_.constness());
     752             :     }
     753    27415096 :   } else if (holder->IsJSGlobalObject()) {
     754             :     GlobalDictionary* dictionary = JSObject::cast(*holder)->global_dictionary();
     755    11822139 :     Object* cell = dictionary->ValueAt(dictionary_entry());
     756             :     DCHECK(cell->IsPropertyCell());
     757    11822140 :     PropertyCell::cast(cell)->set_value(*value);
     758             :   } else {
     759             :     NameDictionary* dictionary = holder->property_dictionary();
     760             :     dictionary->ValueAtPut(dictionary_entry(), *value);
     761             :   }
     762    69223141 : }
     763             : 
     764             : template <bool is_element>
     765     1066926 : bool LookupIterator::SkipInterceptor(JSObject* holder) {
     766             :   auto info = GetInterceptor<is_element>(holder);
     767      706707 :   if (!is_element && name_->IsSymbol() && !info->can_intercept_symbols()) {
     768             :     return true;
     769             :   }
     770     1066912 :   if (info->non_masking()) {
     771         469 :     switch (interceptor_state_) {
     772             :       case InterceptorState::kUninitialized:
     773         294 :         interceptor_state_ = InterceptorState::kSkipNonMasking;
     774             :       // Fall through.
     775             :       case InterceptorState::kSkipNonMasking:
     776             :         return true;
     777             :       case InterceptorState::kProcessNonMasking:
     778             :         return false;
     779             :     }
     780             :   }
     781     1066443 :   return interceptor_state_ == InterceptorState::kProcessNonMasking;
     782             : }
     783             : 
     784   945051101 : JSReceiver* LookupIterator::NextHolder(Map* map) {
     785             :   DisallowHeapAllocation no_gc;
     786   553588200 :   if (map->prototype() == heap()->null_value()) return NULL;
     787   478152972 :   if (!check_prototype_chain() && !map->has_hidden_prototype()) return NULL;
     788             :   return JSReceiver::cast(map->prototype());
     789             : }
     790             : 
     791   196802215 : LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const {
     792             :   DCHECK(!IsElement());
     793   196992961 :   if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
     794             : 
     795             :   Handle<String> name_string = Handle<String>::cast(name_);
     796      162316 :   if (name_string->length() == 0) return NOT_FOUND;
     797             : 
     798      162316 :   return IsSpecialIndex(isolate_->unicode_cache(), *name_string)
     799             :              ? INTEGER_INDEXED_EXOTIC
     800      162316 :              : NOT_FOUND;
     801             : }
     802             : 
     803             : namespace {
     804             : 
     805             : template <bool is_element>
     806             : bool HasInterceptor(Map* map) {
     807             :   return is_element ? map->has_indexed_interceptor()
     808             :                     : map->has_named_interceptor();
     809             : }
     810             : 
     811             : }  // namespace
     812             : 
     813             : template <bool is_element>
     814    57880103 : LookupIterator::State LookupIterator::LookupInSpecialHolder(
     815             :     Map* const map, JSReceiver* const holder) {
     816             :   STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
     817    57880103 :   switch (state_) {
     818             :     case NOT_FOUND:
     819    48128424 :       if (map->IsJSProxyMap()) {
     820      352762 :         if (is_element || !name_->IsPrivate()) return JSPROXY;
     821             :       }
     822    47760916 :       if (map->is_access_check_needed()) {
     823    10261312 :         if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
     824             :       }
     825             :     // Fall through.
     826             :     case ACCESS_CHECK:
     827    77029626 :       if (check_interceptor() && HasInterceptor<is_element>(map) &&
     828     1066926 :           !SkipInterceptor<is_element>(JSObject::cast(holder))) {
     829      706331 :         if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
     830             :       }
     831             :     // Fall through.
     832             :     case INTERCEPTOR:
     833    47388796 :       if (!is_element && map->IsJSGlobalObjectMap()) {
     834             :         GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
     835    36139075 :         int number = dict->FindEntry(name_);
     836    36139070 :         if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
     837    16634600 :         number_ = static_cast<uint32_t>(number);
     838             :         DCHECK(dict->ValueAt(number_)->IsPropertyCell());
     839    16634600 :         PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
     840    33269200 :         if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
     841    16590630 :         property_details_ = cell->property_details();
     842    16590630 :         has_property_ = true;
     843    16590630 :         switch (property_details_.kind()) {
     844             :           case v8::internal::kData:
     845             :             return DATA;
     846             :           case v8::internal::kAccessor:
     847       58545 :             return ACCESSOR;
     848             :         }
     849             :       }
     850    11626006 :       return LookupInRegularHolder<is_element>(map, holder);
     851             :     case ACCESSOR:
     852             :     case DATA:
     853             :       return NOT_FOUND;
     854             :     case INTEGER_INDEXED_EXOTIC:
     855             :     case JSPROXY:
     856             :     case TRANSITION:
     857           0 :       UNREACHABLE();
     858             :   }
     859           0 :   UNREACHABLE();
     860             :   return NOT_FOUND;
     861             : }
     862             : 
     863             : template <bool is_element>
     864   770328000 : LookupIterator::State LookupIterator::LookupInRegularHolder(
     865             :     Map* const map, JSReceiver* const holder) {
     866             :   DisallowHeapAllocation no_gc;
     867   770328000 :   if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
     868             :     return NOT_FOUND;
     869             :   }
     870             : 
     871             :   if (is_element) {
     872             :     JSObject* js_object = JSObject::cast(holder);
     873   414308518 :     ElementsAccessor* accessor = js_object->GetElementsAccessor();
     874             :     FixedArrayBase* backing_store = js_object->elements();
     875   414308517 :     number_ =
     876   414308518 :         accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
     877   414308517 :     if (number_ == kMaxUInt32) {
     878   337822400 :       return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
     879             :     }
     880    76486117 :     property_details_ = accessor->GetDetails(js_object, number_);
     881   356019370 :   } else if (!map->is_dictionary_map()) {
     882             :     DescriptorArray* descriptors = map->instance_descriptors();
     883   327106104 :     int number = descriptors->SearchWithCache(isolate_, *name_, map);
     884   327106225 :     if (number == DescriptorArray::kNotFound) return NotFound(holder);
     885   146053693 :     number_ = static_cast<uint32_t>(number);
     886   146053693 :     property_details_ = descriptors->GetDetails(number_);
     887             :   } else {
     888             :     NameDictionary* dict = holder->property_dictionary();
     889    28913266 :     int number = dict->FindEntry(name_);
     890    28913266 :     if (number == NameDictionary::kNotFound) return NotFound(holder);
     891    13163578 :     number_ = static_cast<uint32_t>(number);
     892    13163578 :     property_details_ = dict->DetailsAt(number_);
     893             :   }
     894   235703392 :   has_property_ = true;
     895   235703392 :   switch (property_details_.kind()) {
     896             :     case v8::internal::kData:
     897             :       return DATA;
     898             :     case v8::internal::kAccessor:
     899    15264990 :       return ACCESSOR;
     900             :   }
     901             : 
     902           0 :   UNREACHABLE();
     903             :   return state_;
     904             : }
     905             : 
     906        1660 : Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
     907        1325 :     const {
     908             :   DCHECK_EQ(ACCESS_CHECK, state_);
     909             :   DisallowHeapAllocation no_gc;
     910             :   AccessCheckInfo* access_check_info =
     911        1660 :       AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
     912        1660 :   if (access_check_info) {
     913             :     Object* interceptor = IsElement() ? access_check_info->indexed_interceptor()
     914        1325 :                                       : access_check_info->named_interceptor();
     915        1325 :     if (interceptor) {
     916         203 :       return handle(InterceptorInfo::cast(interceptor), isolate_);
     917             :     }
     918             :   }
     919        1457 :   return Handle<InterceptorInfo>();
     920             : }
     921             : 
     922    12171028 : bool LookupIterator::TryLookupCachedProperty() {
     923     9376179 :   return state() == LookupIterator::ACCESSOR &&
     924    21546347 :          GetAccessors()->IsAccessorPair() && LookupCachedProperty();
     925             : }
     926             : 
     927    28126067 : bool LookupIterator::LookupCachedProperty() {
     928             :   DCHECK_EQ(state(), LookupIterator::ACCESSOR);
     929             :   DCHECK(GetAccessors()->IsAccessorPair());
     930             : 
     931             :   AccessorPair* accessor_pair = AccessorPair::cast(*GetAccessors());
     932             :   Handle<Object> getter(accessor_pair->getter(), isolate());
     933             :   MaybeHandle<Name> maybe_name =
     934     9375319 :       FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
     935     9375319 :   if (maybe_name.is_null()) return false;
     936             : 
     937             :   // We have found a cached property! Modify the iterator accordingly.
     938         110 :   name_ = maybe_name.ToHandleChecked();
     939         110 :   Restart();
     940         110 :   CHECK_EQ(state(), LookupIterator::DATA);
     941             :   return true;
     942             : }
     943             : 
     944             : }  // namespace internal
     945             : }  // namespace v8

Generated by: LCOV version 1.10