LCOV - code coverage report
Current view: top level - src - map-updater.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 271 307 88.3 %
Date: 2019-04-17 Functions: 20 21 95.2 %

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

Generated by: LCOV version 1.10