LCOV - code coverage report
Current view: top level - src - map-updater.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 271 304 89.1 %
Date: 2019-02-19 Functions: 21 22 95.5 %

          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       16591 :   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      594308 : 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     4160182 :           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      646785 : Name MapUpdater::GetKey(int descriptor) const {
      42      646785 :   return old_descriptors_->GetKey(descriptor);
      43             : }
      44             : 
      45      645481 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
      46             :   DCHECK_LE(0, descriptor);
      47      645481 :   if (descriptor == modified_descriptor_) {
      48      128002 :     PropertyAttributes attributes = new_attributes_;
      49             :     // If the original map was sealed or frozen, let us used the old
      50             :     // attributes so that we follow the same transition path as before.
      51             :     // Note that the user could not have changed the attributes because
      52             :     // both seal and freeze make the properties non-configurable.
      53      128002 :     if (integrity_level_ == SEALED || integrity_level_ == FROZEN) {
      54         518 :       attributes = old_descriptors_->GetDetails(descriptor).attributes();
      55             :     }
      56             :     return PropertyDetails(new_kind_, attributes, new_location_, new_constness_,
      57      256004 :                            new_representation_);
      58             :   }
      59      517480 :   return old_descriptors_->GetDetails(descriptor);
      60             : }
      61             : 
      62       16683 : Object MapUpdater::GetValue(int descriptor) const {
      63             :   DCHECK_LE(0, descriptor);
      64       16683 :   if (descriptor == modified_descriptor_) {
      65             :     DCHECK_EQ(kDescriptor, new_location_);
      66             :     return *new_value_;
      67             :   }
      68             :   DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
      69       33366 :   return old_descriptors_->GetStrongValue(descriptor);
      70             : }
      71             : 
      72      579303 : FieldType MapUpdater::GetFieldType(int descriptor) const {
      73             :   DCHECK_LE(0, descriptor);
      74      579303 :   if (descriptor == modified_descriptor_) {
      75             :     DCHECK_EQ(kField, new_location_);
      76             :     return *new_field_type_;
      77             :   }
      78             :   DCHECK_EQ(kField, GetDetails(descriptor).location());
      79      484238 :   return old_descriptors_->GetFieldType(descriptor);
      80             : }
      81             : 
      82      579304 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      83             :     int descriptor, PropertyLocation location,
      84             :     Representation representation) const {
      85             :   DCHECK_LE(0, descriptor);
      86             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      87             :   DCHECK_EQ(location, GetDetails(descriptor).location());
      88      579304 :   if (location == kField) {
      89      579304 :     return handle(GetFieldType(descriptor), isolate_);
      90             :   } else {
      91           0 :     return GetValue(descriptor)->OptimalType(isolate_, representation);
      92             :   }
      93             : }
      94             : 
      95      347732 : Handle<FieldType> MapUpdater::GetOrComputeFieldType(
      96             :     Handle<DescriptorArray> descriptors, int descriptor,
      97             :     PropertyLocation location, Representation representation) {
      98             :   // |location| is just a pre-fetched GetDetails(descriptor).location().
      99             :   DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
     100      347732 :   if (location == kField) {
     101     1043199 :     return handle(descriptors->GetFieldType(descriptor), isolate_);
     102             :   } else {
     103           0 :     return descriptors->GetStrongValue(descriptor)
     104           0 :         ->OptimalType(isolate_, representation);
     105             :   }
     106             : }
     107             : 
     108      296064 : Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor,
     109             :                                                PropertyAttributes attributes,
     110             :                                                PropertyConstness constness,
     111             :                                                Representation representation,
     112             :                                                Handle<FieldType> field_type) {
     113             :   DCHECK_EQ(kInitialized, state_);
     114             :   DCHECK_LE(0, descriptor);
     115             :   DCHECK(!old_map_->is_dictionary_map());
     116      296064 :   modified_descriptor_ = descriptor;
     117      296064 :   new_kind_ = kData;
     118      296064 :   new_attributes_ = attributes;
     119      296064 :   new_location_ = kField;
     120             : 
     121             :   PropertyDetails old_details =
     122      296065 :       old_descriptors_->GetDetails(modified_descriptor_);
     123             : 
     124             :   // If property kind is not reconfigured merge the result with
     125             :   // representation/field type from the old descriptor.
     126      296069 :   if (old_details.kind() == new_kind_) {
     127      281047 :     new_constness_ = GeneralizeConstness(constness, old_details.constness());
     128             : 
     129      281047 :     Representation old_representation = old_details.representation();
     130      281047 :     new_representation_ = representation.generalize(old_representation);
     131             : 
     132             :     Handle<FieldType> old_field_type =
     133             :         GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
     134      281044 :                               old_details.location(), new_representation_);
     135             : 
     136             :     new_field_type_ =
     137             :         Map::GeneralizeFieldType(old_representation, old_field_type,
     138      281047 :                                  new_representation_, field_type, isolate_);
     139             :   } else {
     140             :     // We don't know if this is a first property kind reconfiguration
     141             :     // and we don't know which value was in this property previously
     142             :     // therefore we can't treat such a property as constant.
     143       15022 :     new_constness_ = PropertyConstness::kMutable;
     144       15022 :     new_representation_ = representation;
     145       15022 :     new_field_type_ = field_type;
     146             :   }
     147             : 
     148             :   Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
     149             :       isolate_, old_map_->instance_type(), &new_constness_,
     150      592142 :       &new_representation_, &new_field_type_);
     151             : 
     152      296069 :   if (TryReconfigureToDataFieldInplace() == kEnd) return result_map_;
     153      121991 :   if (FindRootMap() == kEnd) return result_map_;
     154      106022 :   if (FindTargetMap() == kEnd) return result_map_;
     155       11055 :   if (ConstructNewMap() == kAtIntegrityLevelSource) {
     156          76 :     ConstructNewMapWithIntegrityLevelTransition();
     157             :   }
     158             :   DCHECK_EQ(kEnd, state_);
     159       11055 :   return result_map_;
     160             : }
     161             : 
     162      295076 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
     163             :   DCHECK_EQ(kInitialized, state_);
     164      295076 :   new_elements_kind_ = elements_kind;
     165             :   is_transitionable_fast_elements_kind_ =
     166      295076 :       IsTransitionableFastElementsKind(new_elements_kind_);
     167             : 
     168      295076 :   if (FindRootMap() == kEnd) return result_map_;
     169      295076 :   if (FindTargetMap() == kEnd) return result_map_;
     170         854 :   if (ConstructNewMap() == kAtIntegrityLevelSource) {
     171           0 :     ConstructNewMapWithIntegrityLevelTransition();
     172             :   }
     173             :   DCHECK_EQ(kEnd, state_);
     174         854 :   return result_map_;
     175             : }
     176             : 
     177        3168 : Handle<Map> MapUpdater::Update() {
     178             :   DCHECK_EQ(kInitialized, state_);
     179             :   DCHECK(old_map_->is_deprecated());
     180             : 
     181        3168 :   if (FindRootMap() == kEnd) return result_map_;
     182        3168 :   if (FindTargetMap() == kEnd) return result_map_;
     183         353 :   if (ConstructNewMap() == kAtIntegrityLevelSource) {
     184         210 :     ConstructNewMapWithIntegrityLevelTransition();
     185             :   }
     186             :   DCHECK_EQ(kEnd, state_);
     187             :   if (FLAG_fast_map_update) {
     188             :     TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
     189             :   }
     190         353 :   return result_map_;
     191             : }
     192             : 
     193           0 : void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index,
     194             :                                  PropertyConstness new_constness,
     195             :                                  Representation new_representation,
     196             :                                  Handle<FieldType> new_field_type) {
     197             :   Map::GeneralizeField(isolate_, map, modify_index, new_constness,
     198      695375 :                        new_representation, new_field_type);
     199             : 
     200             :   DCHECK(*old_descriptors_ == old_map_->instance_descriptors() ||
     201             :          *old_descriptors_ == integrity_source_map_->instance_descriptors());
     202           0 : }
     203             : 
     204       16015 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
     205             :   result_map_ = Map::CopyGeneralizeAllFields(
     206             :       isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
     207       16015 :       new_attributes_, reason);
     208       16015 :   state_ = kEnd;
     209       16015 :   return state_;  // Done.
     210             : }
     211             : 
     212      296066 : MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() {
     213             :   // If it's just a representation generalization case (i.e. property kind and
     214             :   // attributes stays unchanged) it's fine to transition from None to anything
     215             :   // but double without any modification to the object, because the default
     216             :   // uninitialized value for representation None can be overwritten by both
     217             :   // smi and tagged values. Doubles, however, would require a box allocation.
     218      296066 :   if (new_representation_.IsNone() || new_representation_.IsDouble()) {
     219       27628 :     return state_;  // Not done yet.
     220             :   }
     221             : 
     222             :   PropertyDetails old_details =
     223      536878 :       old_descriptors_->GetDetails(modified_descriptor_);
     224             :   Representation old_representation = old_details.representation();
     225      268442 :   if (!old_representation.IsNone()) {
     226       94364 :     return state_;  // Not done yet.
     227             :   }
     228             : 
     229             :   DCHECK_EQ(new_kind_, old_details.kind());
     230             :   DCHECK_EQ(new_attributes_, old_details.attributes());
     231             :   DCHECK_EQ(kField, old_details.location());
     232      174078 :   if (FLAG_trace_generalization) {
     233             :     old_map_->PrintGeneralization(
     234             :         isolate_, stdout, "uninitialized field", modified_descriptor_, old_nof_,
     235             :         old_nof_, false, old_representation, new_representation_,
     236             :         handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
     237           0 :         MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
     238             :   }
     239             :   Handle<Map> field_owner(
     240      522225 :       old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_);
     241             : 
     242             :   GeneralizeField(field_owner, modified_descriptor_, new_constness_,
     243      174073 :                   new_representation_, new_field_type_);
     244             :   // Check that the descriptor array was updated.
     245             :   DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
     246             :              .representation()
     247             :              .Equals(new_representation_));
     248             :   DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
     249             :              ->NowIs(new_field_type_));
     250             : 
     251      174075 :   result_map_ = old_map_;
     252      174075 :   state_ = kEnd;
     253      174075 :   return state_;  // Done.
     254             : }
     255             : 
     256         414 : bool MapUpdater::TrySaveIntegrityLevelTransitions() {
     257             :   // Skip integrity level transitions.
     258         414 :   integrity_source_map_ = old_map_;
     259        1269 :   while (!integrity_source_map_->is_extensible()) {
     260             :     integrity_source_map_ =
     261        1323 :         handle(Map::cast(integrity_source_map_->GetBackPointer()), isolate_);
     262             :   }
     263             : 
     264             :   // If there are some non-integrity-level transitions after the first
     265             :   // non-extensible transitions, e.g., if there were private symbols transitions
     266             :   // after the first integrity level transition, then we just bail out and
     267             :   // generalize all the fields.
     268         414 :   if (old_map_->NumberOfOwnDescriptors() !=
     269             :       integrity_source_map_->NumberOfOwnDescriptors()) {
     270             :     return false;
     271             :   }
     272             : 
     273             :   // Figure out the most restrictive integrity level transition (it should
     274             :   // be the last one in the transition tree).
     275         396 :   ReadOnlyRoots roots(isolate_);
     276             :   TransitionsAccessor transitions(
     277         792 :       isolate_, handle(Map::cast(old_map_->GetBackPointer()), isolate_));
     278         792 :   if (transitions.SearchSpecial(roots.frozen_symbol()) == *old_map_) {
     279          79 :     integrity_level_ = FROZEN;
     280         158 :     integrity_level_symbol_ = isolate_->factory()->frozen_symbol();
     281         634 :   } else if (transitions.SearchSpecial(roots.sealed_symbol()) == *old_map_) {
     282         193 :     integrity_level_ = SEALED;
     283         386 :     integrity_level_symbol_ = isolate_->factory()->sealed_symbol();
     284             :   } else {
     285         372 :     CHECK_EQ(transitions.SearchSpecial(roots.nonextensible_symbol()),
     286             :              *old_map_);
     287         124 :     integrity_level_ = NONE;
     288         248 :     integrity_level_symbol_ = isolate_->factory()->nonextensible_symbol();
     289             :   }
     290             : 
     291         396 :   has_integrity_level_transition_ = true;
     292             :   old_descriptors_ =
     293        1188 :       handle(integrity_source_map_->instance_descriptors(), isolate_);
     294         396 :   return true;
     295             : }
     296             : 
     297      420235 : MapUpdater::State MapUpdater::FindRootMap() {
     298             :   DCHECK_EQ(kInitialized, state_);
     299             :   // Check the state of the root map.
     300     1260707 :   root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
     301             :   ElementsKind from_kind = root_map_->elements_kind();
     302      420237 :   ElementsKind to_kind = new_elements_kind_;
     303             : 
     304      420238 :   if (root_map_->is_deprecated()) {
     305           0 :     state_ = kEnd;
     306             :     result_map_ = handle(
     307           0 :         JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
     308           0 :     result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind);
     309             :     DCHECK(result_map_->is_dictionary_map());
     310           0 :     return state_;
     311             :   }
     312             : 
     313      420237 :   if (!old_map_->EquivalentToForTransition(*root_map_)) {
     314          18 :     return CopyGeneralizeAllFields("GenAll_NotEquivalent");
     315      420220 :   } else if (old_map_->is_extensible() != root_map_->is_extensible()) {
     316             :     DCHECK(!old_map_->is_extensible());
     317             :     DCHECK(root_map_->is_extensible());
     318             :     // We have an integrity level transition in the tree, let us make a note
     319             :     // of that transition to be able to replay it later.
     320         414 :     if (!TrySaveIntegrityLevelTransitions()) {
     321          18 :       return CopyGeneralizeAllFields("GenAll_PrivateSymbolsOnNonExtensible");
     322             :     }
     323             : 
     324             :     // We want to build transitions to the original element kind (before
     325             :     // the seal transitions), so change {to_kind} accordingly.
     326             :     DCHECK(to_kind == DICTIONARY_ELEMENTS ||
     327             :            to_kind == SLOW_STRING_WRAPPER_ELEMENTS ||
     328             :            IsFixedTypedArrayElementsKind(to_kind));
     329             :     to_kind = integrity_source_map_->elements_kind();
     330             :   }
     331             : 
     332             :   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
     333      840404 :   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
     334       12688 :       to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
     335      432697 :       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
     336             :       !(IsTransitionableFastElementsKind(from_kind) &&
     337        6151 :         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
     338           0 :     return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
     339             :   }
     340             : 
     341             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     342      420202 :   if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
     343             :     PropertyDetails old_details =
     344       26938 :         old_descriptors_->GetDetails(modified_descriptor_);
     345       38932 :     if (old_details.kind() != new_kind_ ||
     346       11994 :         old_details.attributes() != new_attributes_) {
     347       30877 :       return CopyGeneralizeAllFields("GenAll_RootModification1");
     348             :     }
     349       11994 :     if (old_details.location() != kField) {
     350           0 :       return CopyGeneralizeAllFields("GenAll_RootModification2");
     351             :     }
     352             :     if (new_constness_ != old_details.constness() && !FLAG_modify_map_inplace) {
     353             :       return CopyGeneralizeAllFields("GenAll_RootModification3");
     354             :     }
     355       23988 :     if (!new_representation_.fits_into(old_details.representation())) {
     356         185 :       return CopyGeneralizeAllFields("GenAll_RootModification4");
     357             :     }
     358             : 
     359             :     DCHECK_EQ(kData, old_details.kind());
     360             :     DCHECK_EQ(kData, new_kind_);
     361             :     DCHECK_EQ(kField, new_location_);
     362             :     FieldType old_field_type =
     363       23618 :         old_descriptors_->GetFieldType(modified_descriptor_);
     364       11809 :     if (!new_field_type_->NowIs(old_field_type)) {
     365         804 :       return CopyGeneralizeAllFields("GenAll_RootModification5");
     366             :     }
     367             : 
     368             :     // Modify root map in-place.
     369       22010 :     if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
     370             :       DCHECK(old_map_->is_stable());
     371             :       DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
     372             :       GeneralizeField(old_map_, modified_descriptor_, new_constness_,
     373             :                       old_details.representation(),
     374       22010 :                       handle(old_field_type, isolate_));
     375             :     }
     376             :   }
     377             : 
     378             :   // From here on, use the map with correct elements kind as root map.
     379      404269 :   root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind);
     380      404268 :   state_ = kAtRootMap;
     381      404268 :   return state_;  // Not done yet.
     382             : }
     383             : 
     384      404266 : MapUpdater::State MapUpdater::FindTargetMap() {
     385             :   DCHECK_EQ(kAtRootMap, state_);
     386      404266 :   target_map_ = root_map_;
     387             : 
     388             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     389      922785 :   for (int i = root_nof; i < old_nof_; ++i) {
     390      530609 :     PropertyDetails old_details = GetDetails(i);
     391             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     392             :                          .SearchTransition(GetKey(i), old_details.kind(),
     393      530611 :                                            old_details.attributes());
     394      530611 :     if (transition.is_null()) break;
     395      529033 :     Handle<Map> tmp_map(transition, isolate_);
     396             : 
     397             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     398     1587099 :                                             isolate_);
     399             : 
     400             :     // Check if target map is incompatible.
     401      529034 :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     402             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     403             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     404     1587102 :     if (old_details.kind() == kAccessor &&
     405             :         !EqualImmutableValues(GetValue(i),
     406      553823 :                               tmp_descriptors->GetStrongValue(i))) {
     407             :       // TODO(ishell): mutable accessors are not implemented yet.
     408          41 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     409             :     }
     410             :     PropertyConstness tmp_constness = tmp_details.constness();
     411             :     if (!FLAG_modify_map_inplace &&
     412             :         !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
     413             :       break;
     414             :     }
     415      528993 :     if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
     416             :       break;
     417             :     }
     418      528992 :     Representation tmp_representation = tmp_details.representation();
     419     1057984 :     if (!old_details.representation().fits_into(tmp_representation)) {
     420             :       break;
     421             :     }
     422             : 
     423      518519 :     if (tmp_details.location() == kField) {
     424             :       Handle<FieldType> old_field_type =
     425      510297 :           GetOrComputeFieldType(i, old_details.location(), tmp_representation);
     426             :       PropertyConstness constness =
     427             :           FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
     428             :       GeneralizeField(tmp_map, i, constness, tmp_representation,
     429             :                       old_field_type);
     430             :     } else {
     431             :       // kDescriptor: Check that the value matches.
     432        8222 :       if (!EqualImmutableValues(GetValue(i),
     433       24666 :                                 tmp_descriptors->GetStrongValue(i))) {
     434             :         break;
     435             :       }
     436             :     }
     437             :     DCHECK(!tmp_map->is_deprecated());
     438      518519 :     target_map_ = tmp_map;
     439             :   }
     440             : 
     441             :   // Directly change the map if the target map is more general.
     442             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     443      404227 :   if (target_nof == old_nof_) {
     444             : #ifdef DEBUG
     445             :     if (modified_descriptor_ >= 0) {
     446             :       DescriptorArray target_descriptors = target_map_->instance_descriptors();
     447             :       PropertyDetails details =
     448             :           target_descriptors->GetDetails(modified_descriptor_);
     449             :       DCHECK_EQ(new_kind_, details.kind());
     450             :       DCHECK_EQ(GetDetails(modified_descriptor_).attributes(),
     451             :                 details.attributes());
     452             :       DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
     453             :       DCHECK_EQ(new_location_, details.location());
     454             :       DCHECK(new_representation_.fits_into(details.representation()));
     455             :       if (new_location_ == kField) {
     456             :         DCHECK_EQ(kField, details.location());
     457             :         DCHECK(new_field_type_->NowIs(
     458             :             target_descriptors->GetFieldType(modified_descriptor_)));
     459             :       } else {
     460             :         DCHECK(details.location() == kField ||
     461             :                EqualImmutableValues(
     462             :                    *new_value_,
     463             :                    target_descriptors->GetStrongValue(modified_descriptor_)));
     464             :       }
     465             :     }
     466             : #endif
     467      392174 :     if (*target_map_ != *old_map_) {
     468      596034 :       old_map_->NotifyLeafMapLayoutChange(isolate_);
     469             :     }
     470      392174 :     if (!has_integrity_level_transition_) {
     471      391854 :       result_map_ = target_map_;
     472      391854 :       state_ = kEnd;
     473      783818 :       return state_;  // Done.
     474             :     }
     475             : 
     476             :     // We try to replay the integrity level transition here.
     477             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     478         320 :                          .SearchSpecial(*integrity_level_symbol_);
     479         320 :     if (!transition.is_null()) {
     480         220 :       result_map_ = handle(transition, isolate_);
     481         110 :       state_ = kEnd;
     482         110 :       return state_;  // Done.
     483             :     }
     484             :   }
     485             : 
     486             :   // Find the last compatible target map in the transition tree.
     487       44366 :   for (int i = target_nof; i < old_nof_; ++i) {
     488       33683 :     PropertyDetails old_details = GetDetails(i);
     489             :     Map transition = TransitionsAccessor(isolate_, target_map_)
     490             :                          .SearchTransition(GetKey(i), old_details.kind(),
     491       33683 :                                            old_details.attributes());
     492       33683 :     if (transition.is_null()) break;
     493       32104 :     Handle<Map> tmp_map(transition, isolate_);
     494             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     495       96312 :                                             isolate_);
     496             : #ifdef DEBUG
     497             :     // Check that target map is compatible.
     498             :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     499             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     500             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     501             : #endif
     502       96312 :     if (old_details.kind() == kAccessor &&
     503             :         !EqualImmutableValues(GetValue(i),
     504       32149 :                               tmp_descriptors->GetStrongValue(i))) {
     505           0 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     506             :     }
     507             :     DCHECK(!tmp_map->is_deprecated());
     508       32104 :     target_map_ = tmp_map;
     509             :   }
     510             : 
     511       12262 :   state_ = kAtTargetMap;
     512       12262 :   return state_;  // Not done yet.
     513             : }
     514             : 
     515       12262 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
     516             :   InstanceType instance_type = old_map_->instance_type();
     517             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     518             :   Handle<DescriptorArray> target_descriptors(
     519       36786 :       target_map_->instance_descriptors(), isolate_);
     520             : 
     521             :   // Allocate a new descriptor array large enough to hold the required
     522             :   // descriptors, with minimally the exact same size as the old descriptor
     523             :   // array.
     524             :   int new_slack =
     525       36786 :       std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
     526       12262 :       old_nof_;
     527             :   Handle<DescriptorArray> new_descriptors =
     528       12262 :       DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
     529             :   DCHECK(new_descriptors->number_of_all_descriptors() >
     530             :              target_descriptors->number_of_all_descriptors() ||
     531             :          new_descriptors->number_of_slack_descriptors() > 0 ||
     532             :          new_descriptors->number_of_descriptors() ==
     533             :              old_descriptors_->number_of_descriptors());
     534             :   DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
     535             : 
     536             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     537             : 
     538             :   // Given that we passed root modification check in FindRootMap() so
     539             :   // the root descriptors are either not modified at all or already more
     540             :   // general than we requested. Take |root_nof| entries as is.
     541             :   // 0 -> |root_nof|
     542             :   int current_offset = 0;
     543       13564 :   for (int i = 0; i < root_nof; ++i) {
     544        1302 :     PropertyDetails old_details = old_descriptors_->GetDetails(i);
     545        1302 :     if (old_details.location() == kField) {
     546         352 :       current_offset += old_details.field_width_in_words();
     547             :     }
     548             :     Descriptor d(handle(GetKey(i), isolate_),
     549             :                  MaybeObjectHandle(old_descriptors_->GetValue(i), isolate_),
     550        5208 :                  old_details);
     551        1302 :     new_descriptors->Set(i, &d);
     552             :   }
     553             : 
     554             :   // Merge "updated" old_descriptor entries with target_descriptor entries.
     555             :   // |root_nof| -> |target_nof|
     556       66741 :   for (int i = root_nof; i < target_nof; ++i) {
     557       66741 :     Handle<Name> key(GetKey(i), isolate_);
     558       66741 :     PropertyDetails old_details = GetDetails(i);
     559       66741 :     PropertyDetails target_details = target_descriptors->GetDetails(i);
     560             : 
     561             :     PropertyKind next_kind = old_details.kind();
     562             :     PropertyAttributes next_attributes = old_details.attributes();
     563             :     DCHECK_EQ(next_kind, target_details.kind());
     564             :     DCHECK_EQ(next_attributes, target_details.attributes());
     565             : 
     566             :     PropertyConstness next_constness = GeneralizeConstness(
     567             :         old_details.constness(), target_details.constness());
     568             : 
     569             :     // Note: failed values equality check does not invalidate per-object
     570             :     // property constness.
     571             :     PropertyLocation next_location =
     572          53 :         old_details.location() == kField ||
     573             :                 target_details.location() == kField ||
     574             :                 !EqualImmutableValues(target_descriptors->GetStrongValue(i),
     575       66900 :                                       GetValue(i))
     576             :             ? kField
     577      133482 :             : kDescriptor;
     578             : 
     579             :     if (!FLAG_track_constant_fields && next_location == kField) {
     580             :       next_constness = PropertyConstness::kMutable;
     581             :     }
     582             :     // Ensure that mutable values are stored in fields.
     583             :     DCHECK_IMPLIES(next_constness == PropertyConstness::kMutable,
     584             :                    next_location == kField);
     585             : 
     586             :     Representation next_representation =
     587             :         old_details.representation().generalize(
     588       66741 :             target_details.representation());
     589             : 
     590       66741 :     if (next_location == kField) {
     591             :       Handle<FieldType> old_field_type =
     592       66688 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     593             : 
     594             :       Handle<FieldType> target_field_type =
     595             :           GetOrComputeFieldType(target_descriptors, i,
     596       66688 :                                 target_details.location(), next_representation);
     597             : 
     598             :       Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
     599             :           old_details.representation(), old_field_type, next_representation,
     600       66688 :           target_field_type, isolate_);
     601             : 
     602             :       Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
     603             :           isolate_, instance_type, &next_constness, &next_representation,
     604       66688 :           &next_field_type);
     605             : 
     606             :       MaybeObjectHandle wrapped_type(
     607       66688 :           Map::WrapFieldType(isolate_, next_field_type));
     608       66688 :       Descriptor d;
     609       66688 :       if (next_kind == kData) {
     610             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     611             :                                   next_constness, next_representation,
     612       66688 :                                   wrapped_type);
     613             :       } else {
     614             :         // TODO(ishell): mutable accessors are not implemented yet.
     615           0 :         UNIMPLEMENTED();
     616             :       }
     617       66688 :       current_offset += d.GetDetails().field_width_in_words();
     618       66688 :       new_descriptors->Set(i, &d);
     619             :     } else {
     620             :       DCHECK_EQ(kDescriptor, next_location);
     621             :       DCHECK_EQ(PropertyConstness::kConst, next_constness);
     622             : 
     623          53 :       Handle<Object> value(GetValue(i), isolate_);
     624          53 :       Descriptor d;
     625          53 :       if (next_kind == kData) {
     626             :         DCHECK(!FLAG_track_constant_fields);
     627           0 :         d = Descriptor::DataConstant(key, value, next_attributes);
     628             :       } else {
     629             :         DCHECK_EQ(kAccessor, next_kind);
     630          53 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     631             :       }
     632          53 :       new_descriptors->Set(i, &d);
     633             :     }
     634             :   }
     635             : 
     636             :   // Take "updated" old_descriptor entries.
     637             :   // |target_nof| -> |old_nof|
     638        2396 :   for (int i = target_nof; i < old_nof_; ++i) {
     639        2396 :     PropertyDetails old_details = GetDetails(i);
     640        2396 :     Handle<Name> key(GetKey(i), isolate_);
     641             : 
     642             :     PropertyKind next_kind = old_details.kind();
     643             :     PropertyAttributes next_attributes = old_details.attributes();
     644             :     PropertyConstness next_constness = old_details.constness();
     645             :     PropertyLocation next_location = old_details.location();
     646             :     Representation next_representation = old_details.representation();
     647             : 
     648        2396 :     Descriptor d;
     649        2396 :     if (next_location == kField) {
     650             :       Handle<FieldType> next_field_type =
     651        2319 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     652             : 
     653             :       // If the |new_elements_kind_| is still transitionable then the old map's
     654             :       // elements kind is also transitionable and therefore the old descriptors
     655             :       // array must already have generalized field type.
     656        2718 :       CHECK_IMPLIES(
     657             :           is_transitionable_fast_elements_kind_,
     658             :           Map::IsMostGeneralFieldType(next_representation, *next_field_type));
     659             : 
     660             :       MaybeObjectHandle wrapped_type(
     661        2319 :           Map::WrapFieldType(isolate_, next_field_type));
     662        2319 :       Descriptor d;
     663        2319 :       if (next_kind == kData) {
     664             :         DCHECK_IMPLIES(!FLAG_track_constant_fields,
     665             :                        next_constness == PropertyConstness::kMutable);
     666             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     667             :                                   next_constness, next_representation,
     668        2319 :                                   wrapped_type);
     669             :       } else {
     670             :         // TODO(ishell): mutable accessors are not implemented yet.
     671           0 :         UNIMPLEMENTED();
     672             :       }
     673        2319 :       current_offset += d.GetDetails().field_width_in_words();
     674        2319 :       new_descriptors->Set(i, &d);
     675             :     } else {
     676             :       DCHECK_EQ(kDescriptor, next_location);
     677             :       DCHECK_EQ(PropertyConstness::kConst, next_constness);
     678             : 
     679          77 :       Handle<Object> value(GetValue(i), isolate_);
     680          77 :       if (next_kind == kData) {
     681           0 :         d = Descriptor::DataConstant(key, value, next_attributes);
     682             :       } else {
     683             :         DCHECK_EQ(kAccessor, next_kind);
     684          77 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     685             :       }
     686          77 :       new_descriptors->Set(i, &d);
     687             :     }
     688             :   }
     689             : 
     690       12262 :   new_descriptors->Sort();
     691       12262 :   return new_descriptors;
     692             : }
     693             : 
     694       12262 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
     695             :   DisallowHeapAllocation no_allocation;
     696             : 
     697             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     698             :   Map current = *root_map_;
     699       46899 :   for (int i = root_nof; i < old_nof_; i++) {
     700       46689 :     Name name = descriptors->GetKey(i);
     701       46689 :     PropertyDetails details = descriptors->GetDetails(i);
     702             :     Map next =
     703             :         TransitionsAccessor(isolate_, current, &no_allocation)
     704       93378 :             .SearchTransition(name, details.kind(), details.attributes());
     705       46689 :     if (next.is_null()) break;
     706       45110 :     DescriptorArray next_descriptors = next->instance_descriptors();
     707             : 
     708       45110 :     PropertyDetails next_details = next_descriptors->GetDetails(i);
     709             :     DCHECK_EQ(details.kind(), next_details.kind());
     710             :     DCHECK_EQ(details.attributes(), next_details.attributes());
     711       45110 :     if (details.constness() != next_details.constness()) break;
     712       43091 :     if (details.location() != next_details.location()) break;
     713       43091 :     if (!details.representation().Equals(next_details.representation())) break;
     714             : 
     715       34637 :     if (next_details.location() == kField) {
     716       34599 :       FieldType next_field_type = next_descriptors->GetFieldType(i);
     717       34599 :       if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
     718             :         break;
     719             :       }
     720             :     } else {
     721          38 :       if (!EqualImmutableValues(descriptors->GetStrongValue(i),
     722          76 :                                 next_descriptors->GetStrongValue(i))) {
     723             :         break;
     724             :       }
     725             :     }
     726       34637 :     current = next;
     727             :   }
     728       24524 :   return handle(current, isolate_);
     729             : }
     730             : 
     731       12262 : MapUpdater::State MapUpdater::ConstructNewMap() {
     732       12262 :   Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
     733             : 
     734       12262 :   Handle<Map> split_map = FindSplitMap(new_descriptors);
     735             :   int split_nof = split_map->NumberOfOwnDescriptors();
     736       12262 :   if (old_nof_ == split_nof) {
     737         210 :     CHECK(has_integrity_level_transition_);
     738         210 :     state_ = kAtIntegrityLevelSource;
     739         210 :     return state_;
     740             :   }
     741             : 
     742       12052 :   PropertyDetails split_details = GetDetails(split_nof);
     743       12052 :   TransitionsAccessor transitions(isolate_, split_map);
     744             : 
     745             :   // Invalidate a transition target at |key|.
     746             :   Map maybe_transition = transitions.SearchTransition(
     747       12052 :       GetKey(split_nof), split_details.kind(), split_details.attributes());
     748       12052 :   if (!maybe_transition.is_null()) {
     749       10473 :     maybe_transition->DeprecateTransitionTree(isolate_);
     750             :   }
     751             : 
     752             :   // If |maybe_transition| is not nullptr then the transition array already
     753             :   // contains entry for given descriptor. This means that the transition
     754             :   // could be inserted regardless of whether transitions array is full or not.
     755       12052 :   if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
     756           5 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     757             :   }
     758             : 
     759       24094 :   old_map_->NotifyLeafMapLayoutChange(isolate_);
     760             : 
     761       12047 :   if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
     762             :     PropertyDetails old_details =
     763           0 :         old_descriptors_->GetDetails(modified_descriptor_);
     764             :     PropertyDetails new_details =
     765           0 :         new_descriptors->GetDetails(modified_descriptor_);
     766           0 :     MaybeHandle<FieldType> old_field_type;
     767           0 :     MaybeHandle<FieldType> new_field_type;
     768           0 :     MaybeHandle<Object> old_value;
     769           0 :     MaybeHandle<Object> new_value;
     770           0 :     if (old_details.location() == kField) {
     771             :       old_field_type = handle(
     772           0 :           old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
     773             :     } else {
     774             :       old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_),
     775           0 :                          isolate_);
     776             :     }
     777           0 :     if (new_details.location() == kField) {
     778             :       new_field_type =
     779           0 :           handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
     780             :     } else {
     781             :       new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_),
     782           0 :                          isolate_);
     783             :     }
     784             : 
     785             :     old_map_->PrintGeneralization(
     786             :         isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_,
     787           0 :         old_details.location() == kDescriptor && new_location_ == kField,
     788             :         old_details.representation(), new_details.representation(),
     789           0 :         old_field_type, old_value, new_field_type, new_value);
     790             :   }
     791             : 
     792             :   Handle<LayoutDescriptor> new_layout_descriptor =
     793       12047 :       LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_);
     794             : 
     795             :   Handle<Map> new_map = Map::AddMissingTransitions(
     796       12047 :       isolate_, split_map, new_descriptors, new_layout_descriptor);
     797             : 
     798             :   // Deprecated part of the transition tree is no longer reachable, so replace
     799             :   // current instance descriptors in the "survived" part of the tree with
     800             :   // the new descriptors to maintain descriptors sharing invariant.
     801             :   split_map->ReplaceDescriptors(isolate_, *new_descriptors,
     802       24094 :                                 *new_layout_descriptor);
     803             : 
     804       12047 :   if (has_integrity_level_transition_) {
     805          76 :     target_map_ = new_map;
     806          76 :     state_ = kAtIntegrityLevelSource;
     807             :   } else {
     808       11971 :     result_map_ = new_map;
     809       11971 :     state_ = kEnd;
     810             :   }
     811       12047 :   return state_;  // Done.
     812             : }
     813             : 
     814         286 : MapUpdater::State MapUpdater::ConstructNewMapWithIntegrityLevelTransition() {
     815             :   DCHECK_EQ(kAtIntegrityLevelSource, state_);
     816             : 
     817         286 :   TransitionsAccessor transitions(isolate_, target_map_);
     818         286 :   if (!transitions.CanHaveMoreTransitions()) {
     819           0 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     820             :   }
     821             : 
     822             :   result_map_ = Map::CopyForPreventExtensions(
     823             :       isolate_, target_map_, integrity_level_, integrity_level_symbol_,
     824         286 :       "CopyForPreventExtensions");
     825             : 
     826         286 :   state_ = kEnd;
     827         286 :   return state_;
     828             : }
     829             : 
     830             : }  // namespace internal
     831      178779 : }  // namespace v8

Generated by: LCOV version 1.10