OLD | NEW |
(Empty) | |
| 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 Name* MapUpdater::GetKey(int descriptor) const { |
| 28 return old_descriptors_->GetKey(descriptor); |
| 29 } |
| 30 |
| 31 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_representation_); |
| 36 } |
| 37 return old_descriptors_->GetDetails(descriptor); |
| 38 } |
| 39 |
| 40 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 |
| 50 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 |
| 60 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 |
| 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 |
| 86 Handle<Map> MapUpdater::ReconfigureToDataField(int descriptor, |
| 87 PropertyAttributes attributes, |
| 88 Representation representation, |
| 89 Handle<FieldType> field_type) { |
| 90 DCHECK_EQ(kInitialized, state_); |
| 91 DCHECK_LE(0, descriptor); |
| 92 DCHECK(!old_map_->is_dictionary_map()); |
| 93 modified_descriptor_ = descriptor; |
| 94 new_kind_ = kData; |
| 95 new_attributes_ = attributes; |
| 96 new_location_ = kField; |
| 97 new_representation_ = representation; |
| 98 new_field_type_ = field_type; |
| 99 |
| 100 PropertyDetails old_details = |
| 101 old_descriptors_->GetDetails(modified_descriptor_); |
| 102 |
| 103 // If property kind is not reconfigured merge the result with |
| 104 // representation/field type from the old descriptor. |
| 105 if (old_details.kind() == new_kind_) { |
| 106 Representation old_representation = old_details.representation(); |
| 107 new_representation_ = new_representation_.generalize(old_representation); |
| 108 |
| 109 Handle<FieldType> old_field_type = |
| 110 GetOrComputeFieldType(old_descriptors_, modified_descriptor_, |
| 111 old_details.location(), new_representation_); |
| 112 |
| 113 new_field_type_ = Map::GeneralizeFieldType( |
| 114 old_representation, old_field_type, new_representation_, |
| 115 new_field_type_, isolate_); |
| 116 } |
| 117 |
| 118 if (TryRecofigureToDataFieldInplace() == kEnd) return result_map_; |
| 119 if (FindRootMap() == kEnd) return result_map_; |
| 120 if (FindTargetMap() == kEnd) return result_map_; |
| 121 ConstructNewMap(); |
| 122 DCHECK_EQ(kEnd, state_); |
| 123 return result_map_; |
| 124 } |
| 125 |
| 126 Handle<Map> MapUpdater::ReconfigureElementsKind(ElementsKind elements_kind) { |
| 127 DCHECK_EQ(kInitialized, state_); |
| 128 new_elements_kind_ = elements_kind; |
| 129 |
| 130 if (FindRootMap() == kEnd) return result_map_; |
| 131 if (FindTargetMap() == kEnd) return result_map_; |
| 132 ConstructNewMap(); |
| 133 DCHECK_EQ(kEnd, state_); |
| 134 return result_map_; |
| 135 } |
| 136 |
| 137 Handle<Map> MapUpdater::Update() { |
| 138 DCHECK_EQ(kInitialized, state_); |
| 139 DCHECK(old_map_->is_deprecated()); |
| 140 |
| 141 if (FindRootMap() == kEnd) return result_map_; |
| 142 if (FindTargetMap() == kEnd) return result_map_; |
| 143 ConstructNewMap(); |
| 144 DCHECK_EQ(kEnd, state_); |
| 145 return result_map_; |
| 146 } |
| 147 |
| 148 MapUpdater::State MapUpdater::CopyGeneralizeAllRepresentations( |
| 149 const char* reason) { |
| 150 StoreMode store_mode = |
| 151 modified_descriptor_ >= 0 ? FORCE_FIELD : ALLOW_IN_DESCRIPTOR; |
| 152 result_map_ = Map::CopyGeneralizeAllRepresentations( |
| 153 old_map_, new_elements_kind_, modified_descriptor_, store_mode, new_kind_, |
| 154 new_attributes_, reason); |
| 155 state_ = kEnd; |
| 156 return state_; // Done. |
| 157 } |
| 158 |
| 159 MapUpdater::State MapUpdater::TryRecofigureToDataFieldInplace() { |
| 160 // If it's just a representation generalization case (i.e. property kind and |
| 161 // attributes stays unchanged) it's fine to transition from None to anything |
| 162 // but double without any modification to the object, because the default |
| 163 // uninitialized value for representation None can be overwritten by both |
| 164 // smi and tagged values. Doubles, however, would require a box allocation. |
| 165 if (new_representation_.IsNone() || new_representation_.IsDouble()) { |
| 166 return state_; // Not done yet. |
| 167 } |
| 168 |
| 169 PropertyDetails old_details = |
| 170 old_descriptors_->GetDetails(modified_descriptor_); |
| 171 Representation old_representation = old_details.representation(); |
| 172 if (!old_representation.IsNone()) { |
| 173 return state_; // Not done yet. |
| 174 } |
| 175 |
| 176 DCHECK_EQ(new_kind_, old_details.kind()); |
| 177 DCHECK_EQ(new_attributes_, old_details.attributes()); |
| 178 DCHECK_EQ(kField, old_details.location()); |
| 179 if (FLAG_trace_generalization) { |
| 180 old_map_->PrintGeneralization( |
| 181 stdout, "uninitialized field", modified_descriptor_, old_nof_, old_nof_, |
| 182 false, old_representation, new_representation_, |
| 183 handle(old_descriptors_->GetFieldType(modified_descriptor_), isolate_), |
| 184 MaybeHandle<Object>(), new_field_type_, MaybeHandle<Object>()); |
| 185 } |
| 186 Handle<Map> field_owner(old_map_->FindFieldOwner(modified_descriptor_), |
| 187 isolate_); |
| 188 |
| 189 Map::GeneralizeField(field_owner, modified_descriptor_, new_representation_, |
| 190 new_field_type_); |
| 191 // Check that the descriptor array was updated. |
| 192 DCHECK(old_descriptors_->GetDetails(modified_descriptor_) |
| 193 .representation() |
| 194 .Equals(new_representation_)); |
| 195 DCHECK(old_descriptors_->GetFieldType(modified_descriptor_) |
| 196 ->NowIs(new_field_type_)); |
| 197 |
| 198 result_map_ = old_map_; |
| 199 state_ = kEnd; |
| 200 return state_; // Done. |
| 201 } |
| 202 |
| 203 MapUpdater::State MapUpdater::FindRootMap() { |
| 204 DCHECK_EQ(kInitialized, state_); |
| 205 // Check the state of the root map. |
| 206 root_map_ = handle(old_map_->FindRootMap(), isolate_); |
| 207 int root_nof = root_map_->NumberOfOwnDescriptors(); |
| 208 if (!old_map_->EquivalentToForTransition(*root_map_)) { |
| 209 return CopyGeneralizeAllRepresentations("GenAll_NotEquivalent"); |
| 210 } |
| 211 |
| 212 ElementsKind from_kind = root_map_->elements_kind(); |
| 213 ElementsKind to_kind = new_elements_kind_; |
| 214 // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. |
| 215 if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && |
| 216 to_kind != SLOW_STRING_WRAPPER_ELEMENTS && |
| 217 to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && |
| 218 !(IsTransitionableFastElementsKind(from_kind) && |
| 219 IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { |
| 220 return CopyGeneralizeAllRepresentations("GenAll_InvalidElementsTransition"); |
| 221 } |
| 222 |
| 223 if (modified_descriptor_ >= 0 && modified_descriptor_ < root_nof) { |
| 224 PropertyDetails old_details = |
| 225 old_descriptors_->GetDetails(modified_descriptor_); |
| 226 if (old_details.kind() != new_kind_ || |
| 227 old_details.attributes() != new_attributes_) { |
| 228 return CopyGeneralizeAllRepresentations("GenAll_RootModification1"); |
| 229 } |
| 230 if (!new_representation_.fits_into(old_details.representation())) { |
| 231 return CopyGeneralizeAllRepresentations("GenAll_RootModification2"); |
| 232 } |
| 233 if (old_details.location() != kField) { |
| 234 return CopyGeneralizeAllRepresentations("GenAll_RootModification3"); |
| 235 } |
| 236 DCHECK_EQ(kData, old_details.kind()); |
| 237 DCHECK_EQ(kData, new_kind_); |
| 238 DCHECK_EQ(kField, new_location_); |
| 239 FieldType* old_field_type = |
| 240 old_descriptors_->GetFieldType(modified_descriptor_); |
| 241 if (!new_field_type_->NowIs(old_field_type)) { |
| 242 return CopyGeneralizeAllRepresentations("GenAll_RootModification4"); |
| 243 } |
| 244 } |
| 245 |
| 246 // From here on, use the map with correct elements kind as root map. |
| 247 if (from_kind != to_kind) { |
| 248 root_map_ = Map::AsElementsKind(root_map_, to_kind); |
| 249 } |
| 250 state_ = kAtRootMap; |
| 251 return state_; // Not done yet. |
| 252 } |
| 253 |
| 254 MapUpdater::State MapUpdater::FindTargetMap() { |
| 255 DCHECK_EQ(kAtRootMap, state_); |
| 256 target_map_ = root_map_; |
| 257 |
| 258 int root_nof = root_map_->NumberOfOwnDescriptors(); |
| 259 for (int i = root_nof; i < old_nof_; ++i) { |
| 260 PropertyDetails old_details = GetDetails(i); |
| 261 Map* transition = TransitionArray::SearchTransition( |
| 262 *target_map_, old_details.kind(), GetKey(i), old_details.attributes()); |
| 263 if (transition == NULL) break; |
| 264 Handle<Map> tmp_map(transition, isolate_); |
| 265 |
| 266 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(), |
| 267 isolate_); |
| 268 |
| 269 // Check if target map is incompatible. |
| 270 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); |
| 271 DCHECK_EQ(old_details.kind(), tmp_details.kind()); |
| 272 DCHECK_EQ(old_details.attributes(), tmp_details.attributes()); |
| 273 if (old_details.kind() == kAccessor && |
| 274 !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) { |
| 275 // TODO(ishell): mutable accessors are not implemented yet. |
| 276 return CopyGeneralizeAllRepresentations("GenAll_Incompatible"); |
| 277 } |
| 278 // Check if old location fits into tmp location. |
| 279 if (old_details.location() == kField && |
| 280 tmp_details.location() == kDescriptor) { |
| 281 break; |
| 282 } |
| 283 |
| 284 // Check if old representation fits into tmp representation. |
| 285 Representation tmp_representation = tmp_details.representation(); |
| 286 if (!old_details.representation().fits_into(tmp_representation)) { |
| 287 break; |
| 288 } |
| 289 |
| 290 if (tmp_details.location() == kField) { |
| 291 Handle<FieldType> old_field_type = |
| 292 GetOrComputeFieldType(i, old_details.location(), tmp_representation); |
| 293 Map::GeneralizeField(tmp_map, i, tmp_representation, old_field_type); |
| 294 } else { |
| 295 // kDescriptor: Check that the value matches. |
| 296 if (!EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) { |
| 297 break; |
| 298 } |
| 299 } |
| 300 DCHECK(!tmp_map->is_deprecated()); |
| 301 target_map_ = tmp_map; |
| 302 } |
| 303 |
| 304 // Directly change the map if the target map is more general. |
| 305 int target_nof = target_map_->NumberOfOwnDescriptors(); |
| 306 if (target_nof == old_nof_) { |
| 307 #ifdef DEBUG |
| 308 if (modified_descriptor_ >= 0) { |
| 309 DescriptorArray* target_descriptors = target_map_->instance_descriptors(); |
| 310 PropertyDetails details = |
| 311 target_descriptors->GetDetails(modified_descriptor_); |
| 312 DCHECK_EQ(new_kind_, details.kind()); |
| 313 DCHECK_EQ(new_attributes_, details.attributes()); |
| 314 DCHECK_EQ(new_location_, details.location()); |
| 315 DCHECK(new_representation_.fits_into(details.representation())); |
| 316 if (new_location_ == kField) { |
| 317 DCHECK_EQ(kField, details.location()); |
| 318 DCHECK(new_field_type_->NowIs( |
| 319 target_descriptors->GetFieldType(modified_descriptor_))); |
| 320 } else { |
| 321 DCHECK(details.location() == kField || |
| 322 EqualImmutableValues(*new_value_, target_descriptors->GetValue( |
| 323 modified_descriptor_))); |
| 324 } |
| 325 } |
| 326 #endif |
| 327 if (*target_map_ != *old_map_) { |
| 328 old_map_->NotifyLeafMapLayoutChange(); |
| 329 } |
| 330 result_map_ = target_map_; |
| 331 state_ = kEnd; |
| 332 return state_; // Done. |
| 333 } |
| 334 |
| 335 // Find the last compatible target map in the transition tree. |
| 336 for (int i = target_nof; i < old_nof_; ++i) { |
| 337 PropertyDetails old_details = GetDetails(i); |
| 338 Map* transition = TransitionArray::SearchTransition( |
| 339 *target_map_, old_details.kind(), GetKey(i), old_details.attributes()); |
| 340 if (transition == NULL) break; |
| 341 Handle<Map> tmp_map(transition, isolate_); |
| 342 Handle<DescriptorArray> tmp_descriptors(tmp_map->instance_descriptors(), |
| 343 isolate_); |
| 344 |
| 345 #ifdef DEBUG |
| 346 // Check that target map is compatible. |
| 347 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i); |
| 348 DCHECK_EQ(old_details.kind(), tmp_details.kind()); |
| 349 DCHECK_EQ(old_details.attributes(), tmp_details.attributes()); |
| 350 #endif |
| 351 if (old_details.kind() == kAccessor && |
| 352 !EqualImmutableValues(GetValue(i), tmp_descriptors->GetValue(i))) { |
| 353 return CopyGeneralizeAllRepresentations("GenAll_Incompatible"); |
| 354 } |
| 355 DCHECK(!tmp_map->is_deprecated()); |
| 356 target_map_ = tmp_map; |
| 357 } |
| 358 |
| 359 state_ = kAtTargetMap; |
| 360 return state_; // Not done yet. |
| 361 } |
| 362 |
| 363 Handle<DescriptorArray> MapUpdater::BuildDescriptorArray() { |
| 364 int target_nof = target_map_->NumberOfOwnDescriptors(); |
| 365 Handle<DescriptorArray> target_descriptors( |
| 366 target_map_->instance_descriptors(), isolate_); |
| 367 |
| 368 // Allocate a new descriptor array large enough to hold the required |
| 369 // descriptors, with minimally the exact same size as the old descriptor |
| 370 // array. |
| 371 int new_slack = |
| 372 Max(old_nof_, old_descriptors_->number_of_descriptors()) - old_nof_; |
| 373 Handle<DescriptorArray> new_descriptors = |
| 374 DescriptorArray::Allocate(isolate_, old_nof_, new_slack); |
| 375 DCHECK(new_descriptors->length() > target_descriptors->length() || |
| 376 new_descriptors->NumberOfSlackDescriptors() > 0 || |
| 377 new_descriptors->number_of_descriptors() == |
| 378 old_descriptors_->number_of_descriptors()); |
| 379 DCHECK(new_descriptors->number_of_descriptors() == old_nof_); |
| 380 |
| 381 int root_nof = root_map_->NumberOfOwnDescriptors(); |
| 382 |
| 383 // Given that we passed root modification check in FindRootMap() so |
| 384 // the root descriptors are either not modified at all or already more |
| 385 // general than we requested. Take |root_nof| entries as is. |
| 386 // 0 -> |root_nof| |
| 387 int current_offset = 0; |
| 388 for (int i = 0; i < root_nof; ++i) { |
| 389 PropertyDetails old_details = old_descriptors_->GetDetails(i); |
| 390 if (old_details.location() == kField) { |
| 391 current_offset += old_details.field_width_in_words(); |
| 392 } |
| 393 Descriptor d(handle(GetKey(i), isolate_), |
| 394 handle(old_descriptors_->GetValue(i), isolate_), old_details); |
| 395 new_descriptors->Set(i, &d); |
| 396 } |
| 397 |
| 398 // Merge "updated" old_descriptor entries with target_descriptor entries. |
| 399 // |root_nof| -> |target_nof| |
| 400 for (int i = root_nof; i < target_nof; ++i) { |
| 401 Handle<Name> key(GetKey(i), isolate_); |
| 402 PropertyDetails old_details = GetDetails(i); |
| 403 PropertyDetails target_details = target_descriptors->GetDetails(i); |
| 404 |
| 405 PropertyKind next_kind = old_details.kind(); |
| 406 PropertyAttributes next_attributes = old_details.attributes(); |
| 407 PropertyLocation next_location = |
| 408 old_details.location() == kField || |
| 409 target_details.location() == kField || |
| 410 !EqualImmutableValues(target_descriptors->GetValue(i), |
| 411 GetValue(i)) |
| 412 ? kField |
| 413 : kDescriptor; |
| 414 |
| 415 Representation next_representation = |
| 416 old_details.representation().generalize( |
| 417 target_details.representation()); |
| 418 |
| 419 DCHECK_EQ(next_kind, target_details.kind()); |
| 420 DCHECK_EQ(next_attributes, target_details.attributes()); |
| 421 |
| 422 if (next_location == kField) { |
| 423 Handle<FieldType> old_field_type = |
| 424 GetOrComputeFieldType(i, old_details.location(), next_representation); |
| 425 |
| 426 Handle<FieldType> target_field_type = |
| 427 GetOrComputeFieldType(target_descriptors, i, |
| 428 target_details.location(), next_representation); |
| 429 |
| 430 Handle<FieldType> next_field_type = Map::GeneralizeFieldType( |
| 431 old_details.representation(), old_field_type, next_representation, |
| 432 target_field_type, isolate_); |
| 433 |
| 434 Handle<Object> wrapped_type(Map::WrapType(next_field_type)); |
| 435 Descriptor d; |
| 436 if (next_kind == kData) { |
| 437 d = Descriptor::DataField(key, current_offset, wrapped_type, |
| 438 next_attributes, next_representation); |
| 439 } else { |
| 440 // TODO(ishell): mutable accessors are not implemented yet. |
| 441 UNIMPLEMENTED(); |
| 442 } |
| 443 current_offset += d.GetDetails().field_width_in_words(); |
| 444 new_descriptors->Set(i, &d); |
| 445 } else { |
| 446 DCHECK_EQ(kDescriptor, next_location); |
| 447 |
| 448 Handle<Object> value(GetValue(i), isolate_); |
| 449 Descriptor d; |
| 450 if (next_kind == kData) { |
| 451 d = Descriptor::DataConstant(key, value, next_attributes); |
| 452 } else { |
| 453 DCHECK_EQ(kAccessor, next_kind); |
| 454 d = Descriptor::AccessorConstant(key, value, next_attributes); |
| 455 } |
| 456 new_descriptors->Set(i, &d); |
| 457 } |
| 458 } |
| 459 |
| 460 // Take "updated" old_descriptor entries. |
| 461 // |target_nof| -> |old_nof| |
| 462 for (int i = target_nof; i < old_nof_; ++i) { |
| 463 PropertyDetails old_details = GetDetails(i); |
| 464 Handle<Name> key(GetKey(i), isolate_); |
| 465 |
| 466 PropertyKind next_kind = old_details.kind(); |
| 467 PropertyAttributes next_attributes = old_details.attributes(); |
| 468 PropertyLocation next_location = old_details.location(); |
| 469 Representation next_representation = old_details.representation(); |
| 470 |
| 471 Descriptor d; |
| 472 if (next_location == kField) { |
| 473 Handle<FieldType> old_field_type = |
| 474 GetOrComputeFieldType(i, old_details.location(), next_representation); |
| 475 |
| 476 Handle<Object> wrapped_type(Map::WrapType(old_field_type)); |
| 477 Descriptor d; |
| 478 if (next_kind == kData) { |
| 479 d = Descriptor::DataField(key, current_offset, wrapped_type, |
| 480 next_attributes, next_representation); |
| 481 } else { |
| 482 // TODO(ishell): mutable accessors are not implemented yet. |
| 483 UNIMPLEMENTED(); |
| 484 } |
| 485 current_offset += d.GetDetails().field_width_in_words(); |
| 486 new_descriptors->Set(i, &d); |
| 487 } else { |
| 488 DCHECK_EQ(kDescriptor, next_location); |
| 489 |
| 490 Handle<Object> value(GetValue(i), isolate_); |
| 491 if (next_kind == kData) { |
| 492 d = Descriptor::DataConstant(key, value, next_attributes); |
| 493 } else { |
| 494 DCHECK_EQ(kAccessor, next_kind); |
| 495 d = Descriptor::AccessorConstant(key, value, next_attributes); |
| 496 } |
| 497 new_descriptors->Set(i, &d); |
| 498 } |
| 499 } |
| 500 |
| 501 new_descriptors->Sort(); |
| 502 return new_descriptors; |
| 503 } |
| 504 |
| 505 Handle<Map> MapUpdater::FindSplitMap(Handle<DescriptorArray> descriptors) { |
| 506 DisallowHeapAllocation no_allocation; |
| 507 |
| 508 int root_nof = root_map_->NumberOfOwnDescriptors(); |
| 509 Map* current = *root_map_; |
| 510 for (int i = root_nof; i < old_nof_; i++) { |
| 511 Name* name = descriptors->GetKey(i); |
| 512 PropertyDetails details = descriptors->GetDetails(i); |
| 513 Map* next = TransitionArray::SearchTransition(current, details.kind(), name, |
| 514 details.attributes()); |
| 515 if (next == NULL) break; |
| 516 DescriptorArray* next_descriptors = next->instance_descriptors(); |
| 517 |
| 518 PropertyDetails next_details = next_descriptors->GetDetails(i); |
| 519 DCHECK_EQ(details.kind(), next_details.kind()); |
| 520 DCHECK_EQ(details.attributes(), next_details.attributes()); |
| 521 if (details.location() != next_details.location()) break; |
| 522 if (!details.representation().Equals(next_details.representation())) break; |
| 523 |
| 524 if (next_details.location() == kField) { |
| 525 FieldType* next_field_type = next_descriptors->GetFieldType(i); |
| 526 if (!descriptors->GetFieldType(i)->NowIs(next_field_type)) { |
| 527 break; |
| 528 } |
| 529 } else { |
| 530 if (!EqualImmutableValues(descriptors->GetValue(i), |
| 531 next_descriptors->GetValue(i))) { |
| 532 break; |
| 533 } |
| 534 } |
| 535 current = next; |
| 536 } |
| 537 return handle(current, isolate_); |
| 538 } |
| 539 |
| 540 MapUpdater::State MapUpdater::ConstructNewMap() { |
| 541 Handle<DescriptorArray> new_descriptors = BuildDescriptorArray(); |
| 542 |
| 543 Handle<Map> split_map = FindSplitMap(new_descriptors); |
| 544 int split_nof = split_map->NumberOfOwnDescriptors(); |
| 545 DCHECK_NE(old_nof_, split_nof); |
| 546 |
| 547 PropertyDetails split_details = GetDetails(split_nof); |
| 548 |
| 549 // Invalidate a transition target at |key|. |
| 550 Map* maybe_transition = TransitionArray::SearchTransition( |
| 551 *split_map, split_details.kind(), GetKey(split_nof), |
| 552 split_details.attributes()); |
| 553 if (maybe_transition != NULL) { |
| 554 maybe_transition->DeprecateTransitionTree(); |
| 555 } |
| 556 |
| 557 // If |maybe_transition| is not NULL then the transition array already |
| 558 // contains entry for given descriptor. This means that the transition |
| 559 // could be inserted regardless of whether transitions array is full or not. |
| 560 if (maybe_transition == NULL && |
| 561 !TransitionArray::CanHaveMoreTransitions(split_map)) { |
| 562 return CopyGeneralizeAllRepresentations("GenAll_CantHaveMoreTransitions"); |
| 563 } |
| 564 |
| 565 old_map_->NotifyLeafMapLayoutChange(); |
| 566 |
| 567 if (FLAG_trace_generalization && modified_descriptor_ >= 0) { |
| 568 PropertyDetails old_details = |
| 569 old_descriptors_->GetDetails(modified_descriptor_); |
| 570 PropertyDetails new_details = |
| 571 new_descriptors->GetDetails(modified_descriptor_); |
| 572 MaybeHandle<FieldType> old_field_type; |
| 573 MaybeHandle<FieldType> new_field_type; |
| 574 MaybeHandle<Object> old_value; |
| 575 MaybeHandle<Object> new_value; |
| 576 if (old_details.type() == DATA) { |
| 577 old_field_type = handle( |
| 578 old_descriptors_->GetFieldType(modified_descriptor_), isolate_); |
| 579 } else { |
| 580 old_value = |
| 581 handle(old_descriptors_->GetValue(modified_descriptor_), isolate_); |
| 582 } |
| 583 if (new_details.type() == DATA) { |
| 584 new_field_type = |
| 585 handle(new_descriptors->GetFieldType(modified_descriptor_), isolate_); |
| 586 } else { |
| 587 new_value = |
| 588 handle(new_descriptors->GetValue(modified_descriptor_), isolate_); |
| 589 } |
| 590 |
| 591 old_map_->PrintGeneralization( |
| 592 stdout, "", modified_descriptor_, split_nof, old_nof_, |
| 593 old_details.location() == kDescriptor && new_location_ == kField, |
| 594 old_details.representation(), new_details.representation(), |
| 595 old_field_type, old_value, new_field_type, new_value); |
| 596 } |
| 597 |
| 598 Handle<LayoutDescriptor> new_layout_descriptor = |
| 599 LayoutDescriptor::New(split_map, new_descriptors, old_nof_); |
| 600 |
| 601 Handle<Map> new_map = Map::AddMissingTransitions(split_map, new_descriptors, |
| 602 new_layout_descriptor); |
| 603 |
| 604 // Deprecated part of the transition tree is no longer reachable, so replace |
| 605 // current instance descriptors in the "survived" part of the tree with |
| 606 // the new descriptors to maintain descriptors sharing invariant. |
| 607 split_map->ReplaceDescriptors(*new_descriptors, *new_layout_descriptor); |
| 608 |
| 609 result_map_ = new_map; |
| 610 state_ = kEnd; |
| 611 return state_; // Done. |
| 612 } |
| 613 |
| 614 } // namespace internal |
| 615 } // namespace v8 |
OLD | NEW |