LCOV - code coverage report
Current view: top level - src - map-updater.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 232 258 89.9 %
Date: 2019-01-20 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/transitions.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : namespace {
      18             : 
      19             : inline bool EqualImmutableValues(Object obj1, Object obj2) {
      20        3941 :   if (obj1 == obj2) return true;  // Valid for both kData and kAccessor kinds.
      21             :   // TODO(ishell): compare AccessorPairs.
      22             :   return false;
      23             : }
      24             : 
      25             : }  // namespace
      26             : 
      27      576125 : MapUpdater::MapUpdater(Isolate* isolate, Handle<Map> old_map)
      28             :     : isolate_(isolate),
      29             :       old_map_(old_map),
      30             :       old_descriptors_(old_map->instance_descriptors(), isolate_),
      31             :       old_nof_(old_map_->NumberOfOwnDescriptors()),
      32             :       new_elements_kind_(old_map_->elements_kind()),
      33             :       is_transitionable_fast_elements_kind_(
      34     3456770 :           IsTransitionableFastElementsKind(new_elements_kind_)) {
      35             :   // We shouldn't try to update remote objects.
      36             :   DCHECK(!old_map->FindRootMap(isolate)
      37             :               ->GetConstructor()
      38             :               ->IsFunctionTemplateInfo());
      39             : }
      40             : 
      41      384387 : Name MapUpdater::GetKey(int descriptor) const {
      42      384387 :   return old_descriptors_->GetKey(descriptor);
      43             : }
      44             : 
      45      382534 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
      46             :   DCHECK_LE(0, descriptor);
      47      382534 :   if (descriptor == modified_descriptor_) {
      48             :     return PropertyDetails(new_kind_, new_attributes_, new_location_,
      49      278208 :                            new_constness_, new_representation_);
      50             :   }
      51      243431 :   return old_descriptors_->GetDetails(descriptor);
      52             : }
      53             : 
      54        5577 : Object MapUpdater::GetValue(int descriptor) const {
      55             :   DCHECK_LE(0, descriptor);
      56        5577 :   if (descriptor == modified_descriptor_) {
      57             :     DCHECK_EQ(kDescriptor, new_location_);
      58             :     return *new_value_;
      59             :   }
      60             :   DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
      61        5577 :   return old_descriptors_->GetStrongValue(descriptor);
      62             : }
      63             : 
      64      293201 : FieldType MapUpdater::GetFieldType(int descriptor) const {
      65             :   DCHECK_LE(0, descriptor);
      66      293201 :   if (descriptor == modified_descriptor_) {
      67             :     DCHECK_EQ(kField, new_location_);
      68             :     return *new_field_type_;
      69             :   }
      70             :   DCHECK_EQ(kField, GetDetails(descriptor).location());
      71      213142 :   return old_descriptors_->GetFieldType(descriptor);
      72             : }
      73             : 
      74      293553 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      75             :     int descriptor, PropertyLocation location,
      76             :     Representation representation) const {
      77             :   DCHECK_LE(0, descriptor);
      78             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      79             :   DCHECK_EQ(location, GetDetails(descriptor).location());
      80      293553 :   if (location == kField) {
      81      293201 :     return handle(GetFieldType(descriptor), isolate_);
      82             :   } else {
      83         352 :     return GetValue(descriptor)->OptimalType(isolate_, representation);
      84             :   }
      85             : }
      86             : 
      87      347147 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      88             :     Handle<DescriptorArray> descriptors, int descriptor,
      89             :     PropertyLocation location, Representation representation) {
      90             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      91             :   DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
      92      347147 :   if (location == kField) {
      93      972158 :     return handle(descriptors->GetFieldType(descriptor), isolate_);
      94             :   } else {
      95       46194 :     return descriptors->GetStrongValue(descriptor)
      96       46194 :         ->OptimalType(isolate_, representation);
      97             :   }
      98             : }
      99             : 
     100      278479 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
     101             :                                                PropertyAttributes attributes,
     102             :                                                PropertyConstness constness,
     103             :                                                Representation representation,
     104             :                                                Handle<FieldType> field_type) {
     105             :   DCHECK_EQ(kInitialized, state_);
     106             :   DCHECK_LE(0, descriptor);
     107             :   DCHECK(!old_map_->is_dictionary_map());
     108      278479 :   modified_descriptor_ = descriptor;
     109      278479 :   new_kind_ = kData;
     110      278479 :   new_attributes_ = attributes;
     111      278479 :   new_location_ = kField;
     112             : 
     113             :   PropertyDetails old_details =
     114      278479 :       old_descriptors_->GetDetails(modified_descriptor_);
     115             : 
     116             :   // If property kind is not reconfigured merge the result with
     117             :   // representation/field type from the old descriptor.
     118      278480 :   if (old_details.kind() == new_kind_) {
     119      264602 :     new_constness_ = GeneralizeConstness(constness, old_details.constness());
     120             : 
     121      264602 :     Representation old_representation = old_details.representation();
     122      264602 :     new_representation_ = representation.generalize(old_representation);
     123             : 
     124             :     Handle<FieldType> old_field_type =
     125             :         GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
     126      264602 :                               old_details.location(), new_representation_);
     127             : 
     128             :     new_field_type_ =
     129             :         Map::GeneralizeFieldType(old_representation, old_field_type,
     130      264608 :                                  new_representation_, field_type, isolate_);
     131             :   } else {
     132             :     // We don't know if this is a first property kind reconfiguration
     133             :     // and we don't know which value was in this property previously
     134             :     // therefore we can't treat such a property as constant.
     135       13878 :     new_constness_ = PropertyConstness::kMutable;
     136       13878 :     new_representation_ = representation;
     137       13878 :     new_field_type_ = field_type;
     138             :   }
     139             : 
     140             :   Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
     141             :       isolate_, old_map_->instance_type(), &new_constness_,
     142      556978 :       &new_representation_, &new_field_type_);
     143             : 
     144      278484 :   if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
     145       99868 :   if (FindRootMap() == kEnd) return result_map_;
     146       80006 :   if (FindTargetMap() == kEnd) return result_map_;
     147       19763 :   ConstructNewMap();
     148             :   DCHECK_EQ(kEnd, state_);
     149       19763 :   return result_map_;
     150             : }
     151             : 
     152      294665 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
     153             :   DCHECK_EQ(kInitialized, state_);
     154      294665 :   new_elements_kind_ = elements_kind;
     155             :   is_transitionable_fast_elements_kind_ =
     156      294665 :       IsTransitionableFastElementsKind(new_elements_kind_);
     157             : 
     158      294665 :   if (FindRootMap() == kEnd) return result_map_;
     159      294665 :   if (FindTargetMap() == kEnd) return result_map_;
     160         808 :   ConstructNewMap();
     161             :   DCHECK_EQ(kEnd, state_);
     162         808 :   return result_map_;
     163             : }
     164             : 
     165        2981 : Handle<Map> MapUpdater::Update() {
     166             :   DCHECK_EQ(kInitialized, state_);
     167             :   DCHECK(old_map_->is_deprecated());
     168             : 
     169        2981 :   if (FindRootMap() == kEnd) return result_map_;
     170        2911 :   if (FindTargetMap() == kEnd) return result_map_;
     171         160 :   ConstructNewMap();
     172             :   DCHECK_EQ(kEnd, state_);
     173             :   if (FLAG_fast_map_update) {
     174             :     TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
     175             :   }
     176         160 :   return result_map_;
     177             : }
     178             : 
     179           0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
     180             :                                  PropertyConstness new_constness,
     181             :                                  Representation new_representation,
     182             :                                  Handle<FieldType> new_field_type) {
     183             :   Map::GeneralizeField(isolate_, map, modify_index, new_constness,
     184      387441 :                        new_representation, new_field_type);
     185             : 
     186             :   DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
     187           0 : }
     188             : 
     189       19949 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
     190             :   result_map_ = Map::CopyGeneralizeAllFields(
     191             :       isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
     192       19949 :       new_attributes_, reason);
     193       19949 :   state_ = kEnd;
     194       19949 :   return state_;  // Done.
     195             : }
     196             : 
     197      278484 : MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
     198             :   // If it's just a representation generalization case (i.e. property kind and
     199             :   // attributes stays unchanged) it's fine to transition from None to anything
     200             :   // but double without any modification to the object, because the default
     201             :   // uninitialized value for representation None can be overwritten by both
     202             :   // smi and tagged values. Doubles, however, would require a box allocation.
     203      278484 :   if (new_representation_.IsNone() || new_representation_.IsDouble()) {
     204       28917 :     return state_;  // Not done yet.
     205             :   }
     206             : 
     207             :   PropertyDetails old_details =
     208      499133 :       old_descriptors_->GetDetails(modified_descriptor_);
     209             :   Representation old_representation = old_details.representation();
     210      249568 :   if (!old_representation.IsNone()) {
     211       70951 :     return state_;  // Not done yet.
     212             :   }
     213             : 
     214             :   DCHECK_EQ(new_kind_, old_details.kind());
     215             :   DCHECK_EQ(new_attributes_, old_details.attributes());
     216             :   DCHECK_EQ(kField, old_details.location());
     217      178617 :   if (FLAG_trace_generalization) {
     218             :     old_map_->PrintGeneralization(
     219             :         isolate_, stdout, "uninitialized field", modified_descriptor_, old_nof_,
     220             :         old_nof_, false, old_representation, new_representation_,
     221             :         handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
     222           0 :         MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
     223             :   }
     224             :   Handle<Map> field_owner(
     225      535850 :       old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_);
     226             : 
     227             :   GeneralizeField(field_owner, modified_descriptor_, new_constness_,
     228      178617 :                   new_representation_, new_field_type_);
     229             :   // Check that the descriptor array was updated.
     230             :   DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
     231             :              .representation()
     232             :              .Equals(new_representation_));
     233             :   DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
     234             :              ->NowIs(new_field_type_));
     235             : 
     236      178615 :   result_map_ = old_map_;
     237      178615 :   state_ = kEnd;
     238      178615 :   return state_;  // Done.
     239             : }
     240             : 
     241      397513 : MapUpdater::State MapUpdater::FindRootMap() {
     242             :   DCHECK_EQ(kInitialized, state_);
     243             :   // Check the state of the root map.
     244     1192537 :   root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
     245             :   ElementsKind from_kind = root_map_->elements_kind();
     246      397512 :   ElementsKind to_kind = new_elements_kind_;
     247      397513 :   if (root_map_->is_deprecated()) {
     248           0 :     state_ = kEnd;
     249             :     result_map_ = handle(
     250           0 :         JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
     251           0 :     result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind);
     252             :     DCHECK(result_map_->is_dictionary_map());
     253           0 :     return state_;
     254             :   }
     255             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     256      397511 :   if (!old_map_->EquivalentToForTransition(*root_map_)) {
     257          93 :     return CopyGeneralizeAllFields("GenAll_NotEquivalent");
     258             :   }
     259             : 
     260             :   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
     261      794842 :   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
     262       10986 :       to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
     263      408213 :       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
     264             :       !(IsTransitionableFastElementsKind(from_kind) &&
     265        5299 :         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
     266           0 :     return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
     267             :   }
     268             : 
     269      397421 :   if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
     270             :     PropertyDetails old_details =
     271       19837 :         old_descriptors_->GetDetails(modified_descriptor_);
     272       25875 :     if (old_details.kind() != new_kind_ ||
     273        6038 :         old_details.attributes() != new_attributes_) {
     274       33636 :       return CopyGeneralizeAllFields("GenAll_RootModification1");
     275             :     }
     276        6038 :     if (old_details.location() != kField) {
     277        5255 :       return CopyGeneralizeAllFields("GenAll_RootModification2");
     278             :     }
     279        1566 :     if (new_constness_ != old_details.constness() &&
     280             :         (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
     281           0 :       return CopyGeneralizeAllFields("GenAll_RootModification3");
     282             :     }
     283        1566 :     if (!new_representation_.fits_into(old_details.representation())) {
     284          36 :       return CopyGeneralizeAllFields("GenAll_RootModification4");
     285             :     }
     286             : 
     287             :     DCHECK_EQ(kData, old_details.kind());
     288             :     DCHECK_EQ(kData, new_kind_);
     289             :     DCHECK_EQ(kField, new_location_);
     290             :     FieldType old_field_type =
     291        1494 :         old_descriptors_->GetFieldType(modified_descriptor_);
     292         747 :     if (!new_field_type_->NowIs(old_field_type)) {
     293         747 :       return CopyGeneralizeAllFields("GenAll_RootModification5");
     294             :     }
     295             : 
     296             :     // Modify root map in-place.
     297             :     if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
     298             :       // Only prototype root maps are allowed to be updated in-place.
     299             :       // TODO(ishell): fix all the stubs that use prototype map check to
     300             :       // ensure that the prototype was not modified.
     301             :       DCHECK(old_map_->is_prototype_map());
     302             :       DCHECK(old_map_->is_stable());
     303             :       DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
     304             :       GeneralizeField(old_map_, modified_descriptor_, new_constness_,
     305             :                       old_details.representation(),
     306             :                       handle(old_field_type, isolate_));
     307             :     }
     308             :   }
     309             : 
     310             :   // From here on, use the map with correct elements kind as root map.
     311      377584 :   root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind);
     312      377581 :   state_ = kAtRootMap;
     313      377581 :   return state_;  // Not done yet.
     314             : }
     315             : 
     316      377581 : MapUpdater::State MapUpdater::FindTargetMap() {
     317             :   DCHECK_EQ(kAtRootMap, state_);
     318      377581 :   target_map_ = root_map_;
     319             : 
     320             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     321      587395 :   for (int i = root_nof; i < old_nof_; ++i) {
     322      230554 :     PropertyDetails old_details = GetDetails(i);
     323             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     324             :                          .SearchTransition(GetKey(i), old_details.kind(),
     325      230554 :                                            old_details.attributes());
     326      230558 :     if (transition.is_null()) break;
     327      228978 :     Handle<Map> tmp_map(transition, isolate_);
     328             : 
     329             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     330      686927 :                                             isolate_);
     331             : 
     332             :     // Check if target map is incompatible.
     333      228976 :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     334             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     335             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     336      686934 :     if (old_details.kind() == kAccessor &&
     337             :         !EqualImmutableValues(GetValue(i),
     338      229234 :                               tmp_descriptors->GetStrongValue(i))) {
     339             :       // TODO(ishell): mutable accessors are not implemented yet.
     340          14 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     341             :     }
     342             :     PropertyConstness tmp_constness = tmp_details.constness();
     343      228964 :     if (!FLAG_modify_map_inplace &&
     344             :         !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
     345             :       break;
     346             :     }
     347      220063 :     if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
     348             :       break;
     349             :     }
     350      220048 :     Representation tmp_representation = tmp_details.representation();
     351      440096 :     if (!old_details.representation().fits_into(tmp_representation)) {
     352             :       break;
     353             :     }
     354             : 
     355      209832 :     if (tmp_details.location() == kField) {
     356             :       Handle<FieldType> old_field_type =
     357      208827 :           GetOrComputeFieldType(i, old_details.location(), tmp_representation);
     358             :       PropertyConstness constness =
     359             :           FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
     360             :       GeneralizeField(tmp_map, i, constness, tmp_representation,
     361             :                       old_field_type);
     362             :     } else {
     363             :       // kDescriptor: Check that the value matches.
     364        1005 :       if (!EqualImmutableValues(GetValue(i),
     365        2010 :                                 tmp_descriptors->GetStrongValue(i))) {
     366             :         break;
     367             :       }
     368             :     }
     369             :     DCHECK(!tmp_map->is_deprecated());
     370      209812 :     target_map_ = tmp_map;
     371             :   }
     372             : 
     373             :   // Directly change the map if the target map is more general.
     374             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     375      377568 :   if (target_nof == old_nof_) {
     376             : #ifdef DEBUG
     377             :     if (modified_descriptor_ >= 0) {
     378             :       DescriptorArray target_descriptors = target_map_->instance_descriptors();
     379             :       PropertyDetails details =
     380             :           target_descriptors->GetDetails(modified_descriptor_);
     381             :       DCHECK_EQ(new_kind_, details.kind());
     382             :       DCHECK_EQ(new_attributes_, details.attributes());
     383             :       DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
     384             :       DCHECK_EQ(new_location_, details.location());
     385             :       DCHECK(new_representation_.fits_into(details.representation()));
     386             :       if (new_location_ == kField) {
     387             :         DCHECK_EQ(kField, details.location());
     388             :         DCHECK(new_field_type_->NowIs(
     389             :             target_descriptors->GetFieldType(modified_descriptor_)));
     390             :       } else {
     391             :         DCHECK(details.location() == kField ||
     392             :                EqualImmutableValues(
     393             :                    *new_value_,
     394             :                    target_descriptors->GetStrongValue(modified_descriptor_)));
     395             :       }
     396             :     }
     397             : #endif
     398      356837 :     if (*target_map_ != *old_map_) {
     399      594564 :       old_map_->NotifyLeafMapLayoutChange(isolate_);
     400             :     }
     401      356837 :     result_map_ = target_map_;
     402      356837 :     state_ = kEnd;
     403      356837 :     return state_;  // Done.
     404             :   }
     405             : 
     406             :   // Find the last compatible target map in the transition tree.
     407       42806 :   for (int i = target_nof; i < old_nof_; ++i) {
     408       44387 :     PropertyDetails old_details = GetDetails(i);
     409             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     410             :                          .SearchTransition(GetKey(i), old_details.kind(),
     411       44387 :                                            old_details.attributes());
     412       44387 :     if (transition.is_null()) break;
     413       42806 :     Handle<Map> tmp_map(transition, isolate_);
     414             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     415      128418 :                                             isolate_);
     416             : #ifdef DEBUG
     417             :     // Check that target map is compatible.
     418             :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     419             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     420             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     421             : #endif
     422      128418 :     if (old_details.kind() == kAccessor &&
     423             :         !EqualImmutableValues(GetValue(i),
     424       42836 :                               tmp_descriptors->GetStrongValue(i))) {
     425           0 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     426             :     }
     427             :     DCHECK(!tmp_map->is_deprecated());
     428       42806 :     target_map_ = tmp_map;
     429             :   }
     430             : 
     431       20731 :   state_ = kAtTargetMap;
     432       20731 :   return state_;  // Not done yet.
     433             : }
     434             : 
     435       20731 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
     436             :   InstanceType instance_type = old_map_->instance_type();
     437             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     438             :   Handle<DescriptorArray> target_descriptors(
     439       62193 :       target_map_->instance_descriptors(), isolate_);
     440             : 
     441             :   // Allocate a new descriptor array large enough to hold the required
     442             :   // descriptors, with minimally the exact same size as the old descriptor
     443             :   // array.
     444             :   int new_slack =
     445       62193 :       std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
     446       20731 :       old_nof_;
     447             :   Handle<DescriptorArray> new_descriptors =
     448       20731 :       DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
     449             :   DCHECK(new_descriptors->number_of_all_descriptors() >
     450             :              target_descriptors->number_of_all_descriptors() ||
     451             :          new_descriptors->number_of_slack_descriptors() > 0 ||
     452             :          new_descriptors->number_of_descriptors() ==
     453             :              old_descriptors_->number_of_descriptors());
     454             :   DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
     455             : 
     456             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     457             : 
     458             :   // Given that we passed root modification check in FindRootMap() so
     459             :   // the root descriptors are either not modified at all or already more
     460             :   // general than we requested. Take |root_nof| entries as is.
     461             :   // 0 -> |root_nof|
     462             :   int current_offset = 0;
     463       22585 :   for (int i = 0; i < root_nof; ++i) {
     464        1854 :     PropertyDetails old_details = old_descriptors_->GetDetails(i);
     465        1854 :     if (old_details.location() == kField) {
     466         163 :       current_offset += old_details.field_width_in_words();
     467             :     }
     468             :     Descriptor d(handle(GetKey(i), isolate_),
     469             :                  MaybeObjectHandle(old_descriptors_->GetValue(i), isolate_),
     470        7416 :                  old_details);
     471        1854 :     new_descriptors->Set(i, &d);
     472             :   }
     473             : 
     474             :   // Merge "updated" old_descriptor entries with target_descriptor entries.
     475             :   // |root_nof| -> |target_nof|
     476       84470 :   for (int i = root_nof; i < target_nof; ++i) {
     477       84470 :     Handle<Name> key(GetKey(i), isolate_);
     478       84470 :     PropertyDetails old_details = GetDetails(i);
     479       84470 :     PropertyDetails target_details = target_descriptors->GetDetails(i);
     480             : 
     481             :     PropertyKind next_kind = old_details.kind();
     482             :     PropertyAttributes next_attributes = old_details.attributes();
     483             :     DCHECK_EQ(next_kind, target_details.kind());
     484             :     DCHECK_EQ(next_attributes, target_details.attributes());
     485             : 
     486             :     PropertyConstness next_constness = GeneralizeConstness(
     487             :         old_details.constness(), target_details.constness());
     488             : 
     489             :     // Note: failed values equality check does not invalidate per-object
     490             :     // property constness.
     491             :     PropertyLocation next_location =
     492        1951 :         old_details.location() == kField ||
     493             :                 target_details.location() == kField ||
     494             :                 !EqualImmutableValues(target_descriptors->GetStrongValue(i),
     495       90296 :                                       GetValue(i))
     496             :             ? kField
     497      168940 :             : kDescriptor;
     498             : 
     499       84470 :     if (!FLAG_track_constant_fields && next_location == kField) {
     500             :       next_constness = PropertyConstness::kMutable;
     501             :     }
     502             :     // Ensure that mutable values are stored in fields.
     503             :     DCHECK_IMPLIES(next_constness == PropertyConstness::kMutable,
     504             :                    next_location == kField);
     505             : 
     506             :     Representation next_representation =
     507             :         old_details.representation().generalize(
     508       84470 :             target_details.representation());
     509             : 
     510       84470 :     if (next_location == kField) {
     511             :       Handle<FieldType> old_field_type =
     512       82547 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     513             : 
     514             :       Handle<FieldType> target_field_type =
     515             :           GetOrComputeFieldType(target_descriptors, i,
     516       82547 :                                 target_details.location(), next_representation);
     517             : 
     518             :       Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
     519             :           old_details.representation(), old_field_type, next_representation,
     520       82547 :           target_field_type, isolate_);
     521             : 
     522             :       Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
     523             :           isolate_, instance_type, &next_constness, &next_representation,
     524       82547 :           &next_field_type);
     525             : 
     526             :       MaybeObjectHandle wrapped_type(
     527       82547 :           Map::WrapFieldType(isolate_, next_field_type));
     528       82547 :       Descriptor d;
     529       82547 :       if (next_kind == kData) {
     530             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     531             :                                   next_constness, next_representation,
     532       82547 :                                   wrapped_type);
     533             :       } else {
     534             :         // TODO(ishell): mutable accessors are not implemented yet.
     535           0 :         UNIMPLEMENTED();
     536             :       }
     537       82547 :       current_offset += d.GetDetails().field_width_in_words();
     538       82547 :       new_descriptors->Set(i, &d);
     539             :     } else {
     540             :       DCHECK_EQ(kDescriptor, next_location);
     541             :       DCHECK_EQ(PropertyConstness::kConst, next_constness);
     542             : 
     543        1923 :       Handle<Object> value(GetValue(i), isolate_);
     544        1923 :       Descriptor d;
     545        1923 :       if (next_kind == kData) {
     546             :         DCHECK(!FLAG_track_constant_fields);
     547        1861 :         d = Descriptor::DataConstant(key, value, next_attributes);
     548             :       } else {
     549             :         DCHECK_EQ(kAccessor, next_kind);
     550          62 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     551             :       }
     552        1923 :       new_descriptors->Set(i, &d);
     553             :     }
     554             :   }
     555             : 
     556             :   // Take "updated" old_descriptor entries.
     557             :   // |target_nof| -> |old_nof|
     558        2391 :   for (int i = target_nof; i < old_nof_; ++i) {
     559        2391 :     PropertyDetails old_details = GetDetails(i);
     560        2391 :     Handle<Name> key(GetKey(i), isolate_);
     561             : 
     562             :     PropertyKind next_kind = old_details.kind();
     563             :     PropertyAttributes next_attributes = old_details.attributes();
     564             :     PropertyConstness next_constness = old_details.constness();
     565             :     PropertyLocation next_location = old_details.location();
     566             :     Representation next_representation = old_details.representation();
     567             : 
     568        2391 :     Descriptor d;
     569        2391 :     if (next_location == kField) {
     570             :       Handle<FieldType> next_field_type =
     571        2179 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     572             : 
     573             :       // If the |new_elements_kind_| is still transitionable then the old map's
     574             :       // elements kind is also transitionable and therefore the old descriptors
     575             :       // array must already have non in-place generalizable fields.
     576        2553 :       CHECK_IMPLIES(is_transitionable_fast_elements_kind_,
     577             :                     !Map::IsInplaceGeneralizableField(
     578             :                         next_constness, next_representation, *next_field_type));
     579             : 
     580             :       MaybeObjectHandle wrapped_type(
     581        2179 :           Map::WrapFieldType(isolate_, next_field_type));
     582        2179 :       Descriptor d;
     583        2179 :       if (next_kind == kData) {
     584             :         DCHECK_IMPLIES(!FLAG_track_constant_fields,
     585             :                        next_constness == PropertyConstness::kMutable);
     586             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     587             :                                   next_constness, next_representation,
     588        2179 :                                   wrapped_type);
     589             :       } else {
     590             :         // TODO(ishell): mutable accessors are not implemented yet.
     591           0 :         UNIMPLEMENTED();
     592             :       }
     593        2179 :       current_offset += d.GetDetails().field_width_in_words();
     594        2179 :       new_descriptors->Set(i, &d);
     595             :     } else {
     596             :       DCHECK_EQ(kDescriptor, next_location);
     597             :       DCHECK_EQ(PropertyConstness::kConst, next_constness);
     598             : 
     599         212 :       Handle<Object> value(GetValue(i), isolate_);
     600         212 :       if (next_kind == kData) {
     601         144 :         d = Descriptor::DataConstant(key, value, next_attributes);
     602             :       } else {
     603             :         DCHECK_EQ(kAccessor, next_kind);
     604          68 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     605             :       }
     606         212 :       new_descriptors->Set(i, &d);
     607             :     }
     608             :   }
     609             : 
     610       20731 :   new_descriptors->Sort();
     611       20731 :   return new_descriptors;
     612             : }
     613             : 
     614       20731 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
     615             :   DisallowHeapAllocation no_allocation;
     616             : 
     617             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     618             :   Map current = *root_map_;
     619       62395 :   for (int i = root_nof; i < old_nof_; i++) {
     620       62395 :     Name name = descriptors->GetKey(i);
     621       62395 :     PropertyDetails details = descriptors->GetDetails(i);
     622             :     Map next =
     623             :         TransitionsAccessor(isolate_, current, &no_allocation)
     624      124790 :             .SearchTransition(name, details.kind(), details.attributes());
     625       62395 :     if (next.is_null()) break;
     626       60814 :     DescriptorArray next_descriptors = next->instance_descriptors();
     627             : 
     628       60814 :     PropertyDetails next_details = next_descriptors->GetDetails(i);
     629             :     DCHECK_EQ(details.kind(), next_details.kind());
     630             :     DCHECK_EQ(details.attributes(), next_details.attributes());
     631       60814 :     if (details.constness() != next_details.constness()) break;
     632       51879 :     if (details.location() != next_details.location()) break;
     633       51879 :     if (!details.representation().Equals(next_details.representation())) break;
     634             : 
     635       41664 :     if (next_details.location() == kField) {
     636       40813 :       FieldType next_field_type = next_descriptors->GetFieldType(i);
     637       40813 :       if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
     638             :         break;
     639             :       }
     640             :     } else {
     641         851 :       if (!EqualImmutableValues(descriptors->GetStrongValue(i),
     642        2553 :                                 next_descriptors->GetStrongValue(i))) {
     643             :         break;
     644             :       }
     645             :     }
     646       41664 :     current = next;
     647             :   }
     648       41462 :   return handle(current, isolate_);
     649             : }
     650             : 
     651       20731 : MapUpdater::State MapUpdater::ConstructNewMap() {
     652       20731 :   Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
     653             : 
     654       20731 :   Handle<Map> split_map = FindSplitMap(new_descriptors);
     655             :   int split_nof = split_map->NumberOfOwnDescriptors();
     656             :   DCHECK_NE(old_nof_, split_nof);
     657             : 
     658       20731 :   PropertyDetails split_details = GetDetails(split_nof);
     659       20731 :   TransitionsAccessor transitions(isolate_, split_map);
     660             : 
     661             :   // Invalidate a transition target at |key|.
     662             :   Map maybe_transition = transitions.SearchTransition(
     663       20731 :       GetKey(split_nof), split_details.kind(), split_details.attributes());
     664       20731 :   if (!maybe_transition.is_null()) {
     665       19150 :     maybe_transition->DeprecateTransitionTree(isolate_);
     666             :   }
     667             : 
     668             :   // If |maybe_transition| is not nullptr then the transition array already
     669             :   // contains entry for given descriptor. This means that the transition
     670             :   // could be inserted regardless of whether transitions array is full or not.
     671       20731 :   if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
     672           5 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     673             :   }
     674             : 
     675       41452 :   old_map_->NotifyLeafMapLayoutChange(isolate_);
     676             : 
     677       20726 :   if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
     678             :     PropertyDetails old_details =
     679           0 :         old_descriptors_->GetDetails(modified_descriptor_);
     680             :     PropertyDetails new_details =
     681           0 :         new_descriptors->GetDetails(modified_descriptor_);
     682           0 :     MaybeHandle<FieldType> old_field_type;
     683           0 :     MaybeHandle<FieldType> new_field_type;
     684           0 :     MaybeHandle<Object> old_value;
     685           0 :     MaybeHandle<Object> new_value;
     686           0 :     if (old_details.location() == kField) {
     687             :       old_field_type = handle(
     688           0 :           old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
     689             :     } else {
     690             :       old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_),
     691           0 :                          isolate_);
     692             :     }
     693           0 :     if (new_details.location() == kField) {
     694             :       new_field_type =
     695           0 :           handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
     696             :     } else {
     697             :       new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_),
     698           0 :                          isolate_);
     699             :     }
     700             : 
     701             :     old_map_->PrintGeneralization(
     702             :         isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_,
     703           0 :         old_details.location() == kDescriptor && new_location_ == kField,
     704             :         old_details.representation(), new_details.representation(),
     705           0 :         old_field_type, old_value, new_field_type, new_value);
     706             :   }
     707             : 
     708             :   Handle<LayoutDescriptor> new_layout_descriptor =
     709       20726 :       LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_);
     710             : 
     711             :   Handle<Map> new_map = Map::AddMissingTransitions(
     712       20726 :       isolate_, split_map, new_descriptors, new_layout_descriptor);
     713             : 
     714             :   // Deprecated part of the transition tree is no longer reachable, so replace
     715             :   // current instance descriptors in the "survived" part of the tree with
     716             :   // the new descriptors to maintain descriptors sharing invariant.
     717             :   split_map->ReplaceDescriptors(isolate_, *new_descriptors,
     718       41452 :                                 *new_layout_descriptor);
     719             : 
     720       20726 :   result_map_ = new_map;
     721       20726 :   state_ = kEnd;
     722       20726 :   return state_;  // Done.
     723             : }
     724             : 
     725             : }  // namespace internal
     726      183867 : }  // namespace v8

Generated by: LCOV version 1.10