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