LCOV - code coverage report
Current view: top level - src - map-updater.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 217 241 90.0 %
Date: 2017-04-26 Functions: 16 17 94.1 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/map-updater.h"
       6             : 
       7             : #include "src/field-type.h"
       8             : #include "src/handles.h"
       9             : #include "src/isolate.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/objects.h"
      12             : #include "src/transitions.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : namespace {
      18             : 
      19             : inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
      20       32387 :   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     1447341 : Name* MapUpdater::GetKey(int descriptor) const {
      28     1447341 :   return old_descriptors_->GetKey(descriptor);
      29             : }
      30             : 
      31     1442253 : PropertyDetails MapUpdater::GetDetails(int descriptor) const {
      32             :   DCHECK_LE(0, descriptor);
      33     1442253 :   if (descriptor == modified_descriptor_) {
      34             :     return PropertyDetails(new_kind_, new_attributes_, new_location_,
      35     1646126 :                            new_constness_, new_representation_);
      36             :   }
      37      619190 :   return old_descriptors_->GetDetails(descriptor);
      38             : }
      39             : 
      40       50260 : Object* MapUpdater::GetValue(int descriptor) const {
      41             :   DCHECK_LE(0, descriptor);
      42       50260 :   if (descriptor == modified_descriptor_) {
      43             :     DCHECK_EQ(kDescriptor, new_location_);
      44           0 :     return *new_value_;
      45             :   }
      46             :   DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
      47       50260 :   return old_descriptors_->GetValue(descriptor);
      48             : }
      49             : 
      50      839454 : FieldType* MapUpdater::GetFieldType(int descriptor) const {
      51             :   DCHECK_LE(0, descriptor);
      52      839454 :   if (descriptor == modified_descriptor_) {
      53             :     DCHECK_EQ(kField, new_location_);
      54      324850 :     return *new_field_type_;
      55             :   }
      56             :   DCHECK_EQ(kField, GetDetails(descriptor).location());
      57      514604 :   return old_descriptors_->GetFieldType(descriptor);
      58             : }
      59             : 
      60      840736 : 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      840736 :   if (location == kField) {
      67      839454 :     return handle(GetFieldType(descriptor), isolate_);
      68             :   } else {
      69        1282 :     return GetValue(descriptor)->OptimalType(isolate_, representation);
      70             :   }
      71             : }
      72             : 
      73     1531325 : 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     1531325 :   if (location == kField) {
      79     1651906 :     return handle(descriptors->GetFieldType(descriptor), isolate_);
      80             :   } else {
      81             :     return descriptors->GetValue(descriptor)
      82     1410744 :         ->OptimalType(isolate_, representation);
      83             :   }
      84             : }
      85             : 
      86     1183448 : 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     1183448 :   modified_descriptor_ = descriptor;
      95     1183448 :   new_kind_ = kData;
      96     1183448 :   new_attributes_ = attributes;
      97     1183448 :   new_location_ = kField;
      98             : 
      99             :   PropertyDetails old_details =
     100     1183448 :       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     1183448 :   if (old_details.kind() == new_kind_) {
     105     1160156 :     new_constness_ = GeneralizeConstness(constness, old_details.constness());
     106             : 
     107     1160156 :     Representation old_representation = old_details.representation();
     108     1160156 :     new_representation_ = representation.generalize(old_representation);
     109             : 
     110             :     Handle<FieldType> old_field_type =
     111             :         GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
     112     1160156 :                               old_details.location(), new_representation_);
     113             : 
     114             :     new_field_type_ =
     115             :         Map::GeneralizeFieldType(old_representation, old_field_type,
     116     1160156 :                                  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       23292 :     new_constness_ = kMutable;
     122       23292 :     new_representation_ = representation;
     123       23292 :     new_field_type_ = field_type;
     124             :   }
     125             : 
     126     1183448 :   if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_;
     127      782110 :   if (FindRootMap() == kEnd) return result_map_;
     128      325334 :   if (FindTargetMap() == kEnd) return result_map_;
     129      166181 :   ConstructNewMap();
     130             :   DCHECK_EQ(kEnd, state_);
     131      166181 :   return result_map_;
     132             : }
     133             : 
     134      652950 : Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
     135             :   DCHECK_EQ(kInitialized, state_);
     136      652950 :   new_elements_kind_ = elements_kind;
     137             : 
     138      652950 :   if (FindRootMap() == kEnd) return result_map_;
     139      652950 :   if (FindTargetMap() == kEnd) return result_map_;
     140        1092 :   ConstructNewMap();
     141             :   DCHECK_EQ(kEnd, state_);
     142        1092 :   return result_map_;
     143             : }
     144             : 
     145       10342 : Handle<Map> MapUpdater::Update() {
     146             :   DCHECK_EQ(kInitialized, state_);
     147             :   DCHECK(old_map_->is_deprecated());
     148             : 
     149       10342 :   if (FindRootMap() == kEnd) return result_map_;
     150       10258 :   if (FindTargetMap() == kEnd) return result_map_;
     151         240 :   ConstructNewMap();
     152             :   DCHECK_EQ(kEnd, state_);
     153         240 :   return result_map_;
     154             : }
     155             : 
     156           0 : 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      867911 :                        new_field_type);
     162             : 
     163             :   DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
     164           0 : }
     165             : 
     166      456886 : MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) {
     167             :   result_map_ = Map::CopyGeneralizeAllFields(old_map_, new_elements_kind_,
     168             :                                              modified_descriptor_, new_kind_,
     169      456886 :                                              new_attributes_, reason);
     170      456886 :   state_ = kEnd;
     171      456886 :   return state_;  // Done.
     172             : }
     173             : 
     174     1183448 : 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     1183448 :   if (new_representation_.IsNone() || new_representation_.IsDouble()) {
     181       30082 :     return state_;  // Not done yet.
     182             :   }
     183             : 
     184             :   PropertyDetails old_details =
     185     2306732 :       old_descriptors_->GetDetails(modified_descriptor_);
     186             :   Representation old_representation = old_details.representation();
     187     1153366 :   if (!old_representation.IsNone()) {
     188      752028 :     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      401338 :   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           0 :         MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
     200             :   }
     201             :   Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_),
     202      802676 :                           isolate_);
     203             : 
     204             :   GeneralizeField(field_owner, modified_descriptor_, new_constness_,
     205      401338 :                   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      401338 :   result_map_ = old_map_;
     214      401338 :   state_ = kEnd;
     215      401338 :   return state_;  // Done.
     216             : }
     217             : 
     218     1445402 : MapUpdater::State MapUpdater::FindRootMap() {
     219             :   DCHECK_EQ(kInitialized, state_);
     220             :   // Check the state of the root map.
     221     4336206 :   root_map_ = handle(old_map_->FindRootMap(), isolate_);
     222             :   ElementsKind from_kind = root_map_->elements_kind();
     223     1445402 :   ElementsKind to_kind = new_elements_kind_;
     224     1445402 :   if (root_map_->is_deprecated()) {
     225           0 :     state_ = kEnd;
     226             :     result_map_ = handle(
     227           0 :         JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
     228           0 :     if (from_kind != to_kind) {
     229           0 :       result_map_ = Map::AsElementsKind(result_map_, to_kind);
     230             :     }
     231             :     DCHECK(result_map_->is_dictionary_map());
     232           0 :     return state_;
     233             :   }
     234             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     235     1445402 :   if (!old_map_->EquivalentToForTransition(*root_map_)) {
     236         120 :     return CopyGeneralizeAllFields("GenAll_NotEquivalent");
     237             :   }
     238             : 
     239             :   // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS.
     240     2890564 :   if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
     241      379970 :       to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
     242     1824964 :       to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
     243             :       !(IsTransitionableFastElementsKind(from_kind) &&
     244      189697 :         IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
     245           0 :     return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition");
     246             :   }
     247             : 
     248     1445282 :   if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
     249             :     PropertyDetails old_details =
     250      457298 :         old_descriptors_->GetDetails(modified_descriptor_);
     251      891408 :     if (old_details.kind() != new_kind_ ||
     252      434110 :         old_details.attributes() != new_attributes_) {
     253       23188 :       return CopyGeneralizeAllFields("GenAll_RootModification1");
     254             :     }
     255      434110 :     if (old_details.location() != kField) {
     256      432388 :       return CopyGeneralizeAllFields("GenAll_RootModification2");
     257             :     }
     258        3444 :     if (new_constness_ != old_details.constness() &&
     259             :         (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
     260           0 :       return CopyGeneralizeAllFields("GenAll_RootModification3");
     261             :     }
     262        3444 :     if (!new_representation_.fits_into(old_details.representation())) {
     263          30 :       return CopyGeneralizeAllFields("GenAll_RootModification4");
     264             :     }
     265             : 
     266             :     DCHECK_EQ(kData, old_details.kind());
     267             :     DCHECK_EQ(kData, new_kind_);
     268             :     DCHECK_EQ(kField, new_location_);
     269             :     FieldType* old_field_type =
     270        3384 :         old_descriptors_->GetFieldType(modified_descriptor_);
     271        1692 :     if (!new_field_type_->NowIs(old_field_type)) {
     272        1134 :       return CopyGeneralizeAllFields("GenAll_RootModification5");
     273             :     }
     274             : 
     275             :     // Modify root map in-place.
     276             :     if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
     277             :       // Only prototype root maps are allowed to be updated in-place.
     278             :       // TODO(ishell): fix all the stubs that use prototype map check to
     279             :       // ensure that the prototype was not modified.
     280             :       DCHECK(old_map_->is_prototype_map());
     281             :       DCHECK(old_map_->is_stable());
     282             :       DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
     283             :       GeneralizeField(old_map_, modified_descriptor_, new_constness_,
     284             :                       old_details.representation(),
     285             :                       handle(old_field_type, isolate_));
     286             :     }
     287             :   }
     288             : 
     289             :   // From here on, use the map with correct elements kind as root map.
     290      988542 :   if (from_kind != to_kind) {
     291      653956 :     root_map_ = Map::AsElementsKind(root_map_, to_kind);
     292             :   }
     293      988542 :   state_ = kAtRootMap;
     294      988542 :   return state_;  // Not done yet.
     295             : }
     296             : 
     297      988542 : MapUpdater::State MapUpdater::FindTargetMap() {
     298             :   DCHECK_EQ(kAtRootMap, state_);
     299      988542 :   target_map_ = root_map_;
     300             : 
     301             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     302     1460676 :   for (int i = root_nof; i < old_nof_; ++i) {
     303      639667 :     PropertyDetails old_details = GetDetails(i);
     304             :     Map* transition = TransitionArray::SearchTransition(
     305     1279334 :         *target_map_, old_details.kind(), GetKey(i), old_details.attributes());
     306      639667 :     if (transition == NULL) break;
     307      637450 :     Handle<Map> tmp_map(transition, isolate_);
     308             : 
     309             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     310      637450 :                                             isolate_);
     311             : 
     312             :     // Check if target map is incompatible.
     313      637450 :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     314             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     315             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     316      637628 :     if (old_details.kind() == kAccessor &&
     317         178 :         !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
     318             :       // TODO(ishell): mutable accessors are not implemented yet.
     319          20 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     320             :     }
     321             :     PropertyConstness tmp_constness = tmp_details.constness();
     322      637430 :     if (!FLAG_modify_map_inplace &&
     323             :         !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
     324             :       break;
     325             :     }
     326      501000 :     if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
     327             :       break;
     328             :     }
     329      500980 :     Representation tmp_representation = tmp_details.representation();
     330     1001960 :     if (!old_details.representation().fits_into(tmp_representation)) {
     331             :       break;
     332             :     }
     333             : 
     334      472161 :     if (tmp_details.location() == kField) {
     335             :       Handle<FieldType> old_field_type =
     336      466573 :           GetOrComputeFieldType(i, old_details.location(), tmp_representation);
     337             :       PropertyConstness constness =
     338             :           FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
     339             :       GeneralizeField(tmp_map, i, constness, tmp_representation,
     340             :                       old_field_type);
     341             :     } else {
     342             :       // kDescriptor: Check that the value matches.
     343       11176 :       if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
     344             :         break;
     345             :       }
     346             :     }
     347             :     DCHECK(!tmp_map->is_deprecated());
     348      472134 :     target_map_ = tmp_map;
     349             :   }
     350             : 
     351             :   // Directly change the map if the target map is more general.
     352             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     353      988522 :   if (target_nof == old_nof_) {
     354             : #ifdef DEBUG
     355             :     if (modified_descriptor_ >= 0) {
     356             :       DescriptorArray* target_descriptors = target_map_->instance_descriptors();
     357             :       PropertyDetails details =
     358             :           target_descriptors->GetDetails(modified_descriptor_);
     359             :       DCHECK_EQ(new_kind_, details.kind());
     360             :       DCHECK_EQ(new_attributes_, details.attributes());
     361             :       DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
     362             :       DCHECK_EQ(new_location_, details.location());
     363             :       DCHECK(new_representation_.fits_into(details.representation()));
     364             :       if (new_location_ == kField) {
     365             :         DCHECK_EQ(kField, details.location());
     366             :         DCHECK(new_field_type_->NowIs(
     367             :             target_descriptors->GetFieldType(modified_descriptor_)));
     368             :       } else {
     369             :         DCHECK(details.location() == kField ||
     370             :                EqualImmutableValues(*new_value_, target_descriptors->GetValue(
     371             :                                                      modified_descriptor_)));
     372             :       }
     373             :     }
     374             : #endif
     375      821009 :     if (*target_map_ != *old_map_) {
     376      662877 :       old_map_->NotifyLeafMapLayoutChange();
     377             :     }
     378      821009 :     result_map_ = target_map_;
     379      821009 :     state_ = kEnd;
     380      821009 :     return state_;  // Done.
     381             :   }
     382             : 
     383             :   // Find the last compatible target map in the transition tree.
     384      237064 :   for (int i = target_nof; i < old_nof_; ++i) {
     385      239281 :     PropertyDetails old_details = GetDetails(i);
     386             :     Map* transition = TransitionArray::SearchTransition(
     387      478562 :         *target_map_, old_details.kind(), GetKey(i), old_details.attributes());
     388      239281 :     if (transition == NULL) break;
     389      237064 :     Handle<Map> tmp_map(transition, isolate_);
     390             :     Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
     391      237064 :                                             isolate_);
     392             : #ifdef DEBUG
     393             :     // Check that target map is compatible.
     394             :     PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
     395             :     DCHECK_EQ(old_details.kind(), tmp_details.kind());
     396             :     DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
     397             : #endif
     398      237096 :     if (old_details.kind() == kAccessor &&
     399          32 :         !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) {
     400           0 :       return CopyGeneralizeAllFields("GenAll_Incompatible");
     401             :     }
     402             :     DCHECK(!tmp_map->is_deprecated());
     403      237064 :     target_map_ = tmp_map;
     404             :   }
     405             : 
     406      167513 :   state_ = kAtTargetMap;
     407      167513 :   return state_;  // Not done yet.
     408             : }
     409             : 
     410      167513 : Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
     411             :   int target_nof = target_map_->NumberOfOwnDescriptors();
     412             :   Handle<DescriptorArray> target_descriptors(
     413      167513 :       target_map_->instance_descriptors(), isolate_);
     414             : 
     415             :   // Allocate a new descriptor array large enough to hold the required
     416             :   // descriptors, with minimally the exact same size as the old descriptor
     417             :   // array.
     418             :   int new_slack =
     419      335026 :       Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_;
     420             :   Handle<DescriptorArray> new_descriptors =
     421      167513 :       DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
     422             :   DCHECK(new_descriptors->length() > target_descriptors->length() ||
     423             :          new_descriptors->NumberOfSlackDescriptors() > 0 ||
     424             :          new_descriptors->number_of_descriptors() ==
     425             :              old_descriptors_->number_of_descriptors());
     426             :   DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
     427             : 
     428             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     429             : 
     430             :   // Given that we passed root modification check in FindRootMap() so
     431             :   // the root descriptors are either not modified at all or already more
     432             :   // general than we requested. Take |root_nof| entries as is.
     433             :   // 0 -> |root_nof|
     434             :   int current_offset = 0;
     435      172601 :   for (int i = 0; i < root_nof; ++i) {
     436        5088 :     PropertyDetails old_details = old_descriptors_->GetDetails(i);
     437        5088 :     if (old_details.location() == kField) {
     438         330 :       current_offset += old_details.field_width_in_words();
     439             :     }
     440             :     Descriptor d(handle(GetKey(i), isolate_),
     441       10176 :                  handle(old_descriptors_->GetValue(i), isolate_), old_details);
     442        5088 :     new_descriptors->Set(i, &d);
     443             :   }
     444             : 
     445             :   // Merge "updated" old_descriptor entries with target_descriptor entries.
     446             :   // |root_nof| -> |target_nof|
     447      392621 :   for (int i = root_nof; i < target_nof; ++i) {
     448      392621 :     Handle<Name> key(GetKey(i), isolate_);
     449      392621 :     PropertyDetails old_details = GetDetails(i);
     450      392621 :     PropertyDetails target_details = target_descriptors->GetDetails(i);
     451             : 
     452             :     PropertyKind next_kind = old_details.kind();
     453             :     PropertyAttributes next_attributes = old_details.attributes();
     454             :     DCHECK_EQ(next_kind, target_details.kind());
     455             :     DCHECK_EQ(next_attributes, target_details.attributes());
     456             : 
     457             :     PropertyConstness next_constness = GeneralizeConstness(
     458             :         old_details.constness(), target_details.constness());
     459             : 
     460             :     // Note: failed values equality check does not invalidate per-object
     461             :     // property constness.
     462             :     PropertyLocation next_location =
     463       21572 :         old_details.location() == kField ||
     464             :                 target_details.location() == kField ||
     465             :                 !EqualImmutableValues(target_descriptors->GetValue(i),
     466       21551 :                                       GetValue(i))
     467             :             ? kField
     468      414172 :             : kDescriptor;
     469             : 
     470      392621 :     if (!FLAG_track_constant_fields && next_location == kField) {
     471             :       next_constness = kMutable;
     472             :     }
     473             :     // Ensure that mutable values are stored in fields.
     474             :     DCHECK_IMPLIES(next_constness == kMutable, next_location == kField);
     475             : 
     476             :     Representation next_representation =
     477             :         old_details.representation().generalize(
     478      392621 :             target_details.representation());
     479             : 
     480      392621 :     if (next_location == kField) {
     481             :       Handle<FieldType> old_field_type =
     482      371169 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     483             : 
     484             :       Handle<FieldType> target_field_type =
     485             :           GetOrComputeFieldType(target_descriptors, i,
     486      371169 :                                 target_details.location(), next_representation);
     487             : 
     488             :       Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
     489             :           old_details.representation(), old_field_type, next_representation,
     490      371169 :           target_field_type, isolate_);
     491             : 
     492      371169 :       Handle<Object> wrapped_type(Map::WrapFieldType(next_field_type));
     493             :       Descriptor d;
     494      371169 :       if (next_kind == kData) {
     495             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     496             :                                   next_constness, next_representation,
     497      371169 :                                   wrapped_type);
     498             :       } else {
     499             :         // TODO(ishell): mutable accessors are not implemented yet.
     500           0 :         UNIMPLEMENTED();
     501             :       }
     502      371169 :       current_offset += d.GetDetails().field_width_in_words();
     503      371169 :       new_descriptors->Set(i, &d);
     504             :     } else {
     505             :       DCHECK_EQ(kDescriptor, next_location);
     506             :       DCHECK_EQ(kConst, next_constness);
     507             : 
     508       21452 :       Handle<Object> value(GetValue(i), isolate_);
     509             :       Descriptor d;
     510       21452 :       if (next_kind == kData) {
     511             :         DCHECK(!FLAG_track_constant_fields);
     512       21352 :         d = Descriptor::DataConstant(key, value, next_attributes);
     513             :       } else {
     514             :         DCHECK_EQ(kAccessor, next_kind);
     515         100 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     516             :       }
     517       21452 :       new_descriptors->Set(i, &d);
     518             :     }
     519             :   }
     520             : 
     521             :   // Take "updated" old_descriptor entries.
     522             :   // |target_nof| -> |old_nof|
     523        3171 :   for (int i = target_nof; i < old_nof_; ++i) {
     524        3171 :     PropertyDetails old_details = GetDetails(i);
     525        3171 :     Handle<Name> key(GetKey(i), isolate_);
     526             : 
     527             :     PropertyKind next_kind = old_details.kind();
     528             :     PropertyAttributes next_attributes = old_details.attributes();
     529             :     PropertyConstness next_constness = old_details.constness();
     530             :     PropertyLocation next_location = old_details.location();
     531        3171 :     Representation next_representation = old_details.representation();
     532             : 
     533             :     Descriptor d;
     534        3171 :     if (next_location == kField) {
     535             :       Handle<FieldType> old_field_type =
     536        2994 :           GetOrComputeFieldType(i, old_details.location(), next_representation);
     537             : 
     538        2994 :       Handle<Object> wrapped_type(Map::WrapFieldType(old_field_type));
     539             :       Descriptor d;
     540        2994 :       if (next_kind == kData) {
     541             :         DCHECK_IMPLIES(!FLAG_track_constant_fields, next_constness == kMutable);
     542             :         d = Descriptor::DataField(key, current_offset, next_attributes,
     543             :                                   next_constness, next_representation,
     544        2994 :                                   wrapped_type);
     545             :       } else {
     546             :         // TODO(ishell): mutable accessors are not implemented yet.
     547           0 :         UNIMPLEMENTED();
     548             :       }
     549        2994 :       current_offset += d.GetDetails().field_width_in_words();
     550        2994 :       new_descriptors->Set(i, &d);
     551             :     } else {
     552             :       DCHECK_EQ(kDescriptor, next_location);
     553             :       DCHECK_EQ(kConst, next_constness);
     554             : 
     555         177 :       Handle<Object> value(GetValue(i), isolate_);
     556         177 :       if (next_kind == kData) {
     557          71 :         d = Descriptor::DataConstant(key, value, next_attributes);
     558             :       } else {
     559             :         DCHECK_EQ(kAccessor, next_kind);
     560         106 :         d = Descriptor::AccessorConstant(key, value, next_attributes);
     561             :       }
     562         177 :       new_descriptors->Set(i, &d);
     563             :     }
     564             :   }
     565             : 
     566      167513 :   new_descriptors->Sort();
     567      167513 :   return new_descriptors;
     568             : }
     569             : 
     570      167513 : Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
     571             :   DisallowHeapAllocation no_allocation;
     572             : 
     573             :   int root_nof = root_map_->NumberOfOwnDescriptors();
     574             :   Map* current = *root_map_;
     575      323070 :   for (int i = root_nof; i < old_nof_; i++) {
     576             :     Name* name = descriptors->GetKey(i);
     577      323070 :     PropertyDetails details = descriptors->GetDetails(i);
     578             :     Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
     579      323070 :                                                   details.attributes());
     580      323070 :     if (next == NULL) break;
     581             :     DescriptorArray* next_descriptors = next->instance_descriptors();
     582             : 
     583      320853 :     PropertyDetails next_details = next_descriptors->GetDetails(i);
     584             :     DCHECK_EQ(details.kind(), next_details.kind());
     585             :     DCHECK_EQ(details.attributes(), next_details.attributes());
     586      320853 :     if (details.constness() != next_details.constness()) break;
     587      184376 :     if (details.location() != next_details.location()) break;
     588      184376 :     if (!details.representation().Equals(next_details.representation())) break;
     589             : 
     590      155557 :     if (next_details.location() == kField) {
     591      150519 :       FieldType* next_field_type = next_descriptors->GetFieldType(i);
     592      150519 :       if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) {
     593             :         break;
     594             :       }
     595             :     } else {
     596        5038 :       if (!EqualImmutableValues(descriptors->GetValue(i),
     597             :                                 next_descriptors->GetValue(i))) {
     598             :         break;
     599             :       }
     600             :     }
     601             :     current = next;
     602             :   }
     603      335026 :   return handle(current, isolate_);
     604             : }
     605             : 
     606      167513 : MapUpdater::State MapUpdater::ConstructNewMap() {
     607      167513 :   Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
     608             : 
     609      167513 :   Handle<Map> split_map = FindSplitMap(new_descriptors);
     610             :   int split_nof = split_map->NumberOfOwnDescriptors();
     611             :   DCHECK_NE(old_nof_, split_nof);
     612             : 
     613      167513 :   PropertyDetails split_details = GetDetails(split_nof);
     614             : 
     615             :   // Invalidate a transition target at |key|.
     616             :   Map* maybe_transition = TransitionArray::SearchTransition(
     617             :       *split_map, split_details.kind(), GetKey(split_nof),
     618      335026 :       split_details.attributes());
     619      167513 :   if (maybe_transition != NULL) {
     620      165296 :     maybe_transition->DeprecateTransitionTree();
     621             :   }
     622             : 
     623             :   // If |maybe_transition| is not NULL then the transition array already
     624             :   // contains entry for given descriptor. This means that the transition
     625             :   // could be inserted regardless of whether transitions array is full or not.
     626      169730 :   if (maybe_transition == NULL &&
     627        2217 :       !TransitionArray::CanHaveMoreTransitions(split_map)) {
     628           6 :     return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions");
     629             :   }
     630             : 
     631      167507 :   old_map_->NotifyLeafMapLayoutChange();
     632             : 
     633      167507 :   if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
     634             :     PropertyDetails old_details =
     635           0 :         old_descriptors_->GetDetails(modified_descriptor_);
     636             :     PropertyDetails new_details =
     637           0 :         new_descriptors->GetDetails(modified_descriptor_);
     638             :     MaybeHandle<FieldType> old_field_type;
     639             :     MaybeHandle<FieldType> new_field_type;
     640             :     MaybeHandle<Object> old_value;
     641             :     MaybeHandle<Object> new_value;
     642           0 :     if (old_details.location() == kField) {
     643             :       old_field_type = handle(
     644           0 :           old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
     645             :     } else {
     646             :       old_value =
     647           0 :           handle(old_descriptors_->GetValue(modified_descriptor_), isolate_);
     648             :     }
     649           0 :     if (new_details.location() == kField) {
     650             :       new_field_type =
     651           0 :           handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
     652             :     } else {
     653             :       new_value =
     654           0 :           handle(new_descriptors->GetValue(modified_descriptor_), isolate_);
     655             :     }
     656             : 
     657             :     old_map_->PrintGeneralization(
     658             :         stdout, "", modified_descriptor_, split_nof, old_nof_,
     659           0 :         old_details.location() == kDescriptor && new_location_ == kField,
     660             :         old_details.representation(), new_details.representation(),
     661           0 :         old_field_type, old_value, new_field_type, new_value);
     662             :   }
     663             : 
     664             :   Handle<LayoutDescriptor> new_layout_descriptor =
     665      167507 :       LayoutDescriptor::New(split_map, new_descriptors, old_nof_);
     666             : 
     667             :   Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors,
     668      167507 :                                                    new_layout_descriptor);
     669             : 
     670             :   // Deprecated part of the transition tree is no longer reachable, so replace
     671             :   // current instance descriptors in the "survived" part of the tree with
     672             :   // the new descriptors to maintain descriptors sharing invariant.
     673      167507 :   split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor);
     674             : 
     675      167507 :   result_map_ = new_map;
     676      167507 :   state_ = kEnd;
     677      167507 :   return state_;  // Done.
     678             : }
     679             : 
     680             : }  // namespace internal
     681             : }  // namespace v8

Generated by: LCOV version 1.10