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