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