LCOV - code coverage report
Current view: top level - src - map-updater.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 224 248 90.3 %
Date: 2017-10-20 Functions: 17 18 94.4 %

          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        4769 :   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      397902 : Name* MapUpdater::GetKey(int descriptor) const {
      28      397902 :   return old_descriptors_->GetKey(descriptor);
      29             : }
      30             : 
      31      395831 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
      32             :   DCHECK_LE(0, descriptor);
      33      395831 :   if (descriptor == modified_descriptor_) {
      34             :     return PropertyDetails(new_kind_, new_attributes_, new_location_,
      35      272978 :                            new_constness_, new_representation_);
      36             :   }
      37      259342 :   return old_descriptors_->GetDetails(descriptor);
      38             : }
      39             : 
      40        7252 : Object* MapUpdater::GetValue(int descriptor) const {
      41             :   DCHECK_LE(0, descriptor);
      42        7252 :   if (descriptor == modified_descriptor_) {
      43             :     DCHECK_EQ(kDescriptor, new_location_);
      44           0 :     return *new_value_;
      45             :   }
      46             :   DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
      47        7252 :   return old_descriptors_->GetValue(descriptor);
      48             : }
      49             : 
      50      287251 : FieldType* MapUpdater::GetFieldType(int descriptor) const {
      51             :   DCHECK_LE(0, descriptor);
      52      287251 :   if (descriptor == modified_descriptor_) {
      53             :     DCHECK_EQ(kField, new_location_);
      54       65443 :     return *new_field_type_;
      55             :   }
      56             :   DCHECK_EQ(kField, GetDetails(descriptor).location());
      57      221808 :   return old_descriptors_->GetFieldType(descriptor);
      58             : }
      59             : 
      60      288319 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      61             :     int descriptor, PropertyLocation location,
      62             :     Representation representation) const {
      63             :   DCHECK_LE(0, descriptor);
      64             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      65             :   DCHECK_EQ(location, GetDetails(descriptor).location());
      66      288319 :   if (location == kField) {
      67      287251 :     return handle(GetFieldType(descriptor), isolate_);
      68             :   } else {
      69        1068 :     return GetValue(descriptor)->OptimalType(isolate_, representation);
      70             :   }
      71             : }
      72             : 
      73      450564 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      74             :     Handle<DescriptorArray> descriptors, int descriptor,
      75             :     PropertyLocation location, Representation representation) {
      76             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      77             :   DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
      78      450564 :   if (location == kField) {
      79      854278 :     return handle(descriptors->GetFieldType(descriptor), isolate_);
      80             :   } else {
      81             :     return descriptors->GetValue(descriptor)
      82       46850 :         ->OptimalType(isolate_, representation);
      83             :   }
      84             : }
      85             : 
      86      360534 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
      87             :                                                PropertyAttributes attributes,
      88             :                                                PropertyConstness constness,
      89             :                                                Representation representation,
      90      360534 :                                                Handle<FieldType> field_type) {
      91             :   DCHECK_EQ(kInitialized, state_);
      92             :   DCHECK_LE(0, descriptor);
      93             :   DCHECK(!old_map_->is_dictionary_map());
      94      360534 :   modified_descriptor_ = descriptor;
      95      360534 :   new_kind_ = kData;
      96      360534 :   new_attributes_ = attributes;
      97      360534 :   new_location_ = kField;
      98             : 
      99             :   PropertyDetails old_details =
     100      360534 :       old_descriptors_->GetDetails(modified_descriptor_);
     101             : 
     102             :   // If property kind is not reconfigured merge the result with
     103             :   // representation/field type from the old descriptor.
     104      360534 :   if (old_details.kind() == new_kind_) {
     105      349250 :     new_constness_ = GeneralizeConstness(constness, old_details.constness());
     106             : 
     107      349250 :     Representation old_representation = old_details.representation();
     108      349250 :     new_representation_ = representation.generalize(old_representation);
     109             : 
     110             :     Handle<FieldType> old_field_type =
     111             :         GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
     112      349250 :                               old_details.location(), new_representation_);
     113             : 
     114             :     new_field_type_ =
     115             :         Map::GeneralizeFieldType(old_representation, old_field_type,
     116      349250 :                                  new_representation_, field_type, isolate_);
     117             :   } else {
     118             :     // We don't know if this is a first property kind reconfiguration
     119             :     // and we don't know which value was in this property previously
     120             :     // therefore we can't treat such a property as constant.
     121       11284 :     new_constness_ = kMutable;
     122       11284 :     new_representation_ = representation;
     123       11284 :     new_field_type_ = field_type;
     124             :   }
     125             : 
     126             :   GeneralizeIfTransitionableFastElementsKind(
     127      721068 :       &new_constness_, &new_representation_, &new_field_type_);
     128             : 
     129      360534 :   if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
     130       82966 :   if (FindRootMap() == kEnd) return result_map_;
     131       65985 :   if (FindTargetMap() == kEnd) return result_map_;
     132       23763 :   ConstructNewMap();
     133             :   DCHECK_EQ(kEnd, state_);
     134       23763 :   return result_map_;
     135             : }
     136             : 
     137      427557 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
     138             :   DCHECK_EQ(kInitialized, state_);
     139      427557 :   new_elements_kind_ = elements_kind;
     140             :   is_transitionable_fast_elements_kind_ =
     141      427557 :       IsTransitionableFastElementsKind(new_elements_kind_);
     142             : 
     143      427557 :   if (FindRootMap() == kEnd) return result_map_;
     144      427557 :   if (FindTargetMap() == kEnd) return result_map_;
     145         868 :   ConstructNewMap();
     146             :   DCHECK_EQ(kEnd, state_);
     147         868 :   return result_map_;
     148             : }
     149             : 
     150        4167 : Handle<Map> MapUpdater::Update() {
     151             :   DCHECK_EQ(kInitialized, state_);
     152             :   DCHECK(old_map_->is_deprecated());
     153             : 
     154        4167 :   if (FindRootMap() == kEnd) return result_map_;
     155        4097 :   if (FindTargetMap() == kEnd) return result_map_;
     156         199 :   ConstructNewMap();
     157             :   DCHECK_EQ(kEnd, state_);
     158         199 :   return result_map_;
     159             : }
     160             : 
     161      461848 : void MapUpdater::GeneralizeIfTransitionableFastElementsKind(
     162             :     PropertyConstness* constness, Representation* representation,
     163             :     Handle<FieldType>* field_type) {
     164             :   DCHECK_EQ(is_transitionable_fast_elements_kind_,
     165             :             IsTransitionableFastElementsKind(new_elements_kind_));
     166      476338 :   if (is_transitionable_fast_elements_kind_ &&
     167             :       Map::IsInplaceGeneralizableField(*constness, *representation,
     168             :                                        **field_type)) {
     169             :     // We don't support propagation of field generalization through elements
     170             :     // kind transitions because they are inserted into the transition tree
     171             :     // before field transitions. In order to avoid complexity of handling
     172             :     // such a case we ensure that all maps with transitionable elements kinds
     173             :     // do not have fields that can be generalized in-place (without creation
     174             :     // of a new map).
     175             :     if (FLAG_track_constant_fields && FLAG_modify_map_inplace) {
     176             :       *constness = kMutable;
     177             :     }
     178             :     DCHECK(representation->IsHeapObject());
     179         126 :     *field_type = FieldType::Any(isolate_);
     180             :   }
     181      461848 : }
     182             : 
     183           0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
     184             :                                  PropertyConstness new_constness,
     185             :                                  Representation new_representation,
     186             :                                  Handle<FieldType> new_field_type) {
     187             :   Map::GeneralizeField(map, modify_index, new_constness, new_representation,
     188      462385 :                        new_field_type);
     189             : 
     190             :   DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
     191           0 : }
     192             : 
     193       17070 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
     194             :   result_map_ = Map::CopyGeneralizeAllFields(old_map_, new_elements_kind_,
     195             :                                              modified_descriptor_, new_kind_,
     196       17070 :                                              new_attributes_, reason);
     197       17070 :   state_ = kEnd;
     198       17070 :   return state_;  // Done.
     199             : }
     200             : 
     201      360534 : MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
     202             :   // If it's just a representation generalization case (i.e. property kind and
     203             :   // attributes stays unchanged) it's fine to transition from None to anything
     204             :   // but double without any modification to the object, because the default
     205             :   // uninitialized value for representation None can be overwritten by both
     206             :   // smi and tagged values. Doubles, however, would require a box allocation.
     207      360534 :   if (new_representation_.IsNone() || new_representation_.IsDouble()) {
     208       16528 :     return state_;  // Not done yet.
     209             :   }
     210             : 
     211             :   PropertyDetails old_details =
     212      688012 :       old_descriptors_->GetDetails(modified_descriptor_);
     213             :   Representation old_representation = old_details.representation();
     214      344006 :   if (!old_representation.IsNone()) {
     215       66438 :     return state_;  // Not done yet.
     216             :   }
     217             : 
     218             :   DCHECK_EQ(new_kind_, old_details.kind());
     219             :   DCHECK_EQ(new_attributes_, old_details.attributes());
     220             :   DCHECK_EQ(kField, old_details.location());
     221      277568 :   if (FLAG_trace_generalization) {
     222             :     old_map_->PrintGeneralization(
     223             :         stdout, "uninitialized field", modified_descriptor_, old_nof_, old_nof_,
     224             :         false, old_representation, new_representation_,
     225             :         handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
     226           0 :         MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
     227             :   }
     228             :   Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_),
     229      555136 :                           isolate_);
     230             : 
     231             :   GeneralizeField(field_owner, modified_descriptor_, new_constness_,
     232      277568 :                   new_representation_, new_field_type_);
     233             :   // Check that the descriptor array was updated.
     234             :   DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
     235             :              .representation()
     236             :              .Equals(new_representation_));
     237             :   DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
     238             :              ->NowIs(new_field_type_));
     239             : 
     240      277568 :   result_map_ = old_map_;
     241      277568 :   state_ = kEnd;
     242      277568 :   return state_;  // Done.
     243             : }
     244             : 
     245      514690 : MapUpdater::State MapUpdater::FindRootMap() {
     246             :   DCHECK_EQ(kInitialized, state_);
     247             :   // Check the state of the root map.
     248     1544070 :   root_map_ = handle(old_map_->FindRootMap(), isolate_);
     249             :   ElementsKind from_kind = root_map_->elements_kind();
     250      514690 :   ElementsKind to_kind = new_elements_kind_;
     251      514690 :   if (root_map_->is_deprecated()) {
     252           0 :     state_ = kEnd;
     253             :     result_map_ = handle(
     254           0 :         JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
     255           0 :     if (from_kind != to_kind) {
     256           0 :       result_map_ = Map::AsElementsKind(result_map_, to_kind);
     257             :     }
     258             :     DCHECK(result_map_->is_dictionary_map());
     259           0 :     return state_;
     260             :   }
     261             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     262      514690 :   if (!old_map_->EquivalentToForTransition(*root_map_)) {
     263          95 :     return CopyGeneralizeAllFields("GenAll_NotEquivalent");
     264             :   }
     265             : 
     266             :   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
     267     1029190 :   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
     268      252482 :       to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
     269      766875 :       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
     270             :       !(IsTransitionableFastElementsKind(from_kind) &&
     271      126039 :         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
     272           0 :     return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
     273             :   }
     274             : 
     275      514595 :   if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
     276             :     PropertyDetails old_details =
     277       17549 :         old_descriptors_->GetDetails(modified_descriptor_);
     278       23885 :     if (old_details.kind() != new_kind_ ||
     279        6336 :         old_details.attributes() != new_attributes_) {
     280       11213 :       return CopyGeneralizeAllFields("GenAll_RootModification1");
     281             :     }
     282        6336 :     if (old_details.location() != kField) {
     283        4984 :       return CopyGeneralizeAllFields("GenAll_RootModification2");
     284             :     }
     285        2704 :     if (new_constness_ != old_details.constness() &&
     286             :         (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
     287           0 :       return CopyGeneralizeAllFields("GenAll_RootModification3");
     288             :     }
     289        2704 :     if (!new_representation_.fits_into(old_details.representation())) {
     290          20 :       return CopyGeneralizeAllFields("GenAll_RootModification4");
     291             :     }
     292             : 
     293             :     DCHECK_EQ(kData, old_details.kind());
     294             :     DCHECK_EQ(kData, new_kind_);
     295             :     DCHECK_EQ(kField, new_location_);
     296             :     FieldType* old_field_type =
     297        2664 :         old_descriptors_->GetFieldType(modified_descriptor_);
     298        1332 :     if (!new_field_type_->NowIs(old_field_type)) {
     299         739 :       return CopyGeneralizeAllFields("GenAll_RootModification5");
     300             :     }
     301             : 
     302             :     // Modify root map in-place.
     303             :     if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
     304             :       // Only prototype root maps are allowed to be updated in-place.
     305             :       // TODO(ishell): fix all the stubs that use prototype map check to
     306             :       // ensure that the prototype was not modified.
     307             :       DCHECK(old_map_->is_prototype_map());
     308             :       DCHECK(old_map_->is_stable());
     309             :       DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
     310             :       GeneralizeField(old_map_, modified_descriptor_, new_constness_,
     311             :                       old_details.representation(),
     312             :                       handle(old_field_type, isolate_));
     313             :     }
     314             :   }
     315             : 
     316             :   // From here on, use the map with correct elements kind as root map.
     317      497639 :   if (from_kind != to_kind) {
     318      428253 :     root_map_ = Map::AsElementsKind(root_map_, to_kind);
     319             :   }
     320      497639 :   state_ = kAtRootMap;
     321      497639 :   return state_;  // Not done yet.
     322             : }
     323             : 
     324      497639 : MapUpdater::State MapUpdater::FindTargetMap() {
     325             :   DCHECK_EQ(kAtRootMap, state_);
     326      497639 :   target_map_ = root_map_;
     327             : 
     328             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     329      683636 :   for (int i = root_nof; i < old_nof_; ++i) {
     330      210841 :     PropertyDetails old_details = GetDetails(i);
     331             :     Map* transition = TransitionsAccessor(target_map_)
     332             :                           .SearchTransition(GetKey(i), old_details.kind(),
     333      421682 :                                             old_details.attributes());
     334      210841 :     if (transition == nullptr) break;
     335      209212 :     Handle<Map> tmp_map(transition, isolate_);
     336             : 
     337             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     338      209212 :                                             isolate_);
     339             : 
     340             :     // Check if target map is incompatible.
     341      209212 :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     342             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     343             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     344      209342 :     if (old_details.kind() == kAccessor &&
     345         130 :         !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
     346             :       // TODO(ishell): mutable accessors are not implemented yet.
     347          14 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     348             :     }
     349             :     PropertyConstness tmp_constness = tmp_details.constness();
     350      209198 :     if (!FLAG_modify_map_inplace &&
     351             :         !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
     352             :       break;
     353             :     }
     354      200167 :     if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
     355             :       break;
     356             :     }
     357      200150 :     Representation tmp_representation = tmp_details.representation();
     358      400300 :     if (!old_details.representation().fits_into(tmp_representation)) {
     359             :       break;
     360             :     }
     361             : 
     362      186052 :     if (tmp_details.location() == kField) {
     363             :       Handle<FieldType> old_field_type =
     364      184817 :           GetOrComputeFieldType(i, old_details.location(), tmp_representation);
     365             :       PropertyConstness constness =
     366             :           FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
     367             :       GeneralizeField(tmp_map, i, constness, tmp_representation,
     368             :                       old_field_type);
     369             :     } else {
     370             :       // kDescriptor: Check that the value matches.
     371        2470 :       if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
     372             :         break;
     373             :       }
     374             :     }
     375             :     DCHECK(!tmp_map->is_deprecated());
     376      185997 :     target_map_ = tmp_map;
     377             :   }
     378             : 
     379             :   // Directly change the map if the target map is more general.
     380             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     381      497625 :   if (target_nof == old_nof_) {
     382             : #ifdef DEBUG
     383             :     if (modified_descriptor_ >= 0) {
     384             :       DescriptorArray* target_descriptors = target_map_->instance_descriptors();
     385             :       PropertyDetails details =
     386             :           target_descriptors->GetDetails(modified_descriptor_);
     387             :       DCHECK_EQ(new_kind_, details.kind());
     388             :       DCHECK_EQ(new_attributes_, details.attributes());
     389             :       DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
     390             :       DCHECK_EQ(new_location_, details.location());
     391             :       DCHECK(new_representation_.fits_into(details.representation()));
     392             :       if (new_location_ == kField) {
     393             :         DCHECK_EQ(kField, details.location());
     394             :         DCHECK(new_field_type_->NowIs(
     395             :             target_descriptors->GetFieldType(modified_descriptor_)));
     396             :       } else {
     397             :         DCHECK(details.location() == kField ||
     398             :                EqualImmutableValues(*new_value_, target_descriptors->GetValue(
     399             :                                                      modified_descriptor_)));
     400             :       }
     401             :     }
     402             : #endif
     403      472795 :     if (*target_map_ != *old_map_) {
     404      431252 :       old_map_->NotifyLeafMapLayoutChange();
     405             :     }
     406      472795 :     result_map_ = target_map_;
     407      472795 :     state_ = kEnd;
     408      472795 :     return state_;  // Done.
     409             :   }
     410             : 
     411             :   // Find the last compatible target map in the transition tree.
     412       52685 :   for (int i = target_nof; i < old_nof_; ++i) {
     413       54314 :     PropertyDetails old_details = GetDetails(i);
     414             :     Map* transition = TransitionsAccessor(target_map_)
     415             :                           .SearchTransition(GetKey(i), old_details.kind(),
     416      108628 :                                             old_details.attributes());
     417       54314 :     if (transition == nullptr) break;
     418       52685 :     Handle<Map> tmp_map(transition, isolate_);
     419             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     420       52685 :                                             isolate_);
     421             : #ifdef DEBUG
     422             :     // Check that target map is compatible.
     423             :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     424             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     425             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     426             : #endif
     427       52700 :     if (old_details.kind() == kAccessor &&
     428          15 :         !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
     429           0 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     430             :     }
     431             :     DCHECK(!tmp_map->is_deprecated());
     432       52685 :     target_map_ = tmp_map;
     433             :   }
     434             : 
     435       24830 :   state_ = kAtTargetMap;
     436       24830 :   return state_;  // Not done yet.
     437             : }
     438             : 
     439      126144 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
     440             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     441             :   Handle<DescriptorArray> target_descriptors(
     442       24830 :       target_map_->instance_descriptors(), isolate_);
     443             : 
     444             :   // Allocate a new descriptor array large enough to hold the required
     445             :   // descriptors, with minimally the exact same size as the old descriptor
     446             :   // array.
     447             :   int new_slack =
     448       49660 :       Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_;
     449             :   Handle<DescriptorArray> new_descriptors =
     450       24830 :       DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
     451             :   DCHECK(new_descriptors->length() > target_descriptors->length() ||
     452             :          new_descriptors->NumberOfSlackDescriptors() > 0 ||
     453             :          new_descriptors->number_of_descriptors() ==
     454             :              old_descriptors_->number_of_descriptors());
     455             :   DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
     456             : 
     457             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     458             : 
     459             :   // Given that we passed root modification check in FindRootMap() so
     460             :   // the root descriptors are either not modified at all or already more
     461             :   // general than we requested. Take |root_nof| entries as is.
     462             :   // 0 -> |root_nof|
     463             :   int current_offset = 0;
     464       26901 :   for (int i = 0; i < root_nof; ++i) {
     465        2071 :     PropertyDetails old_details = old_descriptors_->GetDetails(i);
     466        2071 :     if (old_details.location() == kField) {
     467         200 :       current_offset += old_details.field_width_in_words();
     468             :     }
     469             :     Descriptor d(handle(GetKey(i), isolate_),
     470        4142 :                  handle(old_descriptors_->GetValue(i), isolate_), old_details);
     471        2071 :     new_descriptors->Set(i, &d);
     472             :   }
     473             : 
     474             :   // Merge "updated" old_descriptor entries with target_descriptor entries.
     475             :   // |root_nof| -> |target_nof|
     476      103419 :   for (int i = root_nof; i < target_nof; ++i) {
     477      103419 :     Handle<Name> key(GetKey(i), isolate_);
     478      103419 :     PropertyDetails old_details = GetDetails(i);
     479      103419 :     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        2495 :         old_details.location() == kField ||
     493             :                 target_details.location() == kField ||
     494             :                 !EqualImmutableValues(target_descriptors->GetValue(i),
     495        2460 :                                       GetValue(i))
     496             :             ? kField
     497      105879 :             : kDescriptor;
     498             : 
     499      103419 :     if (!FLAG_track_constant_fields && next_location == kField) {
     500             :       next_constness = kMutable;
     501             :     }
     502             :     // Ensure that mutable values are stored in fields.
     503             :     DCHECK_IMPLIES(next_constness == kMutable, next_location == kField);
     504             : 
     505             :     Representation next_representation =
     506             :         old_details.representation().generalize(
     507      103419 :             target_details.representation());
     508             : 
     509      103419 :     if (next_location == kField) {
     510             :       Handle<FieldType> old_field_type =
     511      101314 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     512             : 
     513             :       Handle<FieldType> target_field_type =
     514             :           GetOrComputeFieldType(target_descriptors, i,
     515      101314 :                                 target_details.location(), next_representation);
     516             : 
     517             :       Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
     518             :           old_details.representation(), old_field_type, next_representation,
     519      101314 :           target_field_type, isolate_);
     520             : 
     521             :       GeneralizeIfTransitionableFastElementsKind(
     522      101314 :           &next_constness, &next_representation, &next_field_type);
     523             : 
     524      101314 :       Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
     525             :       Descriptor d;
     526      101314 :       if (next_kind == kData) {
     527             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     528             :                                   next_constness, next_representation,
     529      101314 :                                   wrapped_type);
     530             :       } else {
     531             :         // TODO(ishell): mutable accessors are not implemented yet.
     532           0 :         UNIMPLEMENTED();
     533             :       }
     534      101314 :       current_offset += d.GetDetails().field_width_in_words();
     535      101314 :       new_descriptors->Set(i, &d);
     536             :     } else {
     537             :       DCHECK_EQ(kDescriptor, next_location);
     538             :       DCHECK_EQ(kConst, next_constness);
     539             : 
     540        2105 :       Handle<Object> value(GetValue(i), isolate_);
     541             :       Descriptor d;
     542        2105 :       if (next_kind == kData) {
     543             :         DCHECK(!FLAG_track_constant_fields);
     544        2041 :         d = Descriptor::DataConstant(key, value, next_attributes);
     545             :       } else {
     546             :         DCHECK_EQ(kAccessor, next_kind);
     547          64 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     548             :       }
     549        2105 :       new_descriptors->Set(i, &d);
     550             :     }
     551             :   }
     552             : 
     553             :   // Take "updated" old_descriptor entries.
     554             :   // |target_nof| -> |old_nof|
     555        2427 :   for (int i = target_nof; i < old_nof_; ++i) {
     556        2427 :     PropertyDetails old_details = GetDetails(i);
     557        2427 :     Handle<Name> key(GetKey(i), isolate_);
     558             : 
     559             :     PropertyKind next_kind = old_details.kind();
     560             :     PropertyAttributes next_attributes = old_details.attributes();
     561             :     PropertyConstness next_constness = old_details.constness();
     562             :     PropertyLocation next_location = old_details.location();
     563             :     Representation next_representation = old_details.representation();
     564             : 
     565             :     Descriptor d;
     566        2427 :     if (next_location == kField) {
     567             :       Handle<FieldType> next_field_type =
     568        2188 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     569             : 
     570             :       // If the |new_elements_kind_| is still transitionable then the old map's
     571             :       // elements kind is also transitionable and therefore the old descriptors
     572             :       // array must already have non in-place generalizable fields.
     573        2665 :       CHECK_IMPLIES(is_transitionable_fast_elements_kind_,
     574             :                     !Map::IsInplaceGeneralizableField(
     575             :                         next_constness, next_representation, *next_field_type));
     576             : 
     577        2188 :       Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
     578             :       Descriptor d;
     579        2188 :       if (next_kind == kData) {
     580             :         DCHECK_IMPLIES(!FLAG_track_constant_fields, next_constness == kMutable);
     581             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     582             :                                   next_constness, next_representation,
     583        2188 :                                   wrapped_type);
     584             :       } else {
     585             :         // TODO(ishell): mutable accessors are not implemented yet.
     586           0 :         UNIMPLEMENTED();
     587             :       }
     588        2188 :       current_offset += d.GetDetails().field_width_in_words();
     589        2188 :       new_descriptors->Set(i, &d);
     590             :     } else {
     591             :       DCHECK_EQ(kDescriptor, next_location);
     592             :       DCHECK_EQ(kConst, next_constness);
     593             : 
     594         239 :       Handle<Object> value(GetValue(i), isolate_);
     595         239 :       if (next_kind == kData) {
     596         169 :         d = Descriptor::DataConstant(key, value, next_attributes);
     597             :       } else {
     598             :         DCHECK_EQ(kAccessor, next_kind);
     599          70 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     600             :       }
     601         239 :       new_descriptors->Set(i, &d);
     602             :     }
     603             :   }
     604             : 
     605       24830 :   new_descriptors->Sort();
     606       24830 :   return new_descriptors;
     607             : }
     608             : 
     609       24830 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
     610             :   DisallowHeapAllocation no_allocation;
     611             : 
     612             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     613             :   Map* current = *root_map_;
     614       75564 :   for (int i = root_nof; i < old_nof_; i++) {
     615             :     Name* name = descriptors->GetKey(i);
     616       75564 :     PropertyDetails details = descriptors->GetDetails(i);
     617             :     Map* next =
     618             :         TransitionsAccessor(current, &no_allocation)
     619       75564 :             .SearchTransition(name, details.kind(), details.attributes());
     620       75564 :     if (next == nullptr) break;
     621             :     DescriptorArray* next_descriptors = next->instance_descriptors();
     622             : 
     623       73935 :     PropertyDetails next_details = next_descriptors->GetDetails(i);
     624             :     DCHECK_EQ(details.kind(), next_details.kind());
     625             :     DCHECK_EQ(details.attributes(), next_details.attributes());
     626       73935 :     if (details.constness() != next_details.constness()) break;
     627       64832 :     if (details.location() != next_details.location()) break;
     628       64832 :     if (!details.representation().Equals(next_details.representation())) break;
     629             : 
     630       50734 :     if (next_details.location() == kField) {
     631       49805 :       FieldType* next_field_type = next_descriptors->GetFieldType(i);
     632       49805 :       if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
     633             :         break;
     634             :       }
     635             :     } else {
     636         929 :       if (!EqualImmutableValues(descriptors->GetValue(i),
     637             :                                 next_descriptors->GetValue(i))) {
     638             :         break;
     639             :       }
     640             :     }
     641             :     current = next;
     642             :   }
     643       49660 :   return handle(current, isolate_);
     644             : }
     645             : 
     646       24830 : MapUpdater::State MapUpdater::ConstructNewMap() {
     647       24830 :   Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
     648             : 
     649       24830 :   Handle<Map> split_map = FindSplitMap(new_descriptors);
     650             :   int split_nof = split_map->NumberOfOwnDescriptors();
     651             :   DCHECK_NE(old_nof_, split_nof);
     652             : 
     653       24830 :   PropertyDetails split_details = GetDetails(split_nof);
     654             :   TransitionsAccessor transitions(split_map);
     655             : 
     656             :   // Invalidate a transition target at |key|.
     657             :   Map* maybe_transition = transitions.SearchTransition(
     658       24830 :       GetKey(split_nof), split_details.kind(), split_details.attributes());
     659       24830 :   if (maybe_transition != nullptr) {
     660       23201 :     maybe_transition->DeprecateTransitionTree();
     661             :   }
     662             : 
     663             :   // If |maybe_transition| is not nullptr then the transition array already
     664             :   // contains entry for given descriptor. This means that the transition
     665             :   // could be inserted regardless of whether transitions array is full or not.
     666       24830 :   if (maybe_transition == nullptr && !transitions.CanHaveMoreTransitions()) {
     667           5 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     668             :   }
     669             : 
     670       24825 :   old_map_->NotifyLeafMapLayoutChange();
     671             : 
     672       24825 :   if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
     673             :     PropertyDetails old_details =
     674           0 :         old_descriptors_->GetDetails(modified_descriptor_);
     675             :     PropertyDetails new_details =
     676           0 :         new_descriptors->GetDetails(modified_descriptor_);
     677             :     MaybeHandle<FieldType> old_field_type;
     678             :     MaybeHandle<FieldType> new_field_type;
     679             :     MaybeHandle<Object> old_value;
     680             :     MaybeHandle<Object> new_value;
     681           0 :     if (old_details.location() == kField) {
     682             :       old_field_type = handle(
     683           0 :           old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
     684             :     } else {
     685             :       old_value =
     686           0 :           handle(old_descriptors_->GetValue(modified_descriptor_), isolate_);
     687             :     }
     688           0 :     if (new_details.location() == kField) {
     689             :       new_field_type =
     690           0 :           handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
     691             :     } else {
     692             :       new_value =
     693           0 :           handle(new_descriptors->GetValue(modified_descriptor_), isolate_);
     694             :     }
     695             : 
     696             :     old_map_->PrintGeneralization(
     697             :         stdout, "", modified_descriptor_, split_nof, old_nof_,
     698           0 :         old_details.location() == kDescriptor && new_location_ == kField,
     699             :         old_details.representation(), new_details.representation(),
     700           0 :         old_field_type, old_value, new_field_type, new_value);
     701             :   }
     702             : 
     703             :   Handle<LayoutDescriptor> new_layout_descriptor =
     704       24825 :       LayoutDescriptor::New(split_map, new_descriptors, old_nof_);
     705             : 
     706             :   Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors,
     707       24825 :                                                    new_layout_descriptor);
     708             : 
     709             :   // Deprecated part of the transition tree is no longer reachable, so replace
     710             :   // current instance descriptors in the "survived" part of the tree with
     711             :   // the new descriptors to maintain descriptors sharing invariant.
     712       24825 :   split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
     713             : 
     714       24825 :   result_map_ = new_map;
     715       24825 :   state_ = kEnd;
     716       24825 :   return state_;  // Done.
     717             : }
     718             : 
     719             : }  // namespace internal
     720             : }  // namespace v8

Generated by: LCOV version 1.10