LCOV - code coverage report
Current view: top level - src - map-updater.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 274 310 88.4 %
Date: 2019-03-21 Functions: 19 20 95.0 %

          Line data    Source code
       1             : // Copyright 2017 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/map-updater.h"
       6             : 
       7             : #include "src/field-type.h"
       8             : #include "src/handles.h"
       9             : #include "src/isolate.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/objects.h"
      12             : #include "src/property-details.h"
      13             : #include "src/transitions.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : namespace {
      19             : 
      20             : inline bool EqualImmutableValues(Object obj1, Object obj2) {
      21       16554 :   if (obj1 == obj2) return true;  // Valid for both kData and kAccessor kinds.
      22             :   // TODO(ishell): compare AccessorPairs.
      23             :   return false;
      24             : }
      25             : 
      26             : }  // namespace
      27             : 
      28      595600 : MapUpdater::MapUpdater(Isolate* isolate, Handle<Map> old_map)
      29             :     : isolate_(isolate),
      30             :       old_map_(old_map),
      31             :       old_descriptors_(old_map->instance_descriptors(), isolate_),
      32             :       old_nof_(old_map_->NumberOfOwnDescriptors()),
      33             :       new_elements_kind_(old_map_->elements_kind()),
      34             :       is_transitionable_fast_elements_kind_(
      35     2978000 :           IsTransitionableFastElementsKind(new_elements_kind_)) {
      36             :   // We shouldn't try to update remote objects.
      37             :   DCHECK(!old_map->FindRootMap(isolate)
      38             :               ->GetConstructor()
      39             :               ->IsFunctionTemplateInfo());
      40      595600 : }
      41             : 
      42             : Name MapUpdater::GetKey(int descriptor) const {
      43      647852 :   return old_descriptors_->GetKey(descriptor);
      44             : }
      45             : 
      46      646552 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
      47             :   DCHECK_LE(0, descriptor);
      48      646552 :   if (descriptor == modified_descriptor_) {
      49      129788 :     PropertyAttributes attributes = new_attributes_;
      50             :     // If the original map was sealed or frozen, let us used the old
      51             :     // attributes so that we follow the same transition path as before.
      52             :     // Note that the user could not have changed the attributes because
      53             :     // both seal and freeze make the properties non-configurable.
      54      129788 :     if (integrity_level_ == SEALED || integrity_level_ == FROZEN) {
      55         590 :       attributes = old_descriptors_->GetDetails(descriptor).attributes();
      56             :     }
      57      129788 :     return PropertyDetails(new_kind_, attributes, new_location_, new_constness_,
      58      129788 :                            new_representation_);
      59             :   }
      60      516764 :   return old_descriptors_->GetDetails(descriptor);
      61             : }
      62             : 
      63       16642 : Object MapUpdater::GetValue(int descriptor) const {
      64             :   DCHECK_LE(0, descriptor);
      65       16642 :   if (descriptor == modified_descriptor_) {
      66             :     DCHECK_EQ(kDescriptor, new_location_);
      67             :     return *new_value_;
      68             :   }
      69             :   DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
      70       16642 :   return old_descriptors_->GetStrongValue(descriptor);
      71             : }
      72             : 
      73      581939 : FieldType MapUpdater::GetFieldType(int descriptor) const {
      74             :   DCHECK_LE(0, descriptor);
      75      581939 :   if (descriptor == modified_descriptor_) {
      76             :     DCHECK_EQ(kField, new_location_);
      77             :     return *new_field_type_;
      78             :   }
      79             :   DCHECK_EQ(kField, GetDetails(descriptor).location());
      80      968016 :   return old_descriptors_->GetFieldType(descriptor);
      81             : }
      82             : 
      83      581939 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      84             :     int descriptor, PropertyLocation location,
      85             :     Representation representation) const {
      86             :   DCHECK_LE(0, descriptor);
      87             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      88             :   DCHECK_EQ(location, GetDetails(descriptor).location());
      89      581939 :   if (location == kField) {
      90      581939 :     return handle(GetFieldType(descriptor), isolate_);
      91             :   } else {
      92           0 :     return GetValue(descriptor)->OptimalType(isolate_, representation);
      93             :   }
      94             : }
      95             : 
      96      350749 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      97             :     Handle<DescriptorArray> descriptors, int descriptor,
      98             :     PropertyLocation location, Representation representation) {
      99             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
     100             :   DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
     101      350749 :   if (location == kField) {
     102     1052249 :     return handle(descriptors->GetFieldType(descriptor), isolate_);
     103             :   } else {
     104           0 :     return descriptors->GetStrongValue(descriptor)
     105           0 :         ->OptimalType(isolate_, representation);
     106             :   }
     107             : }
     108             : 
     109      300826 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
     110             :                                                PropertyAttributes attributes,
     111             :                                                PropertyConstness constness,
     112             :                                                Representation representation,
     113             :                                                Handle<FieldType> field_type) {
     114             :   DCHECK_EQ(kInitialized, state_);
     115             :   DCHECK_LE(0, descriptor);
     116             :   DCHECK(!old_map_->is_dictionary_map());
     117      300826 :   modified_descriptor_ = descriptor;
     118      300826 :   new_kind_ = kData;
     119      300826 :   new_attributes_ = attributes;
     120      300826 :   new_location_ = kField;
     121             : 
     122             :   PropertyDetails old_details =
     123      300826 :       old_descriptors_->GetDetails(modified_descriptor_);
     124             : 
     125             :   // If property kind is not reconfigured merge the result with
     126             :   // representation/field type from the old descriptor.
     127      300827 :   if (old_details.kind() == new_kind_) {
     128      285690 :     new_constness_ = GeneralizeConstness(constness, old_details.constness());
     129             : 
     130      285690 :     Representation old_representation = old_details.representation();
     131      285690 :     new_representation_ = representation.generalize(old_representation);
     132             : 
     133             :     Handle<FieldType> old_field_type =
     134             :         GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
     135      285690 :                               old_details.location(), new_representation_);
     136             : 
     137             :     new_field_type_ =
     138             :         Map::GeneralizeFieldType(old_representation, old_field_type,
     139      285691 :                                  new_representation_, field_type, isolate_);
     140             :   } else {
     141             :     // We don't know if this is a first property kind reconfiguration
     142             :     // and we don't know which value was in this property previously
     143             :     // therefore we can't treat such a property as constant.
     144       15137 :     new_constness_ = PropertyConstness::kMutable;
     145       15137 :     new_representation_ = representation;
     146       15137 :     new_field_type_ = field_type;
     147             :   }
     148             : 
     149      601654 :   Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
     150             :       isolate_, old_map_->instance_type(), &new_constness_,
     151      300827 :       &new_representation_, &new_field_type_);
     152             : 
     153      300829 :   if (TryReconfigureToDataFieldInplace() == kEnd) return result_map_;
     154      124749 :   if (FindRootMap() == kEnd) return result_map_;
     155      108607 :   if (FindTargetMap() == kEnd) return result_map_;
     156       10687 :   if (ConstructNewMap() == kAtIntegrityLevelSource) {
     157          85 :     ConstructNewMapWithIntegrityLevelTransition();
     158             :   }
     159             :   DCHECK_EQ(kEnd, state_);
     160       10687 :   return result_map_;
     161             : }
     162             : 
     163      291815 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
     164             :   DCHECK_EQ(kInitialized, state_);
     165      291815 :   new_elements_kind_ = elements_kind;
     166             :   is_transitionable_fast_elements_kind_ =
     167      291815 :       IsTransitionableFastElementsKind(new_elements_kind_);
     168             : 
     169      291815 :   if (FindRootMap() == kEnd) return result_map_;
     170      291815 :   if (FindTargetMap() == kEnd) return result_map_;
     171         829 :   if (ConstructNewMap() == kAtIntegrityLevelSource) {
     172           0 :     ConstructNewMapWithIntegrityLevelTransition();
     173             :   }
     174             :   DCHECK_EQ(kEnd, state_);
     175         829 :   return result_map_;
     176             : }
     177             : 
     178        2957 : Handle<Map> MapUpdater::Update() {
     179             :   DCHECK_EQ(kInitialized, state_);
     180             :   DCHECK(old_map_->is_deprecated());
     181             : 
     182        2957 :   if (FindRootMap() == kEnd) return result_map_;
     183        2957 :   if (FindTargetMap() == kEnd) return result_map_;
     184         300 :   if (ConstructNewMap() == kAtIntegrityLevelSource) {
     185         168 :     ConstructNewMapWithIntegrityLevelTransition();
     186             :   }
     187             :   DCHECK_EQ(kEnd, state_);
     188             :   if (FLAG_fast_map_update) {
     189             :     TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
     190             :   }
     191         300 :   return result_map_;
     192             : }
     193             : 
     194           0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
     195             :                                  PropertyConstness new_constness,
     196             :                                  Representation new_representation,
     197             :                                  Handle<FieldType> new_field_type) {
     198      701430 :   Map::GeneralizeField(isolate_, map, modify_index, new_constness,
     199      701430 :                        new_representation, new_field_type);
     200             : 
     201             :   DCHECK(*old_descriptors_ == old_map_->instance_descriptors() ||
     202             :          *old_descriptors_ == integrity_source_map_->instance_descriptors());
     203           0 : }
     204             : 
     205       16185 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
     206             :   result_map_ = Map::CopyGeneralizeAllFields(
     207       16185 :       isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
     208       32370 :       new_attributes_, reason);
     209       16185 :   state_ = kEnd;
     210       16185 :   return state_;  // Done.
     211             : }
     212             : 
     213      300828 : MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() {
     214             :   // If it's just a representation generalization case (i.e. property kind and
     215             :   // attributes stays unchanged) it's fine to transition from None to anything
     216             :   // but double without any modification to the object, because the default
     217             :   // uninitialized value for representation None can be overwritten by both
     218             :   // smi and tagged values. Doubles, however, would require a box allocation.
     219      300828 :   if (new_representation_.IsNone() || new_representation_.IsDouble()) {
     220       27738 :     return state_;  // Not done yet.
     221             :   }
     222             : 
     223             :   PropertyDetails old_details =
     224      546180 :       old_descriptors_->GetDetails(modified_descriptor_);
     225             :   Representation old_representation = old_details.representation();
     226      273091 :   if (!old_representation.IsNone()) {
     227       97011 :     return state_;  // Not done yet.
     228             :   }
     229             : 
     230             :   DCHECK_EQ(new_kind_, old_details.kind());
     231             :   DCHECK_EQ(new_attributes_, old_details.attributes());
     232             :   DCHECK_EQ(kField, old_details.location());
     233      176080 :   if (FLAG_trace_generalization) {
     234           0 :     old_map_->PrintGeneralization(
     235             :         isolate_, stdout, "uninitialized field", modified_descriptor_, old_nof_,
     236             :         old_nof_, false, old_representation, new_representation_,
     237             :         handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
     238           0 :         MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
     239             :   }
     240             :   Handle<Map> field_owner(
     241      528240 :       old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_);
     242             : 
     243      176080 :   GeneralizeField(field_owner, modified_descriptor_, new_constness_,
     244             :                   new_representation_, new_field_type_);
     245             :   // Check that the descriptor array was updated.
     246             :   DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
     247             :              .representation()
     248             :              .Equals(new_representation_));
     249             :   DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
     250             :              ->NowIs(new_field_type_));
     251             : 
     252      176077 :   result_map_ = old_map_;
     253      176077 :   state_ = kEnd;
     254      176077 :   return state_;  // Done.
     255             : }
     256             : 
     257         401 : bool MapUpdater::TrySaveIntegrityLevelTransitions() {
     258             :   // Figure out the most restrictive integrity level transition (it should
     259             :   // be the last one in the transition tree).
     260             :   Handle<Map> previous =
     261        1203 :       handle(Map::cast(old_map_->GetBackPointer()), isolate_);
     262         401 :   Symbol integrity_level_symbol;
     263         401 :   TransitionsAccessor last_transitions(isolate_, previous);
     264         802 :   if (!last_transitions.HasIntegrityLevelTransitionTo(
     265             :           *old_map_, &integrity_level_symbol, &integrity_level_)) {
     266             :     // The last transition was not integrity level transition - just bail out.
     267             :     // This can happen in the following cases:
     268             :     // - there are private symbol transitions following the integrity level
     269             :     //   transitions (see crbug.com/v8/8854).
     270             :     // - there is a getter added in addition to an existing setter (or a setter
     271             :     //   in addition to an existing getter).
     272             :     return false;
     273             :   }
     274         748 :   integrity_level_symbol_ = handle(integrity_level_symbol, isolate_);
     275         374 :   integrity_source_map_ = previous;
     276             : 
     277             :   // Now walk up the back pointer chain and skip all integrity level
     278             :   // transitions. If we encounter any non-integrity level transition interleaved
     279             :   // with integrity level transitions, just bail out.
     280         432 :   while (!integrity_source_map_->is_extensible()) {
     281             :     previous =
     282          58 :         handle(Map::cast(integrity_source_map_->GetBackPointer()), isolate_);
     283          29 :     TransitionsAccessor transitions(isolate_, previous);
     284          29 :     if (!transitions.HasIntegrityLevelTransitionTo(*integrity_source_map_)) {
     285           0 :       return false;
     286             :     }
     287          29 :     integrity_source_map_ = previous;
     288             :   }
     289             : 
     290             :   // Integrity-level transitions never change number of descriptors.
     291         374 :   CHECK_EQ(old_map_->NumberOfOwnDescriptors(),
     292             :            integrity_source_map_->NumberOfOwnDescriptors());
     293             : 
     294         374 :   has_integrity_level_transition_ = true;
     295             :   old_descriptors_ =
     296         748 :       handle(integrity_source_map_->instance_descriptors(), isolate_);
     297         374 :   return true;
     298             : }
     299             : 
     300      419520 : MapUpdater::State MapUpdater::FindRootMap() {
     301             :   DCHECK_EQ(kInitialized, state_);
     302             :   // Check the state of the root map.
     303     1258561 :   root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
     304             :   ElementsKind from_kind = root_map_->elements_kind();
     305      419521 :   ElementsKind to_kind = new_elements_kind_;
     306             : 
     307      419521 :   if (root_map_->is_deprecated()) {
     308           0 :     state_ = kEnd;
     309             :     result_map_ = handle(
     310           0 :         JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
     311           0 :     result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind);
     312             :     DCHECK(result_map_->is_dictionary_map());
     313           0 :     return state_;
     314             :   }
     315             : 
     316      419521 :   if (!old_map_->EquivalentToForTransition(*root_map_)) {
     317          18 :     return CopyGeneralizeAllFields("GenAll_NotEquivalent");
     318      419503 :   } else if (old_map_->is_extensible() != root_map_->is_extensible()) {
     319             :     DCHECK(!old_map_->is_extensible());
     320             :     DCHECK(root_map_->is_extensible());
     321             :     // We have an integrity level transition in the tree, let us make a note
     322             :     // of that transition to be able to replay it later.
     323         401 :     if (!TrySaveIntegrityLevelTransitions()) {
     324          27 :       return CopyGeneralizeAllFields("GenAll_PrivateSymbolsOnNonExtensible");
     325             :     }
     326             : 
     327             :     // We want to build transitions to the original element kind (before
     328             :     // the seal transitions), so change {to_kind} accordingly.
     329             :     DCHECK(to_kind == DICTIONARY_ELEMENTS ||
     330             :            to_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
     331             :            IsFixedTypedArrayElementsKind(to_kind));
     332             :     to_kind = integrity_source_map_->elements_kind();
     333             :   }
     334             : 
     335             :   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
     336      838952 :   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
     337        6114 :       to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
     338      425397 :       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
     339             :       !(IsTransitionableFastElementsKind(from_kind) &&
     340        2864 :         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
     341           0 :     return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
     342             :   }
     343             : 
     344             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     345      419476 :   if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
     346             :     PropertyDetails old_details =
     347       26816 :         old_descriptors_->GetDetails(modified_descriptor_);
     348       38570 :     if (old_details.kind() != new_kind_ ||
     349       11754 :         old_details.attributes() != new_attributes_) {
     350       15062 :       return CopyGeneralizeAllFields("GenAll_RootModification1");
     351             :     }
     352       11754 :     if (old_details.location() != kField) {
     353           0 :       return CopyGeneralizeAllFields("GenAll_RootModification2");
     354             :     }
     355             :     if (new_constness_ != old_details.constness() && !FLAG_modify_map_inplace) {
     356             :       return CopyGeneralizeAllFields("GenAll_RootModification3");
     357             :     }
     358       11754 :     if (!new_representation_.fits_into(old_details.representation())) {
     359         318 :       return CopyGeneralizeAllFields("GenAll_RootModification4");
     360             :     }
     361             : 
     362             :     DCHECK_EQ(kData, old_details.kind());
     363             :     DCHECK_EQ(kData, new_kind_);
     364             :     DCHECK_EQ(kField, new_location_);
     365             :     FieldType old_field_type =
     366       34308 :         old_descriptors_->GetFieldType(modified_descriptor_);
     367       11436 :     if (!new_field_type_->NowIs(old_field_type)) {
     368         716 :       return CopyGeneralizeAllFields("GenAll_RootModification5");
     369             :     }
     370             : 
     371             :     // Modify root map in-place.
     372       10720 :     if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
     373             :       DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
     374       21440 :       GeneralizeField(old_map_, modified_descriptor_, new_constness_,
     375             :                       old_details.representation(),
     376             :                       handle(old_field_type, isolate_));
     377             :     }
     378             :   }
     379             : 
     380             :   // From here on, use the map with correct elements kind as root map.
     381      403380 :   root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind);
     382      403379 :   state_ = kAtRootMap;
     383      403379 :   return state_;  // Not done yet.
     384             : }
     385             : 
     386      403377 : MapUpdater::State MapUpdater::FindTargetMap() {
     387             :   DCHECK_EQ(kAtRootMap, state_);
     388      403377 :   target_map_ = root_map_;
     389             : 
     390             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     391     1449061 :   for (int i = root_nof; i < old_nof_; ++i) {
     392      534528 :     PropertyDetails old_details = GetDetails(i);
     393             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     394             :                          .SearchTransition(GetKey(i), old_details.kind(),
     395     1069057 :                                            old_details.attributes());
     396      534530 :     if (transition.is_null()) break;
     397      532970 :     Handle<Map> tmp_map(transition, isolate_);
     398             : 
     399             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     400      532969 :                                             isolate_);
     401             : 
     402             :     // Check if target map is incompatible.
     403      532970 :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     404             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     405             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     406     1598910 :     if (old_details.kind() == kAccessor &&
     407      549472 :         !EqualImmutableValues(GetValue(i),
     408             :                               tmp_descriptors->GetStrongValue(i))) {
     409             :       // TODO(ishell): mutable accessors are not implemented yet.
     410          40 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     411             :     }
     412             :     PropertyConstness tmp_constness = tmp_details.constness();
     413             :     if (!FLAG_modify_map_inplace &&
     414             :         !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
     415             :       break;
     416             :     }
     417      532930 :     if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
     418             :       break;
     419             :     }
     420             :     Representation tmp_representation = tmp_details.representation();
     421      532930 :     if (!old_details.representation().fits_into(tmp_representation)) {
     422             :       break;
     423             :     }
     424             : 
     425      522842 :     if (tmp_details.location() == kField) {
     426             :       Handle<FieldType> old_field_type =
     427      514631 :           GetOrComputeFieldType(i, old_details.location(), tmp_representation);
     428             :       PropertyConstness constness =
     429             :           FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
     430             :       GeneralizeField(tmp_map, i, constness, tmp_representation,
     431             :                       old_field_type);
     432             :     } else {
     433             :       // kDescriptor: Check that the value matches.
     434       16422 :       if (!EqualImmutableValues(GetValue(i),
     435             :                                 tmp_descriptors->GetStrongValue(i))) {
     436             :         break;
     437             :       }
     438             :     }
     439             :     DCHECK(!tmp_map->is_deprecated());
     440      522842 :     target_map_ = tmp_map;
     441             :   }
     442             : 
     443             :   // Directly change the map if the target map is more general.
     444             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     445      403339 :   if (target_nof == old_nof_) {
     446             : #ifdef DEBUG
     447             :     if (modified_descriptor_ >= 0) {
     448             :       DescriptorArray target_descriptors = target_map_->instance_descriptors();
     449             :       PropertyDetails details =
     450             :           target_descriptors->GetDetails(modified_descriptor_);
     451             :       DCHECK_EQ(new_kind_, details.kind());
     452             :       DCHECK_EQ(GetDetails(modified_descriptor_).attributes(),
     453             :                 details.attributes());
     454             :       DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
     455             :       DCHECK_EQ(new_location_, details.location());
     456             :       DCHECK(new_representation_.fits_into(details.representation()));
     457             :       if (new_location_ == kField) {
     458             :         DCHECK_EQ(kField, details.location());
     459             :         DCHECK(new_field_type_->NowIs(
     460             :             target_descriptors->GetFieldType(modified_descriptor_)));
     461             :       } else {
     462             :         DCHECK(details.location() == kField ||
     463             :                EqualImmutableValues(
     464             :                    *new_value_,
     465             :                    target_descriptors->GetStrongValue(modified_descriptor_)));
     466             :       }
     467             :     }
     468             : #endif
     469      391691 :     if (*target_map_ != *old_map_) {
     470      294568 :       old_map_->NotifyLeafMapLayoutChange(isolate_);
     471             :     }
     472      391691 :     if (!has_integrity_level_transition_) {
     473      391402 :       result_map_ = target_map_;
     474      391402 :       state_ = kEnd;
     475      782925 :       return state_;  // Done.
     476             :     }
     477             : 
     478             :     // We try to replay the integrity level transition here.
     479             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     480         578 :                          .SearchSpecial(*integrity_level_symbol_);
     481         289 :     if (!transition.is_null()) {
     482         242 :       result_map_ = handle(transition, isolate_);
     483         121 :       state_ = kEnd;
     484         121 :       return state_;  // Done.
     485             :     }
     486             :   }
     487             : 
     488             :   // Find the last compatible target map in the transition tree.
     489       74584 :   for (int i = target_nof; i < old_nof_; ++i) {
     490       32944 :     PropertyDetails old_details = GetDetails(i);
     491             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     492             :                          .SearchTransition(GetKey(i), old_details.kind(),
     493       65888 :                                            old_details.attributes());
     494       32944 :     if (transition.is_null()) break;
     495       31384 :     Handle<Map> tmp_map(transition, isolate_);
     496             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     497       31384 :                                             isolate_);
     498             : #ifdef DEBUG
     499             :     // Check that target map is compatible.
     500             :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     501             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     502             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     503             : #endif
     504       94152 :     if (old_details.kind() == kAccessor &&
     505       31408 :         !EqualImmutableValues(GetValue(i),
     506             :                               tmp_descriptors->GetStrongValue(i))) {
     507           0 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     508             :     }
     509             :     DCHECK(!tmp_map->is_deprecated());
     510       31384 :     target_map_ = tmp_map;
     511             :   }
     512             : 
     513       11816 :   state_ = kAtTargetMap;
     514       11816 :   return state_;  // Not done yet.
     515             : }
     516             : 
     517       11816 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
     518             :   InstanceType instance_type = old_map_->instance_type();
     519             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     520             :   Handle<DescriptorArray> target_descriptors(
     521       11816 :       target_map_->instance_descriptors(), isolate_);
     522             : 
     523             :   // Allocate a new descriptor array large enough to hold the required
     524             :   // descriptors, with minimally the exact same size as the old descriptor
     525             :   // array.
     526             :   int new_slack =
     527       35448 :       std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
     528       11816 :       old_nof_;
     529             :   Handle<DescriptorArray> new_descriptors =
     530       11816 :       DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
     531             :   DCHECK(new_descriptors->number_of_all_descriptors() >
     532             :              target_descriptors->number_of_all_descriptors() ||
     533             :          new_descriptors->number_of_slack_descriptors() > 0 ||
     534             :          new_descriptors->number_of_descriptors() ==
     535             :              old_descriptors_->number_of_descriptors());
     536             :   DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
     537             : 
     538             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     539             : 
     540             :   // Given that we passed root modification check in FindRootMap() so
     541             :   // the root descriptors are either not modified at all or already more
     542             :   // general than we requested. Take |root_nof| entries as is.
     543             :   // 0 -> |root_nof|
     544             :   int current_offset = 0;
     545       14418 :   for (int i = 0; i < root_nof; ++i) {
     546        1301 :     PropertyDetails old_details = old_descriptors_->GetDetails(i);
     547        1301 :     if (old_details.location() == kField) {
     548         350 :       current_offset += old_details.field_width_in_words();
     549             :     }
     550             :     Descriptor d(handle(GetKey(i), isolate_),
     551             :                  MaybeObjectHandle(old_descriptors_->GetValue(i), isolate_),
     552        3903 :                  old_details);
     553        1301 :     new_descriptors->Set(i, &d);
     554             :   }
     555             : 
     556             :   // Merge "updated" old_descriptor entries with target_descriptor entries.
     557             :   // |root_nof| -> |target_nof|
     558      142028 :   for (int i = root_nof; i < target_nof; ++i) {
     559       65106 :     Handle<Name> key(GetKey(i), isolate_);
     560       65106 :     PropertyDetails old_details = GetDetails(i);
     561       65106 :     PropertyDetails target_details = target_descriptors->GetDetails(i);
     562             : 
     563             :     PropertyKind next_kind = old_details.kind();
     564             :     PropertyAttributes next_attributes = old_details.attributes();
     565             :     DCHECK_EQ(next_kind, target_details.kind());
     566             :     DCHECK_EQ(next_attributes, target_details.attributes());
     567             : 
     568             :     PropertyConstness next_constness = GeneralizeConstness(
     569       65106 :         old_details.constness(), target_details.constness());
     570             : 
     571             :     // Note: failed values equality check does not invalidate per-object
     572             :     // property constness.
     573             :     PropertyLocation next_location =
     574          46 :         old_details.location() == kField ||
     575             :                 target_details.location() == kField ||
     576       65244 :                 !EqualImmutableValues(target_descriptors->GetStrongValue(i),
     577             :                                       GetValue(i))
     578             :             ? kField
     579      130212 :             : kDescriptor;
     580             : 
     581             :     if (!FLAG_track_constant_fields && next_location == kField) {
     582             :       next_constness = PropertyConstness::kMutable;
     583             :     }
     584             :     // Ensure that mutable values are stored in fields.
     585             :     DCHECK_IMPLIES(next_constness == PropertyConstness::kMutable,
     586             :                    next_location == kField);
     587             : 
     588             :     Representation next_representation =
     589      130212 :         old_details.representation().generalize(
     590       65106 :             target_details.representation());
     591             : 
     592       65106 :     if (next_location == kField) {
     593             :       Handle<FieldType> old_field_type =
     594       65060 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     595             : 
     596             :       Handle<FieldType> target_field_type =
     597             :           GetOrComputeFieldType(target_descriptors, i,
     598       65060 :                                 target_details.location(), next_representation);
     599             : 
     600             :       Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
     601             :           old_details.representation(), old_field_type, next_representation,
     602       65060 :           target_field_type, isolate_);
     603             : 
     604       65060 :       Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
     605             :           isolate_, instance_type, &next_constness, &next_representation,
     606       65060 :           &next_field_type);
     607             : 
     608             :       MaybeObjectHandle wrapped_type(
     609       65060 :           Map::WrapFieldType(isolate_, next_field_type));
     610       65060 :       Descriptor d;
     611       65060 :       if (next_kind == kData) {
     612      130120 :         d = Descriptor::DataField(key, current_offset, next_attributes,
     613             :                                   next_constness, next_representation,
     614      130120 :                                   wrapped_type);
     615             :       } else {
     616             :         // TODO(ishell): mutable accessors are not implemented yet.
     617           0 :         UNIMPLEMENTED();
     618             :       }
     619       65060 :       current_offset += d.GetDetails().field_width_in_words();
     620       65060 :       new_descriptors->Set(i, &d);
     621             :     } else {
     622             :       DCHECK_EQ(kDescriptor, next_location);
     623             :       DCHECK_EQ(PropertyConstness::kConst, next_constness);
     624             : 
     625          46 :       Handle<Object> value(GetValue(i), isolate_);
     626          46 :       Descriptor d;
     627          46 :       if (next_kind == kData) {
     628             :         DCHECK(!FLAG_track_constant_fields);
     629           0 :         d = Descriptor::DataConstant(key, value, next_attributes);
     630             :       } else {
     631             :         DCHECK_EQ(kAccessor, next_kind);
     632          46 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     633             :       }
     634          46 :       new_descriptors->Set(i, &d);
     635             :     }
     636             :   }
     637             : 
     638             :   // Take "updated" old_descriptor entries.
     639             :   // |target_nof| -> |old_nof|
     640       16466 :   for (int i = target_nof; i < old_nof_; ++i) {
     641        2325 :     PropertyDetails old_details = GetDetails(i);
     642        2325 :     Handle<Name> key(GetKey(i), isolate_);
     643             : 
     644             :     PropertyKind next_kind = old_details.kind();
     645             :     PropertyAttributes next_attributes = old_details.attributes();
     646             :     PropertyConstness next_constness = old_details.constness();
     647             :     PropertyLocation next_location = old_details.location();
     648             :     Representation next_representation = old_details.representation();
     649             : 
     650        2325 :     Descriptor d;
     651        2325 :     if (next_location == kField) {
     652             :       Handle<FieldType> next_field_type =
     653        2249 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     654             : 
     655             :       // If the |new_elements_kind_| is still transitionable then the old map's
     656             :       // elements kind is also transitionable and therefore the old descriptors
     657             :       // array must already have generalized field type.
     658        2648 :       CHECK_IMPLIES(
     659             :           is_transitionable_fast_elements_kind_,
     660             :           Map::IsMostGeneralFieldType(next_representation, *next_field_type));
     661             : 
     662             :       MaybeObjectHandle wrapped_type(
     663        2249 :           Map::WrapFieldType(isolate_, next_field_type));
     664        2249 :       Descriptor d;
     665        2249 :       if (next_kind == kData) {
     666             :         DCHECK_IMPLIES(!FLAG_track_constant_fields,
     667             :                        next_constness == PropertyConstness::kMutable);
     668        4498 :         d = Descriptor::DataField(key, current_offset, next_attributes,
     669             :                                   next_constness, next_representation,
     670        2249 :                                   wrapped_type);
     671             :       } else {
     672             :         // TODO(ishell): mutable accessors are not implemented yet.
     673           0 :         UNIMPLEMENTED();
     674             :       }
     675        2249 :       current_offset += d.GetDetails().field_width_in_words();
     676        2249 :       new_descriptors->Set(i, &d);
     677             :     } else {
     678             :       DCHECK_EQ(kDescriptor, next_location);
     679             :       DCHECK_EQ(PropertyConstness::kConst, next_constness);
     680             : 
     681          76 :       Handle<Object> value(GetValue(i), isolate_);
     682          76 :       if (next_kind == kData) {
     683           0 :         d = Descriptor::DataConstant(key, value, next_attributes);
     684             :       } else {
     685             :         DCHECK_EQ(kAccessor, next_kind);
     686          76 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     687             :       }
     688          76 :       new_descriptors->Set(i, &d);
     689             :     }
     690             :   }
     691             : 
     692       11816 :   new_descriptors->Sort();
     693       11816 :   return new_descriptors;
     694             : }
     695             : 
     696       11816 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
     697             :   DisallowHeapAllocation no_allocation;
     698             : 
     699             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     700             :   Map current = *root_map_;
     701       79260 :   for (int i = root_nof; i < old_nof_; i++) {
     702       45370 :     Name name = descriptors->GetKey(i);
     703       45370 :     PropertyDetails details = descriptors->GetDetails(i);
     704             :     Map next =
     705             :         TransitionsAccessor(isolate_, current, &no_allocation)
     706       90740 :             .SearchTransition(name, details.kind(), details.attributes());
     707       45370 :     if (next.is_null()) break;
     708       43810 :     DescriptorArray next_descriptors = next->instance_descriptors();
     709             : 
     710       43810 :     PropertyDetails next_details = next_descriptors->GetDetails(i);
     711             :     DCHECK_EQ(details.kind(), next_details.kind());
     712             :     DCHECK_EQ(details.attributes(), next_details.attributes());
     713       43810 :     if (details.constness() != next_details.constness()) break;
     714       41773 :     if (details.location() != next_details.location()) break;
     715       41773 :     if (!details.representation().Equals(next_details.representation())) break;
     716             : 
     717       33722 :     if (next_details.location() == kField) {
     718       33688 :       FieldType next_field_type = next_descriptors->GetFieldType(i);
     719       67376 :       if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
     720             :         break;
     721             :       }
     722             :     } else {
     723         102 :       if (!EqualImmutableValues(descriptors->GetStrongValue(i),
     724             :                                 next_descriptors->GetStrongValue(i))) {
     725             :         break;
     726             :       }
     727             :     }
     728             :     current = next;
     729             :   }
     730       23632 :   return handle(current, isolate_);
     731             : }
     732             : 
     733       11816 : MapUpdater::State MapUpdater::ConstructNewMap() {
     734       11816 :   Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
     735             : 
     736       11816 :   Handle<Map> split_map = FindSplitMap(new_descriptors);
     737             :   int split_nof = split_map->NumberOfOwnDescriptors();
     738       11816 :   if (old_nof_ == split_nof) {
     739         168 :     CHECK(has_integrity_level_transition_);
     740         168 :     state_ = kAtIntegrityLevelSource;
     741         168 :     return state_;
     742             :   }
     743             : 
     744       11648 :   PropertyDetails split_details = GetDetails(split_nof);
     745       11648 :   TransitionsAccessor transitions(isolate_, split_map);
     746             : 
     747             :   // Invalidate a transition target at |key|.
     748             :   Map maybe_transition = transitions.SearchTransition(
     749       11648 :       GetKey(split_nof), split_details.kind(), split_details.attributes());
     750       11648 :   if (!maybe_transition.is_null()) {
     751       10088 :     maybe_transition->DeprecateTransitionTree(isolate_);
     752             :   }
     753             : 
     754             :   // If |maybe_transition| is not nullptr then the transition array already
     755             :   // contains entry for given descriptor. This means that the transition
     756             :   // could be inserted regardless of whether transitions array is full or not.
     757       11648 :   if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
     758           4 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     759             :   }
     760             : 
     761       23288 :   old_map_->NotifyLeafMapLayoutChange(isolate_);
     762             : 
     763       11644 :   if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
     764             :     PropertyDetails old_details =
     765           0 :         old_descriptors_->GetDetails(modified_descriptor_);
     766             :     PropertyDetails new_details =
     767           0 :         new_descriptors->GetDetails(modified_descriptor_);
     768           0 :     MaybeHandle<FieldType> old_field_type;
     769           0 :     MaybeHandle<FieldType> new_field_type;
     770           0 :     MaybeHandle<Object> old_value;
     771           0 :     MaybeHandle<Object> new_value;
     772           0 :     if (old_details.location() == kField) {
     773             :       old_field_type = handle(
     774           0 :           old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
     775             :     } else {
     776             :       old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_),
     777           0 :                          isolate_);
     778             :     }
     779           0 :     if (new_details.location() == kField) {
     780             :       new_field_type =
     781           0 :           handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
     782             :     } else {
     783             :       new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_),
     784           0 :                          isolate_);
     785             :     }
     786             : 
     787           0 :     old_map_->PrintGeneralization(
     788             :         isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_,
     789           0 :         old_details.location() == kDescriptor && new_location_ == kField,
     790             :         old_details.representation(), new_details.representation(),
     791           0 :         old_field_type, old_value, new_field_type, new_value);
     792             :   }
     793             : 
     794             :   Handle<LayoutDescriptor> new_layout_descriptor =
     795       11644 :       LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_);
     796             : 
     797             :   Handle<Map> new_map = Map::AddMissingTransitions(
     798       11644 :       isolate_, split_map, new_descriptors, new_layout_descriptor);
     799             : 
     800             :   // Deprecated part of the transition tree is no longer reachable, so replace
     801             :   // current instance descriptors in the "survived" part of the tree with
     802             :   // the new descriptors to maintain descriptors sharing invariant.
     803       34932 :   split_map->ReplaceDescriptors(isolate_, *new_descriptors,
     804       11644 :                                 *new_layout_descriptor);
     805             : 
     806       11644 :   if (has_integrity_level_transition_) {
     807          85 :     target_map_ = new_map;
     808          85 :     state_ = kAtIntegrityLevelSource;
     809             :   } else {
     810       11559 :     result_map_ = new_map;
     811       11559 :     state_ = kEnd;
     812             :   }
     813       11644 :   return state_;  // Done.
     814             : }
     815             : 
     816         253 : MapUpdater::State MapUpdater::ConstructNewMapWithIntegrityLevelTransition() {
     817             :   DCHECK_EQ(kAtIntegrityLevelSource, state_);
     818             : 
     819         253 :   TransitionsAccessor transitions(isolate_, target_map_);
     820         253 :   if (!transitions.CanHaveMoreTransitions()) {
     821           0 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     822             :   }
     823             : 
     824             :   result_map_ = Map::CopyForPreventExtensions(
     825             :       isolate_, target_map_, integrity_level_, integrity_level_symbol_,
     826         253 :       "CopyForPreventExtensions");
     827             : 
     828         253 :   state_ = kEnd;
     829         253 :   return state_;
     830             : }
     831             : 
     832             : }  // namespace internal
     833      120216 : }  // namespace v8

Generated by: LCOV version 1.10