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
14namespace v8 {
15namespace internal {
16
17namespace {
18
19inline 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
27Name* MapUpdater::GetKey(int descriptor) const {
28  return old_descriptors_->GetKey(descriptor);
29}
30
31PropertyDetails 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
40Object* 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
50FieldType* 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
60Handle<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
73Handle<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
86Handle<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
134Handle<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
145Handle<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
156void 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
166MapUpdater::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
174MapUpdater::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
218MapUpdater::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
273MapUpdater::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
383Handle<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
543Handle<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
579MapUpdater::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