5 #include "src/map-updater.h" 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" 19 inline bool EqualImmutableValues(Object* obj1, Object* obj2) {
20 if (obj1 == obj2)
return true;
27 MapUpdater::MapUpdater(Isolate* isolate, Handle<Map> old_map)
30 old_descriptors_(old_map->instance_descriptors(), isolate_),
31 old_nof_(old_map_->NumberOfOwnDescriptors()),
32 new_elements_kind_(old_map_->elements_kind()),
33 is_transitionable_fast_elements_kind_(
34 IsTransitionableFastElementsKind(new_elements_kind_)) {
36 DCHECK(!old_map->FindRootMap(isolate)
38 ->IsFunctionTemplateInfo());
41 Name MapUpdater::GetKey(
int descriptor)
const {
42 return old_descriptors_->GetKey(descriptor);
45 PropertyDetails MapUpdater::GetDetails(
int descriptor)
const {
46 DCHECK_LE(0, descriptor);
47 if (descriptor == modified_descriptor_) {
48 return PropertyDetails(new_kind_, new_attributes_, new_location_,
49 new_constness_, new_representation_);
51 return old_descriptors_->GetDetails(descriptor);
54 Object* MapUpdater::GetValue(
int descriptor)
const {
55 DCHECK_LE(0, descriptor);
56 if (descriptor == modified_descriptor_) {
57 DCHECK_EQ(kDescriptor, new_location_);
60 DCHECK_EQ(kDescriptor, GetDetails(descriptor).location());
61 return old_descriptors_->GetStrongValue(descriptor);
64 FieldType MapUpdater::GetFieldType(
int descriptor)
const {
65 DCHECK_LE(0, descriptor);
66 if (descriptor == modified_descriptor_) {
67 DCHECK_EQ(kField, new_location_);
68 return *new_field_type_;
70 DCHECK_EQ(kField, GetDetails(descriptor).location());
71 return old_descriptors_->GetFieldType(descriptor);
74 Handle<FieldType> MapUpdater::GetOrComputeFieldType(
75 int descriptor, PropertyLocation location,
76 Representation representation)
const {
77 DCHECK_LE(0, descriptor);
79 DCHECK_EQ(location, GetDetails(descriptor).location());
80 if (location == kField) {
81 return handle(GetFieldType(descriptor), isolate_);
83 return GetValue(descriptor)->OptimalType(isolate_, representation);
87 Handle<FieldType> MapUpdater::GetOrComputeFieldType(
88 Handle<DescriptorArray> descriptors,
int descriptor,
89 PropertyLocation location, Representation representation) {
91 DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location);
92 if (location == kField) {
93 return handle(descriptors->GetFieldType(descriptor), isolate_);
95 return descriptors->GetStrongValue(descriptor)
96 ->OptimalType(isolate_, representation);
100 Handle<Map> MapUpdater::ReconfigureToDataField(
int descriptor,
101 PropertyAttributes attributes,
102 PropertyConstness constness,
103 Representation representation,
104 Handle<FieldType> field_type) {
105 DCHECK_EQ(kInitialized, state_);
106 DCHECK_LE(0, descriptor);
107 DCHECK(!old_map_->is_dictionary_map());
108 modified_descriptor_ = descriptor;
110 new_attributes_ = attributes;
111 new_location_ = kField;
113 PropertyDetails old_details =
114 old_descriptors_->GetDetails(modified_descriptor_);
118 if (old_details.kind() == new_kind_) {
119 new_constness_ = GeneralizeConstness(constness, old_details.constness());
121 Representation old_representation = old_details.representation();
122 new_representation_ = representation.generalize(old_representation);
124 Handle<FieldType> old_field_type =
125 GetOrComputeFieldType(old_descriptors_, modified_descriptor_,
126 old_details.location(), new_representation_);
129 Map::GeneralizeFieldType(old_representation, old_field_type,
130 new_representation_, field_type, isolate_);
135 new_constness_ = PropertyConstness::kMutable;
136 new_representation_ = representation;
137 new_field_type_ = field_type;
140 Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
141 isolate_, old_map_->instance_type(), &new_constness_,
142 &new_representation_, &new_field_type_);
144 if (TryRecofigureToDataFieldInplace() == kEnd)
return result_map_;
145 if (FindRootMap() == kEnd)
return result_map_;
146 if (FindTargetMap() == kEnd)
return result_map_;
148 DCHECK_EQ(kEnd, state_);
152 Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) {
153 DCHECK_EQ(kInitialized, state_);
154 new_elements_kind_ = elements_kind;
155 is_transitionable_fast_elements_kind_ =
156 IsTransitionableFastElementsKind(new_elements_kind_);
158 if (FindRootMap() == kEnd)
return result_map_;
159 if (FindTargetMap() == kEnd)
return result_map_;
161 DCHECK_EQ(kEnd, state_);
165 Handle<Map> MapUpdater::Update() {
166 DCHECK_EQ(kInitialized, state_);
167 DCHECK(old_map_->is_deprecated());
169 if (FindRootMap() == kEnd)
return result_map_;
170 if (FindTargetMap() == kEnd)
return result_map_;
172 DCHECK_EQ(kEnd, state_);
173 if (FLAG_fast_map_update) {
174 TransitionsAccessor(isolate_, old_map_).SetMigrationTarget(*result_map_);
179 void MapUpdater::GeneralizeField(Handle<Map> map,
int modify_index,
180 PropertyConstness new_constness,
181 Representation new_representation,
182 Handle<FieldType> new_field_type) {
183 Map::GeneralizeField(isolate_, map, modify_index, new_constness,
184 new_representation, new_field_type);
186 DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors());
189 MapUpdater::State MapUpdater::CopyGeneralizeAllFields(
const char* reason) {
190 result_map_ = Map::CopyGeneralizeAllFields(
191 isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_,
192 new_attributes_, reason);
197 MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() {
203 if (new_representation_.IsNone() || new_representation_.IsDouble()) {
207 PropertyDetails old_details =
208 old_descriptors_->GetDetails(modified_descriptor_);
209 Representation old_representation = old_details.representation();
210 if (!old_representation.IsNone()) {
214 DCHECK_EQ(new_kind_, old_details.kind());
215 DCHECK_EQ(new_attributes_, old_details.attributes());
216 DCHECK_EQ(kField, old_details.location());
217 if (FLAG_trace_generalization) {
218 old_map_->PrintGeneralization(
219 isolate_, stdout,
"uninitialized field", modified_descriptor_, old_nof_,
220 old_nof_,
false, old_representation, new_representation_,
221 handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_),
222 MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>());
224 Handle<Map> field_owner(
225 old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_);
227 GeneralizeField(field_owner, modified_descriptor_, new_constness_,
228 new_representation_, new_field_type_);
230 DCHECK(old_descriptors_->GetDetails(modified_descriptor_)
232 .Equals(new_representation_));
233 DCHECK(old_descriptors_->GetFieldType(modified_descriptor_)
234 ->NowIs(new_field_type_));
236 result_map_ = old_map_;
241 MapUpdater::State MapUpdater::FindRootMap() {
242 DCHECK_EQ(kInitialized, state_);
244 root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_);
245 ElementsKind from_kind = root_map_->elements_kind();
246 ElementsKind to_kind = new_elements_kind_;
247 if (root_map_->is_deprecated()) {
249 result_map_ = handle(
250 JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_);
251 result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind);
252 DCHECK(result_map_->is_dictionary_map());
255 int root_nof = root_map_->NumberOfOwnDescriptors();
256 if (!old_map_->EquivalentToForTransition(*root_map_)) {
257 return CopyGeneralizeAllFields(
"GenAll_NotEquivalent");
261 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS &&
262 to_kind != SLOW_STRING_WRAPPER_ELEMENTS &&
263 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS &&
264 !(IsTransitionableFastElementsKind(from_kind) &&
265 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) {
266 return CopyGeneralizeAllFields(
"GenAll_InvalidElementsTransition");
269 if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) {
270 PropertyDetails old_details =
271 old_descriptors_->GetDetails(modified_descriptor_);
272 if (old_details.kind() != new_kind_ ||
273 old_details.attributes() != new_attributes_) {
274 return CopyGeneralizeAllFields(
"GenAll_RootModification1");
276 if (old_details.location() != kField) {
277 return CopyGeneralizeAllFields(
"GenAll_RootModification2");
279 if (new_constness_ != old_details.constness() &&
280 (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) {
281 return CopyGeneralizeAllFields(
"GenAll_RootModification3");
283 if (!new_representation_.fits_into(old_details.representation())) {
284 return CopyGeneralizeAllFields(
"GenAll_RootModification4");
287 DCHECK_EQ(kData, old_details.kind());
288 DCHECK_EQ(kData, new_kind_);
289 DCHECK_EQ(kField, new_location_);
290 FieldType old_field_type =
291 old_descriptors_->GetFieldType(modified_descriptor_);
292 if (!new_field_type_->NowIs(old_field_type)) {
293 return CopyGeneralizeAllFields(
"GenAll_RootModification5");
297 if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) {
301 DCHECK(old_map_->is_prototype_map());
302 DCHECK(old_map_->is_stable());
303 DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_));
304 GeneralizeField(old_map_, modified_descriptor_, new_constness_,
305 old_details.representation(),
306 handle(old_field_type, isolate_));
311 root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind);
316 MapUpdater::State MapUpdater::FindTargetMap() {
317 DCHECK_EQ(kAtRootMap, state_);
318 target_map_ = root_map_;
320 int root_nof = root_map_->NumberOfOwnDescriptors();
321 for (
int i = root_nof;
i < old_nof_; ++
i) {
322 PropertyDetails old_details = GetDetails(
i);
323 Map transition = TransitionsAccessor(isolate_, target_map_)
324 .SearchTransition(GetKey(
i), old_details.kind(),
325 old_details.attributes());
326 if (transition.is_null())
break;
327 Handle<Map> tmp_map(transition, isolate_);
329 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
333 PropertyDetails tmp_details = tmp_descriptors->GetDetails(
i);
334 DCHECK_EQ(old_details.kind(), tmp_details.kind());
335 DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
336 if (old_details.kind() == kAccessor &&
337 !EqualImmutableValues(GetValue(
i),
338 tmp_descriptors->GetStrongValue(
i))) {
340 return CopyGeneralizeAllFields(
"GenAll_Incompatible");
342 PropertyConstness tmp_constness = tmp_details.constness();
343 if (!FLAG_modify_map_inplace &&
344 !IsGeneralizableTo(old_details.constness(), tmp_constness)) {
347 if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) {
350 Representation tmp_representation = tmp_details.representation();
351 if (!old_details.representation().fits_into(tmp_representation)) {
355 if (tmp_details.location() == kField) {
356 Handle<FieldType> old_field_type =
357 GetOrComputeFieldType(
i, old_details.location(), tmp_representation);
358 PropertyConstness constness =
359 FLAG_modify_map_inplace ? old_details.constness() : tmp_constness;
360 GeneralizeField(tmp_map,
i, constness, tmp_representation,
364 if (!EqualImmutableValues(GetValue(
i),
365 tmp_descriptors->GetStrongValue(
i))) {
369 DCHECK(!tmp_map->is_deprecated());
370 target_map_ = tmp_map;
374 int target_nof = target_map_->NumberOfOwnDescriptors();
375 if (target_nof == old_nof_) {
377 if (modified_descriptor_ >= 0) {
378 DescriptorArray* target_descriptors = target_map_->instance_descriptors();
379 PropertyDetails details =
380 target_descriptors->GetDetails(modified_descriptor_);
381 DCHECK_EQ(new_kind_, details.kind());
382 DCHECK_EQ(new_attributes_, details.attributes());
383 DCHECK(IsGeneralizableTo(new_constness_, details.constness()));
384 DCHECK_EQ(new_location_, details.location());
385 DCHECK(new_representation_.fits_into(details.representation()));
386 if (new_location_ == kField) {
387 DCHECK_EQ(kField, details.location());
388 DCHECK(new_field_type_->NowIs(
389 target_descriptors->GetFieldType(modified_descriptor_)));
391 DCHECK(details.location() == kField ||
392 EqualImmutableValues(
394 target_descriptors->GetStrongValue(modified_descriptor_)));
398 if (*target_map_ != *old_map_) {
399 old_map_->NotifyLeafMapLayoutChange(isolate_);
401 result_map_ = target_map_;
407 for (
int i = target_nof;
i < old_nof_; ++
i) {
408 PropertyDetails old_details = GetDetails(
i);
409 Map transition = TransitionsAccessor(isolate_, target_map_)
410 .SearchTransition(GetKey(
i), old_details.kind(),
411 old_details.attributes());
412 if (transition.is_null())
break;
413 Handle<Map> tmp_map(transition, isolate_);
414 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(),
418 PropertyDetails tmp_details = tmp_descriptors->GetDetails(
i);
419 DCHECK_EQ(old_details.kind(), tmp_details.kind());
420 DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
422 if (old_details.kind() == kAccessor &&
423 !EqualImmutableValues(GetValue(
i),
424 tmp_descriptors->GetStrongValue(
i))) {
425 return CopyGeneralizeAllFields(
"GenAll_Incompatible");
427 DCHECK(!tmp_map->is_deprecated());
428 target_map_ = tmp_map;
431 state_ = kAtTargetMap;
435 Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() {
436 InstanceType instance_type = old_map_->instance_type();
437 int target_nof = target_map_->NumberOfOwnDescriptors();
438 Handle<DescriptorArray> target_descriptors(
439 target_map_->instance_descriptors(), isolate_);
445 std::max<int>(old_nof_, old_descriptors_->number_of_descriptors()) -
447 Handle<DescriptorArray> new_descriptors =
448 DescriptorArray::Allocate(isolate_, old_nof_, new_slack);
449 DCHECK(new_descriptors->number_of_all_descriptors() >
450 target_descriptors->number_of_all_descriptors() ||
451 new_descriptors->number_of_slack_descriptors() > 0 ||
452 new_descriptors->number_of_descriptors() ==
453 old_descriptors_->number_of_descriptors());
454 DCHECK(new_descriptors->number_of_descriptors() == old_nof_);
456 int root_nof = root_map_->NumberOfOwnDescriptors();
462 int current_offset = 0;
463 for (
int i = 0;
i < root_nof; ++
i) {
464 PropertyDetails old_details = old_descriptors_->GetDetails(
i);
465 if (old_details.location() == kField) {
466 current_offset += old_details.field_width_in_words();
468 Descriptor d(handle(GetKey(
i), isolate_),
469 MaybeObjectHandle(old_descriptors_->GetValue(
i), isolate_),
471 new_descriptors->Set(
i, &d);
476 for (
int i = root_nof;
i < target_nof; ++
i) {
477 Handle<Name> key(GetKey(
i), isolate_);
478 PropertyDetails old_details = GetDetails(
i);
479 PropertyDetails target_details = target_descriptors->GetDetails(
i);
481 PropertyKind next_kind = old_details.kind();
482 PropertyAttributes next_attributes = old_details.attributes();
483 DCHECK_EQ(next_kind, target_details.kind());
484 DCHECK_EQ(next_attributes, target_details.attributes());
486 PropertyConstness next_constness = GeneralizeConstness(
487 old_details.constness(), target_details.constness());
491 PropertyLocation next_location =
492 old_details.location() == kField ||
493 target_details.location() == kField ||
494 !EqualImmutableValues(target_descriptors->GetStrongValue(
i),
499 if (!FLAG_track_constant_fields && next_location == kField) {
500 next_constness = PropertyConstness::kMutable;
503 DCHECK_IMPLIES(next_constness == PropertyConstness::kMutable,
504 next_location == kField);
506 Representation next_representation =
507 old_details.representation().generalize(
508 target_details.representation());
510 if (next_location == kField) {
511 Handle<FieldType> old_field_type =
512 GetOrComputeFieldType(
i, old_details.location(), next_representation);
514 Handle<FieldType> target_field_type =
515 GetOrComputeFieldType(target_descriptors,
i,
516 target_details.location(), next_representation);
518 Handle<FieldType> next_field_type = Map::GeneralizeFieldType(
519 old_details.representation(), old_field_type, next_representation,
520 target_field_type, isolate_);
522 Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
523 isolate_, instance_type, &next_constness, &next_representation,
526 MaybeObjectHandle wrapped_type(
527 Map::WrapFieldType(isolate_, next_field_type));
529 if (next_kind == kData) {
530 d = Descriptor::DataField(key, current_offset, next_attributes,
531 next_constness, next_representation,
537 current_offset += d.GetDetails().field_width_in_words();
538 new_descriptors->Set(
i, &d);
540 DCHECK_EQ(kDescriptor, next_location);
541 DCHECK_EQ(PropertyConstness::kConst, next_constness);
543 Handle<Object> value(GetValue(
i), isolate_);
545 if (next_kind == kData) {
546 DCHECK(!FLAG_track_constant_fields);
547 d = Descriptor::DataConstant(key, value, next_attributes);
549 DCHECK_EQ(kAccessor, next_kind);
550 d = Descriptor::AccessorConstant(key, value, next_attributes);
552 new_descriptors->Set(
i, &d);
558 for (
int i = target_nof;
i < old_nof_; ++
i) {
559 PropertyDetails old_details = GetDetails(
i);
560 Handle<Name> key(GetKey(
i), isolate_);
562 PropertyKind next_kind = old_details.kind();
563 PropertyAttributes next_attributes = old_details.attributes();
564 PropertyConstness next_constness = old_details.constness();
565 PropertyLocation next_location = old_details.location();
566 Representation next_representation = old_details.representation();
569 if (next_location == kField) {
570 Handle<FieldType> next_field_type =
571 GetOrComputeFieldType(
i, old_details.location(), next_representation);
576 CHECK_IMPLIES(is_transitionable_fast_elements_kind_,
577 !Map::IsInplaceGeneralizableField(
578 next_constness, next_representation, *next_field_type));
580 MaybeObjectHandle wrapped_type(
581 Map::WrapFieldType(isolate_, next_field_type));
583 if (next_kind == kData) {
584 DCHECK_IMPLIES(!FLAG_track_constant_fields,
585 next_constness == PropertyConstness::kMutable);
586 d = Descriptor::DataField(key, current_offset, next_attributes,
587 next_constness, next_representation,
593 current_offset += d.GetDetails().field_width_in_words();
594 new_descriptors->Set(
i, &d);
596 DCHECK_EQ(kDescriptor, next_location);
597 DCHECK_EQ(PropertyConstness::kConst, next_constness);
599 Handle<Object> value(GetValue(
i), isolate_);
600 if (next_kind == kData) {
601 d = Descriptor::DataConstant(key, value, next_attributes);
603 DCHECK_EQ(kAccessor, next_kind);
604 d = Descriptor::AccessorConstant(key, value, next_attributes);
606 new_descriptors->Set(
i, &d);
610 new_descriptors->Sort();
611 return new_descriptors;
614 Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) {
615 DisallowHeapAllocation no_allocation;
617 int root_nof = root_map_->NumberOfOwnDescriptors();
618 Map current = *root_map_;
619 for (
int i = root_nof;
i < old_nof_;
i++) {
620 Name name = descriptors->GetKey(
i);
621 PropertyDetails details = descriptors->GetDetails(
i);
623 TransitionsAccessor(isolate_, current, &no_allocation)
624 .SearchTransition(name, details.kind(), details.attributes());
625 if (next.is_null())
break;
626 DescriptorArray* next_descriptors = next->instance_descriptors();
628 PropertyDetails next_details = next_descriptors->GetDetails(
i);
629 DCHECK_EQ(details.kind(), next_details.kind());
630 DCHECK_EQ(details.attributes(), next_details.attributes());
631 if (details.constness() != next_details.constness())
break;
632 if (details.location() != next_details.location())
break;
633 if (!details.representation().Equals(next_details.representation()))
break;
635 if (next_details.location() == kField) {
636 FieldType next_field_type = next_descriptors->GetFieldType(
i);
637 if (!descriptors->GetFieldType(
i)->NowIs(next_field_type)) {
641 if (!EqualImmutableValues(descriptors->GetStrongValue(
i),
642 next_descriptors->GetStrongValue(
i))) {
648 return handle(current, isolate_);
651 MapUpdater::State MapUpdater::ConstructNewMap() {
652 Handle<DescriptorArray> new_descriptors = BuildDescriptorArray();
654 Handle<Map> split_map = FindSplitMap(new_descriptors);
655 int split_nof = split_map->NumberOfOwnDescriptors();
656 DCHECK_NE(old_nof_, split_nof);
658 PropertyDetails split_details = GetDetails(split_nof);
659 TransitionsAccessor transitions(isolate_, split_map);
662 Map maybe_transition = transitions.SearchTransition(
663 GetKey(split_nof), split_details.kind(), split_details.attributes());
664 if (!maybe_transition.is_null()) {
665 maybe_transition->DeprecateTransitionTree(isolate_);
671 if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) {
672 return CopyGeneralizeAllFields(
"GenAll_CantHaveMoreTransitions");
675 old_map_->NotifyLeafMapLayoutChange(isolate_);
677 if (FLAG_trace_generalization && modified_descriptor_ >= 0) {
678 PropertyDetails old_details =
679 old_descriptors_->GetDetails(modified_descriptor_);
680 PropertyDetails new_details =
681 new_descriptors->GetDetails(modified_descriptor_);
682 MaybeHandle<FieldType> old_field_type;
683 MaybeHandle<FieldType> new_field_type;
684 MaybeHandle<Object> old_value;
685 MaybeHandle<Object> new_value;
686 if (old_details.location() == kField) {
687 old_field_type = handle(
688 old_descriptors_->GetFieldType(modified_descriptor_), isolate_);
690 old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_),
693 if (new_details.location() == kField) {
695 handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_);
697 new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_),
701 old_map_->PrintGeneralization(
702 isolate_, stdout,
"", modified_descriptor_, split_nof, old_nof_,
703 old_details.location() == kDescriptor && new_location_ == kField,
704 old_details.representation(), new_details.representation(),
705 old_field_type, old_value, new_field_type, new_value);
708 Handle<LayoutDescriptor> new_layout_descriptor =
709 LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_);
711 Handle<Map> new_map = Map::AddMissingTransitions(
712 isolate_, split_map, new_descriptors, new_layout_descriptor);
717 split_map->ReplaceDescriptors(isolate_, *new_descriptors,
718 *new_layout_descriptor);
720 result_map_ = new_map;