• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EqualImmutableValues(Object * obj1,Object * obj2)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 
GetKey(int descriptor) const27 Name* MapUpdater::GetKey(int descriptor) const {
28   return old_descriptors_->GetKey(descriptor);
29 }
30 
GetDetails(int descriptor) const31 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 
GetValue(int descriptor) const40 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 
GetFieldType(int descriptor) const50 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 
GetOrComputeFieldType(int descriptor,PropertyLocation location,Representation representation) const60 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 
GetOrComputeFieldType(Handle<DescriptorArray> descriptors,int descriptor,PropertyLocation location,Representation representation)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 
ReconfigureToDataField(int descriptor,PropertyAttributes attributes,PropertyConstness constness,Representation representation,Handle<FieldType> field_type)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 
ReconfigureElementsKind(ElementsKind elements_kind)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 
Update()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 
GeneralizeField(Handle<Map> map,int modify_index,PropertyConstness new_constness,Representation new_representation,Handle<FieldType> new_field_type)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 
CopyGeneralizeAllFields(const char * reason)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 
TryRecofigureToDataFieldInplace()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 
FindRootMap()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 
FindTargetMap()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 
BuildDescriptorArray()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 
FindSplitMap(Handle<DescriptorArray> descriptors)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 
ConstructNewMap()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