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 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 27 MapUpdater::MapUpdater(Isolate* isolate, Handle<Map> old_map) 28 : isolate_(isolate), 29 old_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_)) { 35 // We shouldn't try to update remote objects. 36 DCHECK(!old_map->FindRootMap(isolate) 37 ->GetConstructor() 38 ->IsFunctionTemplateInfo()); 39 } 40 41 Name* MapUpdater::GetKey(int descriptor) const { 42 return old_descriptors_->GetKey(descriptor); 43 } 44 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_); 50 } 51 return old_descriptors_->GetDetails(descriptor); 52 } 53 54 Object* MapUpdater::GetValue(int descriptor) const { 55 DCHECK_LE(0, descriptor); 56 if (descriptor == modified_descriptor_) { 57 DCHECK_EQ(kDescriptor, new_location_); 58 return *new_value_; 59 } 60 DCHECK_EQ(kDescriptor, GetDetails(descriptor).location()); 61 return old_descriptors_->GetStrongValue(descriptor); 62 } 63 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_; 69 } 70 DCHECK_EQ(kField, GetDetails(descriptor).location()); 71 return old_descriptors_->GetFieldType(descriptor); 72 } 73 74 Handle<FieldType> MapUpdater::GetOrComputeFieldType( 75 int descriptor, PropertyLocation location, 76 Representation representation) const { 77 DCHECK_LE(0, descriptor); 78 // |location| is just a pre-fetched GetDetails(descriptor).location(). 79 DCHECK_EQ(location, GetDetails(descriptor).location()); 80 if (location == kField) { 81 return handle(GetFieldType(descriptor), isolate_); 82 } else { 83 return GetValue(descriptor)->OptimalType(isolate_, representation); 84 } 85 } 86 87 Handle<FieldType> MapUpdater::GetOrComputeFieldType( 88 Handle<DescriptorArray> descriptors, int descriptor, 89 PropertyLocation location, Representation representation) { 90 // |location| is just a pre-fetched GetDetails(descriptor).location(). 91 DCHECK_EQ(descriptors->GetDetails(descriptor).location(), location); 92 if (location == kField) { 93 return handle(descriptors->GetFieldType(descriptor), isolate_); 94 } else { 95 return descriptors->GetStrongValue(descriptor) 96 ->OptimalType(isolate_, representation); 97 } 98 } 99 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; 109 new_kind_ = kData; 110 new_attributes_ = attributes; 111 new_location_ = kField; 112 113 PropertyDetails old_details = 114 old_descriptors_->GetDetails(modified_descriptor_); 115 116 // If property kind is not reconfigured merge the result with 117 // representation/field type from the old descriptor. 118 if (old_details.kind() == new_kind_) { 119 new_constness_ = GeneralizeConstness(constness, old_details.constness()); 120 121 Representation old_representation = old_details.representation(); 122 new_representation_ = representation.generalize(old_representation); 123 124 Handle<FieldType> old_field_type = 125 GetOrComputeFieldType(old_descriptors_, modified_descriptor_, 126 old_details.location(), new_representation_); 127 128 new_field_type_ = 129 Map::GeneralizeFieldType(old_representation, old_field_type, 130 new_representation_, field_type, isolate_); 131 } else { 132 // We don't know if this is a first property kind reconfiguration 133 // and we don't know which value was in this property previously 134 // therefore we can't treat such a property as constant. 135 new_constness_ = PropertyConstness::kMutable; 136 new_representation_ = representation; 137 new_field_type_ = field_type; 138 } 139 140 Map::GeneralizeIfCanHaveTransitionableFastElementsKind( 141 isolate_, old_map_->instance_type(), &new_constness_, 142 &new_representation_, &new_field_type_); 143 144 if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_; 145 if (FindRootMap() == kEnd) return result_map_; 146 if (FindTargetMap() == kEnd) return result_map_; 147 ConstructNewMap(); 148 DCHECK_EQ(kEnd, state_); 149 return result_map_; 150 } 151 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_); 157 158 if (FindRootMap() == kEnd) return result_map_; 159 if (FindTargetMap() == kEnd) return result_map_; 160 ConstructNewMap(); 161 DCHECK_EQ(kEnd, state_); 162 return result_map_; 163 } 164 165 Handle<Map> MapUpdater::Update() { 166 DCHECK_EQ(kInitialized, state_); 167 DCHECK(old_map_->is_deprecated()); 168 169 if (FindRootMap() == kEnd) return result_map_; 170 if (FindTargetMap() == kEnd) return result_map_; 171 ConstructNewMap(); 172 DCHECK_EQ(kEnd, state_); 173 return result_map_; 174 } 175 176 void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index, 177 PropertyConstness new_constness, 178 Representation new_representation, 179 Handle<FieldType> new_field_type) { 180 Map::GeneralizeField(isolate_, map, modify_index, new_constness, 181 new_representation, new_field_type); 182 183 DCHECK_EQ(*old_descriptors_, old_map_->instance_descriptors()); 184 } 185 186 MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) { 187 result_map_ = Map::CopyGeneralizeAllFields( 188 isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_, 189 new_attributes_, reason); 190 state_ = kEnd; 191 return state_; // Done. 192 } 193 194 MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() { 195 // If it's just a representation generalization case (i.e. property kind and 196 // attributes stays unchanged) it's fine to transition from None to anything 197 // but double without any modification to the object, because the default 198 // uninitialized value for representation None can be overwritten by both 199 // smi and tagged values. Doubles, however, would require a box allocation. 200 if (new_representation_.IsNone() || new_representation_.IsDouble()) { 201 return state_; // Not done yet. 202 } 203 204 PropertyDetails old_details = 205 old_descriptors_->GetDetails(modified_descriptor_); 206 Representation old_representation = old_details.representation(); 207 if (!old_representation.IsNone()) { 208 return state_; // Not done yet. 209 } 210 211 DCHECK_EQ(new_kind_, old_details.kind()); 212 DCHECK_EQ(new_attributes_, old_details.attributes()); 213 DCHECK_EQ(kField, old_details.location()); 214 if (FLAG_trace_generalization) { 215 old_map_->PrintGeneralization( 216 isolate_, stdout, "uninitialized field", modified_descriptor_, old_nof_, 217 old_nof_, false, old_representation, new_representation_, 218 handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_), 219 MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>()); 220 } 221 Handle<Map> field_owner( 222 old_map_->FindFieldOwner(isolate_, modified_descriptor_), isolate_); 223 224 GeneralizeField(field_owner, modified_descriptor_, new_constness_, 225 new_representation_, new_field_type_); 226 // Check that the descriptor array was updated. 227 DCHECK(old_descriptors_->GetDetails(modified_descriptor_) 228 .representation() 229 .Equals(new_representation_)); 230 DCHECK(old_descriptors_->GetFieldType(modified_descriptor_) 231 ->NowIs(new_field_type_)); 232 233 result_map_ = old_map_; 234 state_ = kEnd; 235 return state_; // Done. 236 } 237 238 MapUpdater::State MapUpdater::FindRootMap() { 239 DCHECK_EQ(kInitialized, state_); 240 // Check the state of the root map. 241 root_map_ = handle(old_map_->FindRootMap(isolate_), isolate_); 242 ElementsKind from_kind = root_map_->elements_kind(); 243 ElementsKind to_kind = new_elements_kind_; 244 if (root_map_->is_deprecated()) { 245 state_ = kEnd; 246 result_map_ = handle( 247 JSFunction::cast(root_map_->GetConstructor())->initial_map(), isolate_); 248 result_map_ = Map::AsElementsKind(isolate_, result_map_, to_kind); 249 DCHECK(result_map_->is_dictionary_map()); 250 return state_; 251 } 252 int root_nof = root_map_->NumberOfOwnDescriptors(); 253 if (!old_map_->EquivalentToForTransition(*root_map_)) { 254 return CopyGeneralizeAllFields("GenAll_NotEquivalent"); 255 } 256 257 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. 258 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && 259 to_kind != SLOW_STRING_WRAPPER_ELEMENTS && 260 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && 261 !(IsTransitionableFastElementsKind(from_kind) && 262 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { 263 return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition"); 264 } 265 266 if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) { 267 PropertyDetails old_details = 268 old_descriptors_->GetDetails(modified_descriptor_); 269 if (old_details.kind() != new_kind_ || 270 old_details.attributes() != new_attributes_) { 271 return CopyGeneralizeAllFields("GenAll_RootModification1"); 272 } 273 if (old_details.location() != kField) { 274 return CopyGeneralizeAllFields("GenAll_RootModification2"); 275 } 276 if (new_constness_ != old_details.constness() && 277 (!FLAG_modify_map_inplace || !old_map_->is_prototype_map())) { 278 return CopyGeneralizeAllFields("GenAll_RootModification3"); 279 } 280 if (!new_representation_.fits_into(old_details.representation())) { 281 return CopyGeneralizeAllFields("GenAll_RootModification4"); 282 } 283 284 DCHECK_EQ(kData, old_details.kind()); 285 DCHECK_EQ(kData, new_kind_); 286 DCHECK_EQ(kField, new_location_); 287 FieldType* old_field_type = 288 old_descriptors_->GetFieldType(modified_descriptor_); 289 if (!new_field_type_->NowIs(old_field_type)) { 290 return CopyGeneralizeAllFields("GenAll_RootModification5"); 291 } 292 293 // Modify root map in-place. 294 if (FLAG_modify_map_inplace && new_constness_ != old_details.constness()) { 295 // Only prototype root maps are allowed to be updated in-place. 296 // TODO(ishell): fix all the stubs that use prototype map check to 297 // ensure that the prototype was not modified. 298 DCHECK(old_map_->is_prototype_map()); 299 DCHECK(old_map_->is_stable()); 300 DCHECK(IsGeneralizableTo(old_details.constness(), new_constness_)); 301 GeneralizeField(old_map_, modified_descriptor_, new_constness_, 302 old_details.representation(), 303 handle(old_field_type, isolate_)); 304 } 305 } 306 307 // From here on, use the map with correct elements kind as root map. 308 root_map_ = Map::AsElementsKind(isolate_, root_map_, to_kind); 309 state_ = kAtRootMap; 310 return state_; // Not done yet. 311 } 312 313 MapUpdater::State MapUpdater::FindTargetMap() { 314 DCHECK_EQ(kAtRootMap, state_); 315 target_map_ = root_map_; 316 317 int root_nof = root_map_->NumberOfOwnDescriptors(); 318 for (int i = root_nof; i < old_nof_; ++i) { 319 PropertyDetails old_details = GetDetails(i); 320 Map* transition = TransitionsAccessor(isolate_, target_map_) 321 .SearchTransition(GetKey(i), old_details.kind(), 322 old_details.attributes()); 323 if (transition == nullptr) break; 324 Handle<Map> tmp_map(transition, isolate_); 325 326 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(), 327 isolate_); 328 329 // Check if target map is incompatible. 330 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); 331 DCHECK_EQ(old_details.kind(), tmp_details.kind()); 332 DCHECK_EQ(old_details.attributes(), tmp_details.attributes()); 333 if (old_details.kind() == kAccessor && 334 !EqualImmutableValues(GetValue(i), 335 tmp_descriptors->GetStrongValue(i))) { 336 // TODO(ishell): mutable accessors are not implemented yet. 337 return CopyGeneralizeAllFields("GenAll_Incompatible"); 338 } 339 PropertyConstness tmp_constness = tmp_details.constness(); 340 if (!FLAG_modify_map_inplace && 341 !IsGeneralizableTo(old_details.constness(), tmp_constness)) { 342 break; 343 } 344 if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) { 345 break; 346 } 347 Representation tmp_representation = tmp_details.representation(); 348 if (!old_details.representation().fits_into(tmp_representation)) { 349 break; 350 } 351 352 if (tmp_details.location() == kField) { 353 Handle<FieldType> old_field_type = 354 GetOrComputeFieldType(i, old_details.location(), tmp_representation); 355 PropertyConstness constness = 356 FLAG_modify_map_inplace ? old_details.constness() : tmp_constness; 357 GeneralizeField(tmp_map, i, constness, tmp_representation, 358 old_field_type); 359 } else { 360 // kDescriptor: Check that the value matches. 361 if (!EqualImmutableValues(GetValue(i), 362 tmp_descriptors->GetStrongValue(i))) { 363 break; 364 } 365 } 366 DCHECK(!tmp_map->is_deprecated()); 367 target_map_ = tmp_map; 368 } 369 370 // Directly change the map if the target map is more general. 371 int target_nof = target_map_->NumberOfOwnDescriptors(); 372 if (target_nof == old_nof_) { 373 #ifdef DEBUG 374 if (modified_descriptor_ >= 0) { 375 DescriptorArray* target_descriptors = target_map_->instance_descriptors(); 376 PropertyDetails details = 377 target_descriptors->GetDetails(modified_descriptor_); 378 DCHECK_EQ(new_kind_, details.kind()); 379 DCHECK_EQ(new_attributes_, details.attributes()); 380 DCHECK(IsGeneralizableTo(new_constness_, details.constness())); 381 DCHECK_EQ(new_location_, details.location()); 382 DCHECK(new_representation_.fits_into(details.representation())); 383 if (new_location_ == kField) { 384 DCHECK_EQ(kField, details.location()); 385 DCHECK(new_field_type_->NowIs( 386 target_descriptors->GetFieldType(modified_descriptor_))); 387 } else { 388 DCHECK(details.location() == kField || 389 EqualImmutableValues( 390 *new_value_, 391 target_descriptors->GetStrongValue(modified_descriptor_))); 392 } 393 } 394 #endif 395 if (*target_map_ != *old_map_) { 396 old_map_->NotifyLeafMapLayoutChange(isolate_); 397 } 398 result_map_ = target_map_; 399 state_ = kEnd; 400 return state_; // Done. 401 } 402 403 // Find the last compatible target map in the transition tree. 404 for (int i = target_nof; i < old_nof_; ++i) { 405 PropertyDetails old_details = GetDetails(i); 406 Map* transition = TransitionsAccessor(isolate_, target_map_) 407 .SearchTransition(GetKey(i), old_details.kind(), 408 old_details.attributes()); 409 if (transition == nullptr) break; 410 Handle<Map> tmp_map(transition, isolate_); 411 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(), 412 isolate_); 413 #ifdef DEBUG 414 // Check that target map is compatible. 415 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); 416 DCHECK_EQ(old_details.kind(), tmp_details.kind()); 417 DCHECK_EQ(old_details.attributes(), tmp_details.attributes()); 418 #endif 419 if (old_details.kind() == kAccessor && 420 !EqualImmutableValues(GetValue(i), 421 tmp_descriptors->GetStrongValue(i))) { 422 return CopyGeneralizeAllFields("GenAll_Incompatible"); 423 } 424 DCHECK(!tmp_map->is_deprecated()); 425 target_map_ = tmp_map; 426 } 427 428 state_ = kAtTargetMap; 429 return state_; // Not done yet. 430 } 431 432 Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() { 433 InstanceType instance_type = old_map_->instance_type(); 434 int target_nof = target_map_->NumberOfOwnDescriptors(); 435 Handle<DescriptorArray> target_descriptors( 436 target_map_->instance_descriptors(), isolate_); 437 438 // Allocate a new descriptor array large enough to hold the required 439 // descriptors, with minimally the exact same size as the old descriptor 440 // array. 441 int new_slack = 442 Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_; 443 Handle<DescriptorArray> new_descriptors = 444 DescriptorArray::Allocate(isolate_, old_nof_, new_slack); 445 DCHECK(new_descriptors->length() > target_descriptors->length() || 446 new_descriptors->NumberOfSlackDescriptors() > 0 || 447 new_descriptors->number_of_descriptors() == 448 old_descriptors_->number_of_descriptors()); 449 DCHECK(new_descriptors->number_of_descriptors() == old_nof_); 450 451 int root_nof = root_map_->NumberOfOwnDescriptors(); 452 453 // Given that we passed root modification check in FindRootMap() so 454 // the root descriptors are either not modified at all or already more 455 // general than we requested. Take |root_nof| entries as is. 456 // 0 -> |root_nof| 457 int current_offset = 0; 458 for (int i = 0; i < root_nof; ++i) { 459 PropertyDetails old_details = old_descriptors_->GetDetails(i); 460 if (old_details.location() == kField) { 461 current_offset += old_details.field_width_in_words(); 462 } 463 Descriptor d(handle(GetKey(i), isolate_), 464 MaybeObjectHandle(old_descriptors_->GetValue(i), isolate_), 465 old_details); 466 new_descriptors->Set(i, &d); 467 } 468 469 // Merge "updated" old_descriptor entries with target_descriptor entries. 470 // |root_nof| -> |target_nof| 471 for (int i = root_nof; i < target_nof; ++i) { 472 Handle<Name> key(GetKey(i), isolate_); 473 PropertyDetails old_details = GetDetails(i); 474 PropertyDetails target_details = target_descriptors->GetDetails(i); 475 476 PropertyKind next_kind = old_details.kind(); 477 PropertyAttributes next_attributes = old_details.attributes(); 478 DCHECK_EQ(next_kind, target_details.kind()); 479 DCHECK_EQ(next_attributes, target_details.attributes()); 480 481 PropertyConstness next_constness = GeneralizeConstness( 482 old_details.constness(), target_details.constness()); 483 484 // Note: failed values equality check does not invalidate per-object 485 // property constness. 486 PropertyLocation next_location = 487 old_details.location() == kField || 488 target_details.location() == kField || 489 !EqualImmutableValues(target_descriptors->GetStrongValue(i), 490 GetValue(i)) 491 ? kField 492 : kDescriptor; 493 494 if (!FLAG_track_constant_fields && next_location == kField) { 495 next_constness = PropertyConstness::kMutable; 496 } 497 // Ensure that mutable values are stored in fields. 498 DCHECK_IMPLIES(next_constness == PropertyConstness::kMutable, 499 next_location == kField); 500 501 Representation next_representation = 502 old_details.representation().generalize( 503 target_details.representation()); 504 505 if (next_location == kField) { 506 Handle<FieldType> old_field_type = 507 GetOrComputeFieldType(i, old_details.location(), next_representation); 508 509 Handle<FieldType> target_field_type = 510 GetOrComputeFieldType(target_descriptors, i, 511 target_details.location(), next_representation); 512 513 Handle<FieldType> next_field_type = Map::GeneralizeFieldType( 514 old_details.representation(), old_field_type, next_representation, 515 target_field_type, isolate_); 516 517 Map::GeneralizeIfCanHaveTransitionableFastElementsKind( 518 isolate_, instance_type, &next_constness, &next_representation, 519 &next_field_type); 520 521 MaybeObjectHandle wrapped_type( 522 Map::WrapFieldType(isolate_, next_field_type)); 523 Descriptor d; 524 if (next_kind == kData) { 525 d = Descriptor::DataField(key, current_offset, next_attributes, 526 next_constness, next_representation, 527 wrapped_type); 528 } else { 529 // TODO(ishell): mutable accessors are not implemented yet. 530 UNIMPLEMENTED(); 531 } 532 current_offset += d.GetDetails().field_width_in_words(); 533 new_descriptors->Set(i, &d); 534 } else { 535 DCHECK_EQ(kDescriptor, next_location); 536 DCHECK_EQ(PropertyConstness::kConst, next_constness); 537 538 Handle<Object> value(GetValue(i), isolate_); 539 Descriptor d; 540 if (next_kind == kData) { 541 DCHECK(!FLAG_track_constant_fields); 542 d = Descriptor::DataConstant(key, value, next_attributes); 543 } else { 544 DCHECK_EQ(kAccessor, next_kind); 545 d = Descriptor::AccessorConstant(key, value, next_attributes); 546 } 547 new_descriptors->Set(i, &d); 548 } 549 } 550 551 // Take "updated" old_descriptor entries. 552 // |target_nof| -> |old_nof| 553 for (int i = target_nof; i < old_nof_; ++i) { 554 PropertyDetails old_details = GetDetails(i); 555 Handle<Name> key(GetKey(i), isolate_); 556 557 PropertyKind next_kind = old_details.kind(); 558 PropertyAttributes next_attributes = old_details.attributes(); 559 PropertyConstness next_constness = old_details.constness(); 560 PropertyLocation next_location = old_details.location(); 561 Representation next_representation = old_details.representation(); 562 563 Descriptor d; 564 if (next_location == kField) { 565 Handle<FieldType> next_field_type = 566 GetOrComputeFieldType(i, old_details.location(), next_representation); 567 568 // If the |new_elements_kind_| is still transitionable then the old map's 569 // elements kind is also transitionable and therefore the old descriptors 570 // array must already have non in-place generalizable fields. 571 CHECK_IMPLIES(is_transitionable_fast_elements_kind_, 572 !Map::IsInplaceGeneralizableField( 573 next_constness, next_representation, *next_field_type)); 574 575 MaybeObjectHandle wrapped_type( 576 Map::WrapFieldType(isolate_, next_field_type)); 577 Descriptor d; 578 if (next_kind == kData) { 579 DCHECK_IMPLIES(!FLAG_track_constant_fields, 580 next_constness == PropertyConstness::kMutable); 581 d = Descriptor::DataField(key, current_offset, next_attributes, 582 next_constness, next_representation, 583 wrapped_type); 584 } else { 585 // TODO(ishell): mutable accessors are not implemented yet. 586 UNIMPLEMENTED(); 587 } 588 current_offset += d.GetDetails().field_width_in_words(); 589 new_descriptors->Set(i, &d); 590 } else { 591 DCHECK_EQ(kDescriptor, next_location); 592 DCHECK_EQ(PropertyConstness::kConst, next_constness); 593 594 Handle<Object> value(GetValue(i), isolate_); 595 if (next_kind == kData) { 596 d = Descriptor::DataConstant(key, value, next_attributes); 597 } else { 598 DCHECK_EQ(kAccessor, next_kind); 599 d = Descriptor::AccessorConstant(key, value, next_attributes); 600 } 601 new_descriptors->Set(i, &d); 602 } 603 } 604 605 new_descriptors->Sort(); 606 return new_descriptors; 607 } 608 609 Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) { 610 DisallowHeapAllocation no_allocation; 611 612 int root_nof = root_map_->NumberOfOwnDescriptors(); 613 Map* current = *root_map_; 614 for (int i = root_nof; i < old_nof_; i++) { 615 Name* name = descriptors->GetKey(i); 616 PropertyDetails details = descriptors->GetDetails(i); 617 Map* next = 618 TransitionsAccessor(isolate_, current, &no_allocation) 619 .SearchTransition(name, details.kind(), details.attributes()); 620 if (next == nullptr) break; 621 DescriptorArray* next_descriptors = next->instance_descriptors(); 622 623 PropertyDetails next_details = next_descriptors->GetDetails(i); 624 DCHECK_EQ(details.kind(), next_details.kind()); 625 DCHECK_EQ(details.attributes(), next_details.attributes()); 626 if (details.constness() != next_details.constness()) break; 627 if (details.location() != next_details.location()) break; 628 if (!details.representation().Equals(next_details.representation())) break; 629 630 if (next_details.location() == kField) { 631 FieldType* next_field_type = next_descriptors->GetFieldType(i); 632 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) { 633 break; 634 } 635 } else { 636 if (!EqualImmutableValues(descriptors->GetStrongValue(i), 637 next_descriptors->GetStrongValue(i))) { 638 break; 639 } 640 } 641 current = next; 642 } 643 return handle(current, isolate_); 644 } 645 646 MapUpdater::State MapUpdater::ConstructNewMap() { 647 Handle<DescriptorArray> new_descriptors = BuildDescriptorArray(); 648 649 Handle<Map> split_map = FindSplitMap(new_descriptors); 650 int split_nof = split_map->NumberOfOwnDescriptors(); 651 DCHECK_NE(old_nof_, split_nof); 652 653 PropertyDetails split_details = GetDetails(split_nof); 654 TransitionsAccessor transitions(isolate_, split_map); 655 656 // Invalidate a transition target at |key|. 657 Map* maybe_transition = transitions.SearchTransition( 658 GetKey(split_nof), split_details.kind(), split_details.attributes()); 659 if (maybe_transition != nullptr) { 660 maybe_transition->DeprecateTransitionTree(isolate_); 661 } 662 663 // If |maybe_transition| is not nullptr then the transition array already 664 // contains entry for given descriptor. This means that the transition 665 // could be inserted regardless of whether transitions array is full or not. 666 if (maybe_transition == nullptr && !transitions.CanHaveMoreTransitions()) { 667 return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions"); 668 } 669 670 old_map_->NotifyLeafMapLayoutChange(isolate_); 671 672 if (FLAG_trace_generalization && modified_descriptor_ >= 0) { 673 PropertyDetails old_details = 674 old_descriptors_->GetDetails(modified_descriptor_); 675 PropertyDetails new_details = 676 new_descriptors->GetDetails(modified_descriptor_); 677 MaybeHandle<FieldType> old_field_type; 678 MaybeHandle<FieldType> new_field_type; 679 MaybeHandle<Object> old_value; 680 MaybeHandle<Object> new_value; 681 if (old_details.location() == kField) { 682 old_field_type = handle( 683 old_descriptors_->GetFieldType(modified_descriptor_), isolate_); 684 } else { 685 old_value = handle(old_descriptors_->GetStrongValue(modified_descriptor_), 686 isolate_); 687 } 688 if (new_details.location() == kField) { 689 new_field_type = 690 handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_); 691 } else { 692 new_value = handle(new_descriptors->GetStrongValue(modified_descriptor_), 693 isolate_); 694 } 695 696 old_map_->PrintGeneralization( 697 isolate_, stdout, "", modified_descriptor_, split_nof, old_nof_, 698 old_details.location() == kDescriptor && new_location_ == kField, 699 old_details.representation(), new_details.representation(), 700 old_field_type, old_value, new_field_type, new_value); 701 } 702 703 Handle<LayoutDescriptor> new_layout_descriptor = 704 LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_); 705 706 Handle<Map> new_map = Map::AddMissingTransitions( 707 isolate_, split_map, new_descriptors, new_layout_descriptor); 708 709 // Deprecated part of the transition tree is no longer reachable, so replace 710 // current instance descriptors in the "survived" part of the tree with 711 // the new descriptors to maintain descriptors sharing invariant. 712 split_map->ReplaceDescriptors(isolate_, *new_descriptors, 713 *new_layout_descriptor); 714 715 result_map_ = new_map; 716 state_ = kEnd; 717 return state_; // Done. 718 } 719 720 } // namespace internal 721 } // namespace v8 722