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