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