1 // Copyright 2015 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 <stdlib.h> 6 #include <utility> 7 8 #include "test/cctest/test-api.h" 9 10 #include "src/v8.h" 11 12 #include "src/compilation-cache.h" 13 #include "src/execution.h" 14 #include "src/factory.h" 15 #include "src/field-type.h" 16 #include "src/global-handles.h" 17 #include "src/ic/stub-cache.h" 18 #include "src/macro-assembler.h" 19 20 using namespace v8::internal; 21 22 23 // TODO(ishell): fix this once TransitionToPrototype stops generalizing 24 // all field representations (similar to crbug/448711 where elements kind 25 // and observed transitions caused generalization of all field representations). 26 const bool IS_PROTO_TRANS_ISSUE_FIXED = false; 27 28 29 // TODO(ishell): fix this once TransitionToAccessorProperty is able to always 30 // keep map in fast mode. 31 const bool IS_ACCESSOR_FIELD_SUPPORTED = false; 32 33 34 // Number of properties used in the tests. 35 const int kPropCount = 7; 36 37 38 // 39 // Helper functions. 40 // 41 42 static Handle<String> MakeString(const char* str) { 43 Isolate* isolate = CcTest::i_isolate(); 44 Factory* factory = isolate->factory(); 45 return factory->InternalizeUtf8String(str); 46 } 47 48 49 static Handle<String> MakeName(const char* str, int suffix) { 50 EmbeddedVector<char, 128> buffer; 51 SNPrintF(buffer, "%s%d", str, suffix); 52 return MakeString(buffer.start()); 53 } 54 55 56 static Handle<AccessorPair> CreateAccessorPair(bool with_getter, 57 bool with_setter) { 58 Isolate* isolate = CcTest::i_isolate(); 59 Factory* factory = isolate->factory(); 60 Handle<AccessorPair> pair = factory->NewAccessorPair(); 61 Handle<String> empty_string = factory->empty_string(); 62 if (with_getter) { 63 Handle<JSFunction> func = factory->NewFunction(empty_string); 64 pair->set_getter(*func); 65 } 66 if (with_setter) { 67 Handle<JSFunction> func = factory->NewFunction(empty_string); 68 pair->set_setter(*func); 69 } 70 return pair; 71 } 72 73 74 static bool EqualDetails(DescriptorArray* descriptors, int descriptor, 75 PropertyType type, PropertyAttributes attributes, 76 Representation representation, int field_index = -1) { 77 PropertyDetails details = descriptors->GetDetails(descriptor); 78 if (details.type() != type) return false; 79 if (details.attributes() != attributes) return false; 80 if (!details.representation().Equals(representation)) return false; 81 if (field_index >= 0 && details.field_index() != field_index) return false; 82 return true; 83 } 84 85 86 class Expectations { 87 static const int MAX_PROPERTIES = 10; 88 Isolate* isolate_; 89 ElementsKind elements_kind_; 90 PropertyType types_[MAX_PROPERTIES]; 91 PropertyAttributes attributes_[MAX_PROPERTIES]; 92 Representation representations_[MAX_PROPERTIES]; 93 // FieldType for kField, value for DATA_CONSTANT and getter for 94 // ACCESSOR_CONSTANT. 95 Handle<Object> values_[MAX_PROPERTIES]; 96 // Setter for ACCESSOR_CONSTANT. 97 Handle<Object> setter_values_[MAX_PROPERTIES]; 98 int number_of_properties_; 99 100 public: 101 explicit Expectations(Isolate* isolate, ElementsKind elements_kind) 102 : isolate_(isolate), 103 elements_kind_(elements_kind), 104 number_of_properties_(0) {} 105 106 explicit Expectations(Isolate* isolate) 107 : Expectations( 108 isolate, 109 isolate->object_function()->initial_map()->elements_kind()) {} 110 111 void Init(int index, PropertyType type, PropertyAttributes attributes, 112 Representation representation, Handle<Object> value) { 113 CHECK(index < MAX_PROPERTIES); 114 types_[index] = type; 115 attributes_[index] = attributes; 116 representations_[index] = representation; 117 values_[index] = value; 118 } 119 120 void Print() const { 121 OFStream os(stdout); 122 os << "Expectations: #" << number_of_properties_ << "\n"; 123 for (int i = 0; i < number_of_properties_; i++) { 124 os << " " << i << ": "; 125 os << "Descriptor @ "; 126 if (types_[i] == ACCESSOR_CONSTANT) { 127 os << "(get: " << Brief(*values_[i]) 128 << ", set: " << Brief(*setter_values_[i]) << ") "; 129 } else { 130 os << Brief(*values_[i]); 131 } 132 os << " ("; 133 switch (types_[i]) { 134 case DATA_CONSTANT: 135 os << "immutable "; 136 // Fall through. 137 case DATA: 138 os << "data"; 139 break; 140 141 case ACCESSOR_CONSTANT: 142 os << "immutable "; 143 // Fall through. 144 case ACCESSOR: 145 os << "accessor"; 146 break; 147 } 148 os << ": " << representations_[i].Mnemonic(); 149 os << ", attrs: " << attributes_[i] << ")\n"; 150 } 151 os << "\n"; 152 } 153 154 void SetElementsKind(ElementsKind elements_kind) { 155 elements_kind_ = elements_kind; 156 } 157 158 Handle<FieldType> GetFieldType(int index) { 159 CHECK(index < MAX_PROPERTIES); 160 CHECK(types_[index] == DATA || types_[index] == ACCESSOR); 161 return Handle<FieldType>::cast(values_[index]); 162 } 163 164 void SetDataField(int index, PropertyAttributes attrs, 165 Representation representation, Handle<FieldType> value) { 166 Init(index, DATA, attrs, representation, value); 167 } 168 169 void SetDataField(int index, Representation representation, 170 Handle<FieldType> value) { 171 SetDataField(index, attributes_[index], representation, value); 172 } 173 174 void SetAccessorField(int index, PropertyAttributes attrs) { 175 Init(index, ACCESSOR, attrs, Representation::Tagged(), 176 FieldType::Any(isolate_)); 177 } 178 179 void SetAccessorField(int index) { 180 SetAccessorField(index, attributes_[index]); 181 } 182 183 void SetDataConstant(int index, PropertyAttributes attrs, 184 Handle<JSFunction> value) { 185 Init(index, DATA_CONSTANT, attrs, Representation::HeapObject(), value); 186 } 187 188 void SetDataConstant(int index, Handle<JSFunction> value) { 189 SetDataConstant(index, attributes_[index], value); 190 } 191 192 void SetAccessorConstant(int index, PropertyAttributes attrs, 193 Handle<Object> getter, Handle<Object> setter) { 194 Init(index, ACCESSOR_CONSTANT, attrs, Representation::Tagged(), getter); 195 setter_values_[index] = setter; 196 } 197 198 void SetAccessorConstantComponent(int index, PropertyAttributes attrs, 199 AccessorComponent component, 200 Handle<Object> accessor) { 201 CHECK_EQ(ACCESSOR_CONSTANT, types_[index]); 202 CHECK(index < number_of_properties_); 203 if (component == ACCESSOR_GETTER) { 204 values_[index] = accessor; 205 } else { 206 setter_values_[index] = accessor; 207 } 208 } 209 210 void SetAccessorConstant(int index, PropertyAttributes attrs, 211 Handle<AccessorPair> pair) { 212 Handle<Object> getter = handle(pair->getter(), isolate_); 213 Handle<Object> setter = handle(pair->setter(), isolate_); 214 SetAccessorConstant(index, attrs, getter, setter); 215 } 216 217 void SetAccessorConstant(int index, Handle<Object> getter, 218 Handle<Object> setter) { 219 SetAccessorConstant(index, attributes_[index], getter, setter); 220 } 221 222 void SetAccessorConstant(int index, Handle<AccessorPair> pair) { 223 Handle<Object> getter = handle(pair->getter(), isolate_); 224 Handle<Object> setter = handle(pair->setter(), isolate_); 225 SetAccessorConstant(index, getter, setter); 226 } 227 228 void GeneralizeRepresentation(int index) { 229 CHECK(index < number_of_properties_); 230 representations_[index] = Representation::Tagged(); 231 if (types_[index] == DATA || types_[index] == ACCESSOR) { 232 values_[index] = FieldType::Any(isolate_); 233 } 234 } 235 236 237 bool Check(DescriptorArray* descriptors, int descriptor) const { 238 PropertyType type = types_[descriptor]; 239 if (!EqualDetails(descriptors, descriptor, type, attributes_[descriptor], 240 representations_[descriptor])) { 241 return false; 242 } 243 Object* value = descriptors->GetValue(descriptor); 244 Object* expected_value = *values_[descriptor]; 245 switch (type) { 246 case DATA: 247 case ACCESSOR: { 248 FieldType* type = descriptors->GetFieldType(descriptor); 249 return FieldType::cast(expected_value) == type; 250 } 251 252 case DATA_CONSTANT: 253 return value == expected_value; 254 255 case ACCESSOR_CONSTANT: { 256 if (value == expected_value) return true; 257 if (!value->IsAccessorPair()) return false; 258 AccessorPair* pair = AccessorPair::cast(value); 259 return pair->Equals(expected_value, *setter_values_[descriptor]); 260 } 261 } 262 UNREACHABLE(); 263 return false; 264 } 265 266 bool Check(Map* map, int expected_nof) const { 267 CHECK_EQ(elements_kind_, map->elements_kind()); 268 CHECK(number_of_properties_ <= MAX_PROPERTIES); 269 CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors()); 270 CHECK(!map->is_dictionary_map()); 271 272 DescriptorArray* descriptors = map->instance_descriptors(); 273 CHECK(expected_nof <= number_of_properties_); 274 for (int i = 0; i < expected_nof; i++) { 275 if (!Check(descriptors, i)) { 276 Print(); 277 #ifdef OBJECT_PRINT 278 descriptors->Print(); 279 #endif 280 Check(descriptors, i); 281 return false; 282 } 283 } 284 return true; 285 } 286 287 bool Check(Map* map) const { return Check(map, number_of_properties_); } 288 289 290 // 291 // Helper methods for initializing expectations and adding properties to 292 // given |map|. 293 // 294 295 Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) { 296 elements_kind_ = elements_kind; 297 map = Map::AsElementsKind(map, elements_kind); 298 CHECK_EQ(elements_kind_, map->elements_kind()); 299 return map; 300 } 301 302 Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes, 303 Representation representation, 304 Handle<FieldType> heap_type) { 305 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 306 int property_index = number_of_properties_++; 307 SetDataField(property_index, attributes, representation, heap_type); 308 309 Handle<String> name = MakeName("prop", property_index); 310 return Map::CopyWithField(map, name, heap_type, attributes, representation, 311 INSERT_TRANSITION) 312 .ToHandleChecked(); 313 } 314 315 Handle<Map> AddDataConstant(Handle<Map> map, PropertyAttributes attributes, 316 Handle<JSFunction> value) { 317 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 318 int property_index = number_of_properties_++; 319 SetDataConstant(property_index, attributes, value); 320 321 Handle<String> name = MakeName("prop", property_index); 322 return Map::CopyWithConstant(map, name, value, attributes, 323 INSERT_TRANSITION) 324 .ToHandleChecked(); 325 } 326 327 Handle<Map> TransitionToDataField(Handle<Map> map, 328 PropertyAttributes attributes, 329 Representation representation, 330 Handle<FieldType> heap_type, 331 Handle<Object> value) { 332 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 333 int property_index = number_of_properties_++; 334 SetDataField(property_index, attributes, representation, heap_type); 335 336 Handle<String> name = MakeName("prop", property_index); 337 return Map::TransitionToDataProperty( 338 map, name, value, attributes, Object::CERTAINLY_NOT_STORE_FROM_KEYED); 339 } 340 341 Handle<Map> TransitionToDataConstant(Handle<Map> map, 342 PropertyAttributes attributes, 343 Handle<JSFunction> value) { 344 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 345 int property_index = number_of_properties_++; 346 SetDataConstant(property_index, attributes, value); 347 348 Handle<String> name = MakeName("prop", property_index); 349 return Map::TransitionToDataProperty( 350 map, name, value, attributes, Object::CERTAINLY_NOT_STORE_FROM_KEYED); 351 } 352 353 Handle<Map> FollowDataTransition(Handle<Map> map, 354 PropertyAttributes attributes, 355 Representation representation, 356 Handle<FieldType> heap_type) { 357 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 358 int property_index = number_of_properties_++; 359 SetDataField(property_index, attributes, representation, heap_type); 360 361 Handle<String> name = MakeName("prop", property_index); 362 Map* target = 363 TransitionArray::SearchTransition(*map, kData, *name, attributes); 364 CHECK(target != NULL); 365 return handle(target); 366 } 367 368 Handle<Map> AddAccessorConstant(Handle<Map> map, 369 PropertyAttributes attributes, 370 Handle<AccessorPair> pair) { 371 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 372 int property_index = number_of_properties_++; 373 SetAccessorConstant(property_index, attributes, pair); 374 375 Handle<String> name = MakeName("prop", property_index); 376 377 AccessorConstantDescriptor new_desc(name, pair, attributes); 378 return Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION); 379 } 380 381 Handle<Map> AddAccessorConstant(Handle<Map> map, 382 PropertyAttributes attributes, 383 Handle<Object> getter, 384 Handle<Object> setter) { 385 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 386 int property_index = number_of_properties_++; 387 SetAccessorConstant(property_index, attributes, getter, setter); 388 389 Handle<String> name = MakeName("prop", property_index); 390 391 CHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_)); 392 Factory* factory = isolate_->factory(); 393 394 if (!getter->IsNull(isolate_)) { 395 Handle<AccessorPair> pair = factory->NewAccessorPair(); 396 pair->SetComponents(*getter, *factory->null_value()); 397 AccessorConstantDescriptor new_desc(name, pair, attributes); 398 map = Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION); 399 } 400 if (!setter->IsNull(isolate_)) { 401 Handle<AccessorPair> pair = factory->NewAccessorPair(); 402 pair->SetComponents(*getter, *setter); 403 AccessorConstantDescriptor new_desc(name, pair, attributes); 404 map = Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION); 405 } 406 return map; 407 } 408 409 Handle<Map> TransitionToAccessorConstant(Handle<Map> map, 410 PropertyAttributes attributes, 411 Handle<AccessorPair> pair) { 412 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); 413 int property_index = number_of_properties_++; 414 SetAccessorConstant(property_index, attributes, pair); 415 416 Handle<String> name = MakeName("prop", property_index); 417 418 Isolate* isolate = CcTest::i_isolate(); 419 Handle<Object> getter(pair->getter(), isolate); 420 Handle<Object> setter(pair->setter(), isolate); 421 422 int descriptor = 423 map->instance_descriptors()->SearchWithCache(isolate, *name, *map); 424 map = Map::TransitionToAccessorProperty(isolate, map, name, descriptor, 425 getter, setter, attributes); 426 CHECK(!map->is_deprecated()); 427 CHECK(!map->is_dictionary_map()); 428 return map; 429 } 430 }; 431 432 433 //////////////////////////////////////////////////////////////////////////////// 434 // A set of tests for property reconfiguration that makes new transition tree 435 // branch. 436 // 437 438 TEST(ReconfigureAccessorToNonExistingDataField) { 439 CcTest::InitializeVM(); 440 v8::HandleScope scope(CcTest::isolate()); 441 Isolate* isolate = CcTest::i_isolate(); 442 Handle<FieldType> any_type = FieldType::Any(isolate); 443 Handle<FieldType> none_type = FieldType::None(isolate); 444 Handle<AccessorPair> pair = CreateAccessorPair(true, true); 445 446 Expectations expectations(isolate); 447 448 // Create a map, add required properties to it and initialize expectations. 449 Handle<Map> initial_map = Map::Create(isolate, 0); 450 Handle<Map> map = initial_map; 451 map = expectations.AddAccessorConstant(map, NONE, pair); 452 453 CHECK(!map->is_deprecated()); 454 CHECK(map->is_stable()); 455 CHECK(expectations.Check(*map)); 456 457 Handle<Map> new_map = Map::ReconfigureProperty( 458 map, 0, kData, NONE, Representation::None(), none_type, FORCE_FIELD); 459 // |map| did not change except marked unstable. 460 CHECK(!map->is_deprecated()); 461 CHECK(!map->is_stable()); 462 CHECK(expectations.Check(*map)); 463 464 expectations.SetDataField(0, NONE, Representation::None(), none_type); 465 466 CHECK(!new_map->is_deprecated()); 467 CHECK(new_map->is_stable()); 468 CHECK(expectations.Check(*new_map)); 469 470 Handle<Map> new_map2 = Map::ReconfigureProperty( 471 map, 0, kData, NONE, Representation::None(), none_type, FORCE_FIELD); 472 CHECK_EQ(*new_map, *new_map2); 473 474 Handle<Object> value(Smi::FromInt(0), isolate); 475 Handle<Map> prepared_map = Map::PrepareForDataProperty(new_map, 0, value); 476 // None to Smi generalization is trivial, map does not change. 477 CHECK_EQ(*new_map, *prepared_map); 478 479 expectations.SetDataField(0, NONE, Representation::Smi(), any_type); 480 CHECK(prepared_map->is_stable()); 481 CHECK(expectations.Check(*prepared_map)); 482 483 // Now create an object with |map|, migrate it to |prepared_map| and ensure 484 // that the data property is uninitialized. 485 Factory* factory = isolate->factory(); 486 Handle<JSObject> obj = factory->NewJSObjectFromMap(map); 487 JSObject::MigrateToMap(obj, prepared_map); 488 FieldIndex index = FieldIndex::ForDescriptor(*prepared_map, 0); 489 CHECK(obj->RawFastPropertyAt(index)->IsUninitialized(isolate)); 490 #ifdef VERIFY_HEAP 491 obj->ObjectVerify(); 492 #endif 493 } 494 495 496 // This test checks that the LookupIterator machinery involved in 497 // JSObject::SetOwnPropertyIgnoreAttributes() does not try to migrate object 498 // to a map with a property with None representation. 499 TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) { 500 CcTest::InitializeVM(); 501 Isolate* isolate = CcTest::i_isolate(); 502 Factory* factory = isolate->factory(); 503 v8::HandleScope scope(CcTest::isolate()); 504 505 CompileRun( 506 "function getter() { return 1; };" 507 "function setter() {};" 508 "var o = {};" 509 "Object.defineProperty(o, 'foo', " 510 " { get: getter, set: setter, " 511 " configurable: true, enumerable: true});"); 512 513 Handle<String> foo_str = factory->InternalizeUtf8String("foo"); 514 Handle<String> obj_name = factory->InternalizeUtf8String("o"); 515 516 Handle<Object> obj_value = 517 Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); 518 CHECK(obj_value->IsJSObject()); 519 Handle<JSObject> obj = Handle<JSObject>::cast(obj_value); 520 521 CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors()); 522 CHECK(obj->map()->instance_descriptors()->GetValue(0)->IsAccessorPair()); 523 524 Handle<Object> value(Smi::FromInt(42), isolate); 525 JSObject::SetOwnPropertyIgnoreAttributes(obj, foo_str, value, NONE).Check(); 526 527 // Check that the property contains |value|. 528 CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors()); 529 FieldIndex index = FieldIndex::ForDescriptor(obj->map(), 0); 530 Object* the_value = obj->RawFastPropertyAt(index); 531 CHECK(the_value->IsSmi()); 532 CHECK_EQ(42, Smi::cast(the_value)->value()); 533 } 534 535 536 //////////////////////////////////////////////////////////////////////////////// 537 // A set of tests for representation generalization case. 538 // 539 540 // This test ensures that representation/field type generalization at 541 // |property_index| is done correctly independently of the fact that the |map| 542 // is detached from transition tree or not. 543 // 544 // {} - p0 - p1 - p2: |detach_point_map| 545 // | 546 // X - detached at |detach_property_at_index| 547 // | 548 // + - p3 - p4: |map| 549 // 550 // Detaching does not happen if |detach_property_at_index| is -1. 551 // 552 static void TestGeneralizeRepresentation( 553 int detach_property_at_index, int property_index, 554 Representation from_representation, Handle<FieldType> from_type, 555 Representation to_representation, Handle<FieldType> to_type, 556 Representation expected_representation, Handle<FieldType> expected_type, 557 bool expected_deprecation, bool expected_field_type_dependency) { 558 Isolate* isolate = CcTest::i_isolate(); 559 Handle<FieldType> any_type = FieldType::Any(isolate); 560 561 CHECK(detach_property_at_index >= -1 && 562 detach_property_at_index < kPropCount); 563 CHECK(property_index < kPropCount); 564 CHECK_NE(detach_property_at_index, property_index); 565 566 const bool is_detached_map = detach_property_at_index >= 0; 567 568 Expectations expectations(isolate); 569 570 // Create a map, add required properties to it and initialize expectations. 571 Handle<Map> initial_map = Map::Create(isolate, 0); 572 Handle<Map> map = initial_map; 573 Handle<Map> detach_point_map; 574 for (int i = 0; i < kPropCount; i++) { 575 if (i == property_index) { 576 map = 577 expectations.AddDataField(map, NONE, from_representation, from_type); 578 } else { 579 map = 580 expectations.AddDataField(map, NONE, Representation::Smi(), any_type); 581 if (i == detach_property_at_index) { 582 detach_point_map = map; 583 } 584 } 585 } 586 CHECK(!map->is_deprecated()); 587 CHECK(map->is_stable()); 588 CHECK(expectations.Check(*map)); 589 590 Zone zone(isolate->allocator()); 591 592 if (is_detached_map) { 593 detach_point_map = Map::ReconfigureProperty( 594 detach_point_map, detach_property_at_index, kData, NONE, 595 Representation::Tagged(), any_type, FORCE_FIELD); 596 expectations.SetDataField(detach_property_at_index, 597 Representation::Tagged(), any_type); 598 CHECK(map->is_deprecated()); 599 CHECK(expectations.Check(*detach_point_map, 600 detach_point_map->NumberOfOwnDescriptors())); 601 } 602 603 // Create new maps by generalizing representation of propX field. 604 Handle<Map> field_owner(map->FindFieldOwner(property_index), isolate); 605 CompilationInfo info(ArrayVector("testing"), isolate, &zone); 606 CHECK(!info.dependencies()->HasAborted()); 607 608 info.dependencies()->AssumeFieldType(field_owner); 609 610 Handle<Map> new_map = 611 Map::ReconfigureProperty(map, property_index, kData, NONE, 612 to_representation, to_type, FORCE_FIELD); 613 614 expectations.SetDataField(property_index, expected_representation, 615 expected_type); 616 617 CHECK(!new_map->is_deprecated()); 618 CHECK(expectations.Check(*new_map)); 619 620 if (is_detached_map) { 621 CHECK(!map->is_stable()); 622 CHECK(map->is_deprecated()); 623 CHECK_NE(*map, *new_map); 624 CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(), 625 info.dependencies()->HasAborted()); 626 627 } else if (expected_deprecation) { 628 CHECK(!map->is_stable()); 629 CHECK(map->is_deprecated()); 630 CHECK(field_owner->is_deprecated()); 631 CHECK_NE(*map, *new_map); 632 CHECK(!info.dependencies()->HasAborted()); 633 634 } else { 635 CHECK(!field_owner->is_deprecated()); 636 CHECK(map->is_stable()); // Map did not change, must be left stable. 637 CHECK_EQ(*map, *new_map); 638 639 CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted()); 640 } 641 642 { 643 // Check that all previous maps are not stable. 644 Map* tmp = *new_map; 645 while (true) { 646 Object* back = tmp->GetBackPointer(); 647 if (back->IsUndefined(isolate)) break; 648 tmp = Map::cast(back); 649 CHECK(!tmp->is_stable()); 650 } 651 } 652 653 info.dependencies()->Rollback(); // Properly cleanup compilation info. 654 655 // Update all deprecated maps and check that they are now the same. 656 Handle<Map> updated_map = Map::Update(map); 657 CHECK_EQ(*new_map, *updated_map); 658 } 659 660 static void TestGeneralizeRepresentation( 661 Representation from_representation, Handle<FieldType> from_type, 662 Representation to_representation, Handle<FieldType> to_type, 663 Representation expected_representation, Handle<FieldType> expected_type, 664 bool expected_deprecation, bool expected_field_type_dependency) { 665 // Check the cases when the map being reconfigured is a part of the 666 // transition tree. 667 STATIC_ASSERT(kPropCount > 4); 668 int indices[] = {0, 2, kPropCount - 1}; 669 for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) { 670 TestGeneralizeRepresentation( 671 -1, indices[i], from_representation, from_type, to_representation, 672 to_type, expected_representation, expected_type, expected_deprecation, 673 expected_field_type_dependency); 674 } 675 676 if (!from_representation.IsNone()) { 677 // Check the cases when the map being reconfigured is NOT a part of the 678 // transition tree. "None -> anything" representation changes make sense 679 // only for "attached" maps. 680 int indices[] = {0, kPropCount - 1}; 681 for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) { 682 TestGeneralizeRepresentation( 683 indices[i], 2, from_representation, from_type, to_representation, 684 to_type, expected_representation, expected_type, expected_deprecation, 685 expected_field_type_dependency); 686 } 687 688 // Check that reconfiguration to the very same field works correctly. 689 Representation representation = from_representation; 690 Handle<FieldType> type = from_type; 691 TestGeneralizeRepresentation(-1, 2, representation, type, representation, 692 type, representation, type, false, false); 693 } 694 } 695 696 static void TestGeneralizeRepresentation(Representation from_representation, 697 Handle<FieldType> from_type, 698 Representation to_representation, 699 Handle<FieldType> to_type, 700 Representation expected_representation, 701 Handle<FieldType> expected_type) { 702 const bool expected_deprecation = true; 703 const bool expected_field_type_dependency = false; 704 705 TestGeneralizeRepresentation( 706 from_representation, from_type, to_representation, to_type, 707 expected_representation, expected_type, expected_deprecation, 708 expected_field_type_dependency); 709 } 710 711 static void TestGeneralizeRepresentationTrivial( 712 Representation from_representation, Handle<FieldType> from_type, 713 Representation to_representation, Handle<FieldType> to_type, 714 Representation expected_representation, Handle<FieldType> expected_type, 715 bool expected_field_type_dependency = true) { 716 const bool expected_deprecation = false; 717 718 TestGeneralizeRepresentation( 719 from_representation, from_type, to_representation, to_type, 720 expected_representation, expected_type, expected_deprecation, 721 expected_field_type_dependency); 722 } 723 724 725 TEST(GeneralizeRepresentationSmiToDouble) { 726 CcTest::InitializeVM(); 727 v8::HandleScope scope(CcTest::isolate()); 728 Isolate* isolate = CcTest::i_isolate(); 729 Handle<FieldType> any_type = FieldType::Any(isolate); 730 731 TestGeneralizeRepresentation(Representation::Smi(), any_type, 732 Representation::Double(), any_type, 733 Representation::Double(), any_type); 734 } 735 736 737 TEST(GeneralizeRepresentationSmiToTagged) { 738 CcTest::InitializeVM(); 739 v8::HandleScope scope(CcTest::isolate()); 740 Isolate* isolate = CcTest::i_isolate(); 741 Handle<FieldType> any_type = FieldType::Any(isolate); 742 Handle<FieldType> value_type = 743 FieldType::Class(Map::Create(isolate, 0), isolate); 744 745 TestGeneralizeRepresentation(Representation::Smi(), any_type, 746 Representation::HeapObject(), value_type, 747 Representation::Tagged(), any_type); 748 } 749 750 751 TEST(GeneralizeRepresentationDoubleToTagged) { 752 CcTest::InitializeVM(); 753 v8::HandleScope scope(CcTest::isolate()); 754 Isolate* isolate = CcTest::i_isolate(); 755 Handle<FieldType> any_type = FieldType::Any(isolate); 756 Handle<FieldType> value_type = 757 FieldType::Class(Map::Create(isolate, 0), isolate); 758 759 TestGeneralizeRepresentation(Representation::Double(), any_type, 760 Representation::HeapObject(), value_type, 761 Representation::Tagged(), any_type); 762 } 763 764 765 TEST(GeneralizeRepresentationHeapObjectToTagged) { 766 CcTest::InitializeVM(); 767 v8::HandleScope scope(CcTest::isolate()); 768 Isolate* isolate = CcTest::i_isolate(); 769 Handle<FieldType> any_type = FieldType::Any(isolate); 770 Handle<FieldType> value_type = 771 FieldType::Class(Map::Create(isolate, 0), isolate); 772 773 TestGeneralizeRepresentation(Representation::HeapObject(), value_type, 774 Representation::Smi(), any_type, 775 Representation::Tagged(), any_type); 776 } 777 778 779 TEST(GeneralizeRepresentationHeapObjectToHeapObject) { 780 CcTest::InitializeVM(); 781 v8::HandleScope scope(CcTest::isolate()); 782 Isolate* isolate = CcTest::i_isolate(); 783 Handle<FieldType> any_type = FieldType::Any(isolate); 784 785 Handle<FieldType> current_type = 786 FieldType::Class(Map::Create(isolate, 0), isolate); 787 788 Handle<FieldType> new_type = 789 FieldType::Class(Map::Create(isolate, 0), isolate); 790 791 Handle<FieldType> expected_type = any_type; 792 793 TestGeneralizeRepresentationTrivial( 794 Representation::HeapObject(), current_type, 795 Representation::HeapObject(), new_type, Representation::HeapObject(), 796 expected_type); 797 current_type = expected_type; 798 799 new_type = FieldType::Class(Map::Create(isolate, 0), isolate); 800 801 TestGeneralizeRepresentationTrivial( 802 Representation::HeapObject(), any_type, Representation::HeapObject(), 803 new_type, Representation::HeapObject(), any_type, false); 804 } 805 806 807 TEST(GeneralizeRepresentationNoneToSmi) { 808 CcTest::InitializeVM(); 809 v8::HandleScope scope(CcTest::isolate()); 810 Isolate* isolate = CcTest::i_isolate(); 811 Handle<FieldType> none_type = FieldType::None(isolate); 812 Handle<FieldType> any_type = FieldType::Any(isolate); 813 814 // None -> Smi representation change is trivial. 815 TestGeneralizeRepresentationTrivial(Representation::None(), none_type, 816 Representation::Smi(), any_type, 817 Representation::Smi(), any_type); 818 } 819 820 821 TEST(GeneralizeRepresentationNoneToDouble) { 822 CcTest::InitializeVM(); 823 v8::HandleScope scope(CcTest::isolate()); 824 Isolate* isolate = CcTest::i_isolate(); 825 Handle<FieldType> none_type = FieldType::None(isolate); 826 Handle<FieldType> any_type = FieldType::Any(isolate); 827 828 // None -> Double representation change is NOT trivial. 829 TestGeneralizeRepresentation(Representation::None(), none_type, 830 Representation::Double(), any_type, 831 Representation::Double(), any_type); 832 } 833 834 835 TEST(GeneralizeRepresentationNoneToHeapObject) { 836 CcTest::InitializeVM(); 837 v8::HandleScope scope(CcTest::isolate()); 838 Isolate* isolate = CcTest::i_isolate(); 839 Handle<FieldType> none_type = FieldType::None(isolate); 840 Handle<FieldType> value_type = 841 FieldType::Class(Map::Create(isolate, 0), isolate); 842 843 // None -> HeapObject representation change is trivial. 844 TestGeneralizeRepresentationTrivial(Representation::None(), none_type, 845 Representation::HeapObject(), value_type, 846 Representation::HeapObject(), value_type); 847 } 848 849 850 TEST(GeneralizeRepresentationNoneToTagged) { 851 CcTest::InitializeVM(); 852 v8::HandleScope scope(CcTest::isolate()); 853 Isolate* isolate = CcTest::i_isolate(); 854 Handle<FieldType> none_type = FieldType::None(isolate); 855 Handle<FieldType> any_type = FieldType::Any(isolate); 856 857 // None -> HeapObject representation change is trivial. 858 TestGeneralizeRepresentationTrivial(Representation::None(), none_type, 859 Representation::Tagged(), any_type, 860 Representation::Tagged(), any_type); 861 } 862 863 864 //////////////////////////////////////////////////////////////////////////////// 865 // A set of tests for representation generalization case with kAccessor 866 // properties. 867 // 868 869 TEST(GeneralizeRepresentationWithAccessorProperties) { 870 CcTest::InitializeVM(); 871 v8::HandleScope scope(CcTest::isolate()); 872 Isolate* isolate = CcTest::i_isolate(); 873 Handle<FieldType> any_type = FieldType::Any(isolate); 874 Handle<AccessorPair> pair = CreateAccessorPair(true, true); 875 876 const int kAccessorProp = kPropCount / 2; 877 Expectations expectations(isolate); 878 879 // Create a map, add required properties to it and initialize expectations. 880 Handle<Map> initial_map = Map::Create(isolate, 0); 881 Handle<Map> map = initial_map; 882 for (int i = 0; i < kPropCount; i++) { 883 if (i == kAccessorProp) { 884 map = expectations.AddAccessorConstant(map, NONE, pair); 885 } else { 886 map = 887 expectations.AddDataField(map, NONE, Representation::Smi(), any_type); 888 } 889 } 890 CHECK(!map->is_deprecated()); 891 CHECK(map->is_stable()); 892 CHECK(expectations.Check(*map)); 893 894 // Create new maps by generalizing representation of propX field. 895 Handle<Map> maps[kPropCount]; 896 for (int i = 0; i < kPropCount; i++) { 897 if (i == kAccessorProp) { 898 // Skip accessor property reconfiguration. 899 maps[i] = maps[i - 1]; 900 continue; 901 } 902 Handle<Map> new_map = Map::ReconfigureProperty( 903 map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD); 904 maps[i] = new_map; 905 906 expectations.SetDataField(i, Representation::Double(), any_type); 907 908 CHECK(!map->is_stable()); 909 CHECK(map->is_deprecated()); 910 CHECK_NE(*map, *new_map); 911 CHECK(i == 0 || maps[i - 1]->is_deprecated()); 912 913 CHECK(!new_map->is_deprecated()); 914 CHECK(expectations.Check(*new_map)); 915 } 916 917 Handle<Map> active_map = maps[kPropCount - 1]; 918 CHECK(!active_map->is_deprecated()); 919 920 // Update all deprecated maps and check that they are now the same. 921 Handle<Map> updated_map = Map::Update(map); 922 CHECK_EQ(*active_map, *updated_map); 923 for (int i = 0; i < kPropCount; i++) { 924 updated_map = Map::Update(maps[i]); 925 CHECK_EQ(*active_map, *updated_map); 926 } 927 } 928 929 930 //////////////////////////////////////////////////////////////////////////////// 931 // A set of tests for attribute reconfiguration case. 932 // 933 934 // This test ensures that representation/field type generalization is correctly 935 // propagated from one branch of transition tree (|map2|) to another (|map|). 936 // 937 // + - p2B - p3 - p4: |map2| 938 // | 939 // {} - p0 - p1 - p2A - p3 - p4: |map| 940 // 941 // where "p2A" and "p2B" differ only in the attributes. 942 // 943 static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation( 944 Representation from_representation, Handle<FieldType> from_type, 945 Representation to_representation, Handle<FieldType> to_type, 946 Representation expected_representation, Handle<FieldType> expected_type) { 947 Isolate* isolate = CcTest::i_isolate(); 948 949 Expectations expectations(isolate); 950 951 // Create a map, add required properties to it and initialize expectations. 952 Handle<Map> initial_map = Map::Create(isolate, 0); 953 Handle<Map> map = initial_map; 954 for (int i = 0; i < kPropCount; i++) { 955 map = expectations.AddDataField(map, NONE, from_representation, from_type); 956 } 957 CHECK(!map->is_deprecated()); 958 CHECK(map->is_stable()); 959 CHECK(expectations.Check(*map)); 960 961 962 // Create another branch in transition tree (property at index |kSplitProp| 963 // has different attributes), initialize expectations. 964 const int kSplitProp = kPropCount / 2; 965 Expectations expectations2(isolate); 966 967 Handle<Map> map2 = initial_map; 968 for (int i = 0; i < kSplitProp; i++) { 969 map2 = expectations2.FollowDataTransition(map2, NONE, from_representation, 970 from_type); 971 } 972 map2 = 973 expectations2.AddDataField(map2, READ_ONLY, to_representation, to_type); 974 975 for (int i = kSplitProp + 1; i < kPropCount; i++) { 976 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type); 977 } 978 CHECK(!map2->is_deprecated()); 979 CHECK(map2->is_stable()); 980 CHECK(expectations2.Check(*map2)); 981 982 Zone zone(isolate->allocator()); 983 Handle<Map> field_owner(map->FindFieldOwner(kSplitProp), isolate); 984 CompilationInfo info(ArrayVector("testing"), isolate, &zone); 985 CHECK(!info.dependencies()->HasAborted()); 986 info.dependencies()->AssumeFieldType(field_owner); 987 988 // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which 989 // should generalize representations in |map1|. 990 Handle<Map> new_map = 991 Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); 992 993 // |map2| should be left unchanged but marked unstable. 994 CHECK(!map2->is_stable()); 995 CHECK(!map2->is_deprecated()); 996 CHECK_NE(*map2, *new_map); 997 CHECK(expectations2.Check(*map2)); 998 999 // |map| should be deprecated and |new_map| should match new expectations. 1000 for (int i = kSplitProp; i < kPropCount; i++) { 1001 expectations.SetDataField(i, expected_representation, expected_type); 1002 } 1003 CHECK(map->is_deprecated()); 1004 CHECK(!info.dependencies()->HasAborted()); 1005 info.dependencies()->Rollback(); // Properly cleanup compilation info. 1006 CHECK_NE(*map, *new_map); 1007 1008 CHECK(!new_map->is_deprecated()); 1009 CHECK(expectations.Check(*new_map)); 1010 1011 // Update deprecated |map|, it should become |new_map|. 1012 Handle<Map> updated_map = Map::Update(map); 1013 CHECK_EQ(*new_map, *updated_map); 1014 } 1015 1016 1017 // This test ensures that trivial representation/field type generalization 1018 // (from HeapObject to HeapObject) is correctly propagated from one branch of 1019 // transition tree (|map2|) to another (|map|). 1020 // 1021 // + - p2B - p3 - p4: |map2| 1022 // | 1023 // {} - p0 - p1 - p2A - p3 - p4: |map| 1024 // 1025 // where "p2A" and "p2B" differ only in the attributes. 1026 // 1027 static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( 1028 Representation from_representation, Handle<FieldType> from_type, 1029 Representation to_representation, Handle<FieldType> to_type, 1030 Representation expected_representation, Handle<FieldType> expected_type, 1031 bool expected_field_type_dependency = true) { 1032 Isolate* isolate = CcTest::i_isolate(); 1033 1034 Expectations expectations(isolate); 1035 1036 // Create a map, add required properties to it and initialize expectations. 1037 Handle<Map> initial_map = Map::Create(isolate, 0); 1038 Handle<Map> map = initial_map; 1039 for (int i = 0; i < kPropCount; i++) { 1040 map = expectations.AddDataField(map, NONE, from_representation, from_type); 1041 } 1042 CHECK(!map->is_deprecated()); 1043 CHECK(map->is_stable()); 1044 CHECK(expectations.Check(*map)); 1045 1046 1047 // Create another branch in transition tree (property at index |kSplitProp| 1048 // has different attributes), initialize expectations. 1049 const int kSplitProp = kPropCount / 2; 1050 Expectations expectations2(isolate); 1051 1052 Handle<Map> map2 = initial_map; 1053 for (int i = 0; i < kSplitProp; i++) { 1054 map2 = expectations2.FollowDataTransition(map2, NONE, from_representation, 1055 from_type); 1056 } 1057 map2 = 1058 expectations2.AddDataField(map2, READ_ONLY, to_representation, to_type); 1059 1060 for (int i = kSplitProp + 1; i < kPropCount; i++) { 1061 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type); 1062 } 1063 CHECK(!map2->is_deprecated()); 1064 CHECK(map2->is_stable()); 1065 CHECK(expectations2.Check(*map2)); 1066 1067 Zone zone(isolate->allocator()); 1068 Handle<Map> field_owner(map->FindFieldOwner(kSplitProp), isolate); 1069 CompilationInfo info(ArrayVector("testing"), isolate, &zone); 1070 CHECK(!info.dependencies()->HasAborted()); 1071 info.dependencies()->AssumeFieldType(field_owner); 1072 1073 // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which 1074 // should generalize representations in |map1|. 1075 Handle<Map> new_map = 1076 Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); 1077 1078 // |map2| should be left unchanged but marked unstable. 1079 CHECK(!map2->is_stable()); 1080 CHECK(!map2->is_deprecated()); 1081 CHECK_NE(*map2, *new_map); 1082 CHECK(expectations2.Check(*map2)); 1083 1084 // In trivial case |map| should be returned as a result of the property 1085 // reconfiguration, respective field types should be generalized and 1086 // respective code dependencies should be invalidated. |map| should be NOT 1087 // deprecated and it should match new expectations. 1088 for (int i = kSplitProp; i < kPropCount; i++) { 1089 expectations.SetDataField(i, expected_representation, expected_type); 1090 } 1091 CHECK(!map->is_deprecated()); 1092 CHECK_EQ(*map, *new_map); 1093 CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted()); 1094 info.dependencies()->Rollback(); // Properly cleanup compilation info. 1095 1096 CHECK(!new_map->is_deprecated()); 1097 CHECK(expectations.Check(*new_map)); 1098 1099 Handle<Map> updated_map = Map::Update(map); 1100 CHECK_EQ(*new_map, *updated_map); 1101 } 1102 1103 1104 TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToDouble) { 1105 CcTest::InitializeVM(); 1106 v8::HandleScope scope(CcTest::isolate()); 1107 Isolate* isolate = CcTest::i_isolate(); 1108 Handle<FieldType> any_type = FieldType::Any(isolate); 1109 1110 TestReconfigureDataFieldAttribute_GeneralizeRepresentation( 1111 Representation::Smi(), any_type, Representation::Double(), any_type, 1112 Representation::Double(), any_type); 1113 } 1114 1115 1116 TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToTagged) { 1117 CcTest::InitializeVM(); 1118 v8::HandleScope scope(CcTest::isolate()); 1119 Isolate* isolate = CcTest::i_isolate(); 1120 Handle<FieldType> any_type = FieldType::Any(isolate); 1121 Handle<FieldType> value_type = 1122 FieldType::Class(Map::Create(isolate, 0), isolate); 1123 1124 TestReconfigureDataFieldAttribute_GeneralizeRepresentation( 1125 Representation::Smi(), any_type, Representation::HeapObject(), value_type, 1126 Representation::Tagged(), any_type); 1127 } 1128 1129 1130 TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationDoubleToTagged) { 1131 CcTest::InitializeVM(); 1132 v8::HandleScope scope(CcTest::isolate()); 1133 Isolate* isolate = CcTest::i_isolate(); 1134 Handle<FieldType> any_type = FieldType::Any(isolate); 1135 Handle<FieldType> value_type = 1136 FieldType::Class(Map::Create(isolate, 0), isolate); 1137 1138 TestReconfigureDataFieldAttribute_GeneralizeRepresentation( 1139 Representation::Double(), any_type, Representation::HeapObject(), 1140 value_type, Representation::Tagged(), any_type); 1141 } 1142 1143 1144 TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjToHeapObj) { 1145 CcTest::InitializeVM(); 1146 v8::HandleScope scope(CcTest::isolate()); 1147 Isolate* isolate = CcTest::i_isolate(); 1148 Handle<FieldType> any_type = FieldType::Any(isolate); 1149 1150 Handle<FieldType> current_type = 1151 FieldType::Class(Map::Create(isolate, 0), isolate); 1152 1153 Handle<FieldType> new_type = 1154 FieldType::Class(Map::Create(isolate, 0), isolate); 1155 1156 Handle<FieldType> expected_type = any_type; 1157 1158 TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( 1159 Representation::HeapObject(), current_type, Representation::HeapObject(), 1160 new_type, Representation::HeapObject(), expected_type); 1161 current_type = expected_type; 1162 1163 new_type = FieldType::Class(Map::Create(isolate, 0), isolate); 1164 1165 TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( 1166 Representation::HeapObject(), any_type, Representation::HeapObject(), 1167 new_type, Representation::HeapObject(), any_type, false); 1168 } 1169 1170 1171 TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjectToTagged) { 1172 CcTest::InitializeVM(); 1173 v8::HandleScope scope(CcTest::isolate()); 1174 Isolate* isolate = CcTest::i_isolate(); 1175 Handle<FieldType> any_type = FieldType::Any(isolate); 1176 Handle<FieldType> value_type = 1177 FieldType::Class(Map::Create(isolate, 0), isolate); 1178 1179 TestReconfigureDataFieldAttribute_GeneralizeRepresentation( 1180 Representation::HeapObject(), value_type, Representation::Smi(), any_type, 1181 Representation::Tagged(), any_type); 1182 } 1183 1184 1185 // Checks that given |map| is deprecated and that it updates to given |new_map| 1186 // which in turn should match expectations. 1187 struct CheckDeprecated { 1188 void Check(Handle<Map> map, Handle<Map> new_map, 1189 const Expectations& expectations) { 1190 CHECK(map->is_deprecated()); 1191 CHECK_NE(*map, *new_map); 1192 1193 CHECK(!new_map->is_deprecated()); 1194 CHECK(expectations.Check(*new_map)); 1195 1196 // Update deprecated |map|, it should become |new_map|. 1197 Handle<Map> updated_map = Map::Update(map); 1198 CHECK_EQ(*new_map, *updated_map); 1199 } 1200 }; 1201 1202 1203 // Checks that given |map| is NOT deprecated, equals to given |new_map| and 1204 // matches expectations. 1205 struct CheckSameMap { 1206 void Check(Handle<Map> map, Handle<Map> new_map, 1207 const Expectations& expectations) { 1208 // |map| was not reconfigured, therefore it should stay stable. 1209 CHECK(map->is_stable()); 1210 CHECK(!map->is_deprecated()); 1211 CHECK_EQ(*map, *new_map); 1212 1213 CHECK(!new_map->is_deprecated()); 1214 CHECK(expectations.Check(*new_map)); 1215 1216 // Update deprecated |map|, it should become |new_map|. 1217 Handle<Map> updated_map = Map::Update(map); 1218 CHECK_EQ(*new_map, *updated_map); 1219 } 1220 }; 1221 1222 1223 // Checks that given |map| is NOT deprecated and matches expectations. 1224 // |new_map| is unrelated to |map|. 1225 struct CheckUnrelated { 1226 void Check(Handle<Map> map, Handle<Map> new_map, 1227 const Expectations& expectations) { 1228 CHECK(!map->is_deprecated()); 1229 CHECK_NE(*map, *new_map); 1230 CHECK(expectations.Check(*map)); 1231 1232 CHECK(new_map->is_stable()); 1233 CHECK(!new_map->is_deprecated()); 1234 } 1235 }; 1236 1237 1238 // Checks that given |map| is NOT deprecated, and |new_map| is a result of 1239 // copy-generalize-all-representations. 1240 struct CheckCopyGeneralizeAllRepresentations { 1241 void Check(Handle<Map> map, Handle<Map> new_map, Expectations& expectations) { 1242 CHECK(!map->is_deprecated()); 1243 CHECK_NE(*map, *new_map); 1244 1245 CHECK(new_map->GetBackPointer()->IsUndefined(map->GetIsolate())); 1246 for (int i = 0; i < kPropCount; i++) { 1247 expectations.GeneralizeRepresentation(i); 1248 } 1249 1250 CHECK(!new_map->is_deprecated()); 1251 CHECK(expectations.Check(*new_map)); 1252 } 1253 }; 1254 1255 1256 // This test ensures that representation/field type generalization is correctly 1257 // propagated from one branch of transition tree (|map2|) to another (|map1|). 1258 // 1259 // + - p2B - p3 - p4: |map2| 1260 // | 1261 // {} - p0 - p1: |map| 1262 // | 1263 // + - p2A - p3 - p4: |map1| 1264 // | 1265 // + - the property customized by the TestConfig provided 1266 // 1267 // where "p2A" and "p2B" differ only in the attributes. 1268 // 1269 template <typename TestConfig, typename Checker> 1270 static void TestReconfigureProperty_CustomPropertyAfterTargetMap( 1271 TestConfig& config, Checker& checker) { 1272 Isolate* isolate = CcTest::i_isolate(); 1273 Handle<FieldType> any_type = FieldType::Any(isolate); 1274 1275 const int kCustomPropIndex = kPropCount - 2; 1276 Expectations expectations(isolate); 1277 1278 const int kSplitProp = 2; 1279 CHECK(kSplitProp < kCustomPropIndex); 1280 1281 const Representation representation = Representation::Smi(); 1282 1283 // Create common part of transition tree. 1284 Handle<Map> initial_map = Map::Create(isolate, 0); 1285 Handle<Map> map = initial_map; 1286 for (int i = 0; i < kSplitProp; i++) { 1287 map = expectations.AddDataField(map, NONE, representation, any_type); 1288 } 1289 CHECK(!map->is_deprecated()); 1290 CHECK(map->is_stable()); 1291 CHECK(expectations.Check(*map)); 1292 1293 1294 // Create branch to |map1|. 1295 Handle<Map> map1 = map; 1296 Expectations expectations1 = expectations; 1297 for (int i = kSplitProp; i < kCustomPropIndex; i++) { 1298 map1 = expectations1.AddDataField(map1, NONE, representation, any_type); 1299 } 1300 map1 = config.AddPropertyAtBranch(1, expectations1, map1); 1301 for (int i = kCustomPropIndex + 1; i < kPropCount; i++) { 1302 map1 = expectations1.AddDataField(map1, NONE, representation, any_type); 1303 } 1304 CHECK(!map1->is_deprecated()); 1305 CHECK(map1->is_stable()); 1306 CHECK(expectations1.Check(*map1)); 1307 1308 1309 // Create another branch in transition tree (property at index |kSplitProp| 1310 // has different attributes), initialize expectations. 1311 Handle<Map> map2 = map; 1312 Expectations expectations2 = expectations; 1313 map2 = expectations2.AddDataField(map2, READ_ONLY, representation, any_type); 1314 for (int i = kSplitProp + 1; i < kCustomPropIndex; i++) { 1315 map2 = expectations2.AddDataField(map2, NONE, representation, any_type); 1316 } 1317 map2 = config.AddPropertyAtBranch(2, expectations2, map2); 1318 for (int i = kCustomPropIndex + 1; i < kPropCount; i++) { 1319 map2 = expectations2.AddDataField(map2, NONE, representation, any_type); 1320 } 1321 CHECK(!map2->is_deprecated()); 1322 CHECK(map2->is_stable()); 1323 CHECK(expectations2.Check(*map2)); 1324 1325 1326 // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which 1327 // should generalize representations in |map1|. 1328 Handle<Map> new_map = 1329 Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE); 1330 1331 // |map2| should be left unchanged but marked unstable. 1332 CHECK(!map2->is_stable()); 1333 CHECK(!map2->is_deprecated()); 1334 CHECK_NE(*map2, *new_map); 1335 CHECK(expectations2.Check(*map2)); 1336 1337 config.UpdateExpectations(kCustomPropIndex, expectations1); 1338 checker.Check(map1, new_map, expectations1); 1339 } 1340 1341 1342 TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) { 1343 CcTest::InitializeVM(); 1344 v8::HandleScope scope(CcTest::isolate()); 1345 1346 struct TestConfig { 1347 Handle<JSFunction> js_func_; 1348 TestConfig() { 1349 Isolate* isolate = CcTest::i_isolate(); 1350 Factory* factory = isolate->factory(); 1351 js_func_ = factory->NewFunction(factory->empty_string()); 1352 } 1353 1354 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations, 1355 Handle<Map> map) { 1356 CHECK(branch_id == 1 || branch_id == 2); 1357 // Add the same data constant property at both transition tree branches. 1358 return expectations.AddDataConstant(map, NONE, js_func_); 1359 } 1360 1361 void UpdateExpectations(int property_index, Expectations& expectations) { 1362 // Expectations stay the same. 1363 } 1364 }; 1365 1366 TestConfig config; 1367 // Two branches are "compatible" so the |map1| should NOT be deprecated. 1368 CheckSameMap checker; 1369 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1370 } 1371 1372 1373 TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) { 1374 CcTest::InitializeVM(); 1375 v8::HandleScope scope(CcTest::isolate()); 1376 1377 struct TestConfig { 1378 Handle<JSFunction> js_func1_; 1379 Handle<JSFunction> js_func2_; 1380 TestConfig() { 1381 Isolate* isolate = CcTest::i_isolate(); 1382 Factory* factory = isolate->factory(); 1383 js_func1_ = factory->NewFunction(factory->empty_string()); 1384 js_func2_ = factory->NewFunction(factory->empty_string()); 1385 } 1386 1387 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations, 1388 Handle<Map> map) { 1389 CHECK(branch_id == 1 || branch_id == 2); 1390 Handle<JSFunction> js_func = branch_id == 1 ? js_func1_ : js_func2_; 1391 return expectations.AddDataConstant(map, NONE, js_func); 1392 } 1393 1394 void UpdateExpectations(int property_index, Expectations& expectations) { 1395 Isolate* isolate = CcTest::i_isolate(); 1396 Handle<FieldType> function_type = 1397 FieldType::Class(isolate->sloppy_function_map(), isolate); 1398 expectations.SetDataField(property_index, Representation::HeapObject(), 1399 function_type); 1400 } 1401 }; 1402 1403 TestConfig config; 1404 // Two branches are "incompatible" so the |map1| should be deprecated. 1405 CheckDeprecated checker; 1406 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1407 } 1408 1409 1410 TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) { 1411 CcTest::InitializeVM(); 1412 v8::HandleScope scope(CcTest::isolate()); 1413 1414 struct TestConfig { 1415 Handle<JSFunction> js_func_; 1416 Handle<AccessorPair> pair_; 1417 TestConfig() { 1418 Isolate* isolate = CcTest::i_isolate(); 1419 Factory* factory = isolate->factory(); 1420 js_func_ = factory->NewFunction(factory->empty_string()); 1421 pair_ = CreateAccessorPair(true, true); 1422 } 1423 1424 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations, 1425 Handle<Map> map) { 1426 CHECK(branch_id == 1 || branch_id == 2); 1427 if (branch_id == 1) { 1428 return expectations.AddDataConstant(map, NONE, js_func_); 1429 } else { 1430 return expectations.AddAccessorConstant(map, NONE, pair_); 1431 } 1432 } 1433 1434 void UpdateExpectations(int property_index, Expectations& expectations) {} 1435 }; 1436 1437 TestConfig config; 1438 // These are completely separate branches in transition tree. 1439 CheckUnrelated checker; 1440 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1441 } 1442 1443 1444 TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) { 1445 CcTest::InitializeVM(); 1446 v8::HandleScope scope(CcTest::isolate()); 1447 1448 struct TestConfig { 1449 Handle<AccessorPair> pair_; 1450 TestConfig() { pair_ = CreateAccessorPair(true, true); } 1451 1452 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations, 1453 Handle<Map> map) { 1454 CHECK(branch_id == 1 || branch_id == 2); 1455 // Add the same accessor constant property at both transition tree 1456 // branches. 1457 return expectations.AddAccessorConstant(map, NONE, pair_); 1458 } 1459 1460 void UpdateExpectations(int property_index, Expectations& expectations) { 1461 // Two branches are "compatible" so the |map1| should NOT be deprecated. 1462 } 1463 }; 1464 1465 TestConfig config; 1466 CheckSameMap checker; 1467 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1468 } 1469 1470 1471 TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) { 1472 CcTest::InitializeVM(); 1473 v8::HandleScope scope(CcTest::isolate()); 1474 1475 struct TestConfig { 1476 Handle<AccessorPair> pair1_; 1477 Handle<AccessorPair> pair2_; 1478 TestConfig() { 1479 pair1_ = CreateAccessorPair(true, true); 1480 pair2_ = CreateAccessorPair(true, true); 1481 } 1482 1483 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations, 1484 Handle<Map> map) { 1485 CHECK(branch_id == 1 || branch_id == 2); 1486 Handle<AccessorPair> pair = branch_id == 1 ? pair1_ : pair2_; 1487 return expectations.AddAccessorConstant(map, NONE, pair); 1488 } 1489 1490 void UpdateExpectations(int property_index, Expectations& expectations) { 1491 if (IS_ACCESSOR_FIELD_SUPPORTED) { 1492 expectations.SetAccessorField(property_index); 1493 } else { 1494 // Currently we have a copy-generalize-all-representations case and 1495 // ACCESSOR property becomes ACCESSOR_CONSTANT. 1496 expectations.SetAccessorConstant(property_index, pair2_); 1497 } 1498 } 1499 }; 1500 1501 TestConfig config; 1502 if (IS_ACCESSOR_FIELD_SUPPORTED) { 1503 CheckCopyGeneralizeAllRepresentations checker; 1504 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1505 } else { 1506 // Currently we have a copy-generalize-all-representations case. 1507 CheckCopyGeneralizeAllRepresentations checker; 1508 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1509 } 1510 } 1511 1512 1513 TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) { 1514 CcTest::InitializeVM(); 1515 v8::HandleScope scope(CcTest::isolate()); 1516 1517 struct TestConfig { 1518 Handle<AccessorPair> pair_; 1519 TestConfig() { pair_ = CreateAccessorPair(true, true); } 1520 1521 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations, 1522 Handle<Map> map) { 1523 CHECK(branch_id == 1 || branch_id == 2); 1524 if (branch_id == 1) { 1525 return expectations.AddAccessorConstant(map, NONE, pair_); 1526 } else { 1527 Isolate* isolate = CcTest::i_isolate(); 1528 Handle<FieldType> any_type = FieldType::Any(isolate); 1529 return expectations.AddDataField(map, NONE, Representation::Smi(), 1530 any_type); 1531 } 1532 } 1533 1534 void UpdateExpectations(int property_index, Expectations& expectations) {} 1535 }; 1536 1537 TestConfig config; 1538 // These are completely separate branches in transition tree. 1539 CheckUnrelated checker; 1540 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker); 1541 } 1542 1543 1544 //////////////////////////////////////////////////////////////////////////////// 1545 // A set of tests for elements kind reconfiguration case. 1546 // 1547 1548 // This test ensures that representation/field type generalization is correctly 1549 // propagated from one branch of transition tree (|map2) to another (|map|). 1550 // 1551 // + - p0 - p1 - p2A - p3 - p4: |map| 1552 // | 1553 // ek 1554 // | 1555 // {} - p0 - p1 - p2B - p3 - p4: |map2| 1556 // 1557 // where "p2A" and "p2B" differ only in the representation/field type. 1558 // 1559 static void TestReconfigureElementsKind_GeneralizeRepresentation( 1560 Representation from_representation, Handle<FieldType> from_type, 1561 Representation to_representation, Handle<FieldType> to_type, 1562 Representation expected_representation, Handle<FieldType> expected_type) { 1563 Isolate* isolate = CcTest::i_isolate(); 1564 1565 Expectations expectations(isolate, FAST_SMI_ELEMENTS); 1566 1567 // Create a map, add required properties to it and initialize expectations. 1568 Handle<Map> initial_map = Map::Create(isolate, 0); 1569 initial_map->set_elements_kind(FAST_SMI_ELEMENTS); 1570 1571 Handle<Map> map = initial_map; 1572 map = expectations.AsElementsKind(map, FAST_ELEMENTS); 1573 for (int i = 0; i < kPropCount; i++) { 1574 map = expectations.AddDataField(map, NONE, from_representation, from_type); 1575 } 1576 CHECK(!map->is_deprecated()); 1577 CHECK(map->is_stable()); 1578 CHECK(expectations.Check(*map)); 1579 1580 // Create another branch in transition tree (property at index |kDiffProp| 1581 // has different representatio/field type), initialize expectations. 1582 const int kDiffProp = kPropCount / 2; 1583 Expectations expectations2(isolate, FAST_SMI_ELEMENTS); 1584 1585 Handle<Map> map2 = initial_map; 1586 for (int i = 0; i < kPropCount; i++) { 1587 if (i == kDiffProp) { 1588 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type); 1589 } else { 1590 map2 = expectations2.AddDataField(map2, NONE, from_representation, 1591 from_type); 1592 } 1593 } 1594 CHECK(!map2->is_deprecated()); 1595 CHECK(map2->is_stable()); 1596 CHECK(expectations2.Check(*map2)); 1597 1598 Zone zone(isolate->allocator()); 1599 Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate); 1600 CompilationInfo info(ArrayVector("testing"), isolate, &zone); 1601 CHECK(!info.dependencies()->HasAborted()); 1602 info.dependencies()->AssumeFieldType(field_owner); 1603 1604 // Reconfigure elements kinds of |map2|, which should generalize 1605 // representations in |map|. 1606 Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS); 1607 1608 // |map2| should be left unchanged but marked unstable. 1609 CHECK(!map2->is_stable()); 1610 CHECK(!map2->is_deprecated()); 1611 CHECK_NE(*map2, *new_map); 1612 CHECK(expectations2.Check(*map2)); 1613 1614 // |map| should be deprecated and |new_map| should match new expectations. 1615 expectations.SetDataField(kDiffProp, expected_representation, expected_type); 1616 1617 CHECK(map->is_deprecated()); 1618 CHECK(!info.dependencies()->HasAborted()); 1619 info.dependencies()->Rollback(); // Properly cleanup compilation info. 1620 CHECK_NE(*map, *new_map); 1621 1622 CHECK(!new_map->is_deprecated()); 1623 CHECK(expectations.Check(*new_map)); 1624 1625 // Update deprecated |map|, it should become |new_map|. 1626 Handle<Map> updated_map = Map::Update(map); 1627 CHECK_EQ(*new_map, *updated_map); 1628 1629 // Ensure Map::FindElementsKindTransitionedMap() is able to find the 1630 // transitioned map. 1631 { 1632 MapHandleList map_list; 1633 map_list.Add(updated_map); 1634 Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list); 1635 CHECK_EQ(*updated_map, transitioned_map); 1636 } 1637 } 1638 1639 // This test ensures that trivial representation/field type generalization 1640 // (from HeapObject to HeapObject) is correctly propagated from one branch of 1641 // transition tree (|map2|) to another (|map|). 1642 // 1643 // + - p0 - p1 - p2A - p3 - p4: |map| 1644 // | 1645 // ek 1646 // | 1647 // {} - p0 - p1 - p2B - p3 - p4: |map2| 1648 // 1649 // where "p2A" and "p2B" differ only in the representation/field type. 1650 // 1651 static void TestReconfigureElementsKind_GeneralizeRepresentationTrivial( 1652 Representation from_representation, Handle<FieldType> from_type, 1653 Representation to_representation, Handle<FieldType> to_type, 1654 Representation expected_representation, Handle<FieldType> expected_type, 1655 bool expected_field_type_dependency = true) { 1656 Isolate* isolate = CcTest::i_isolate(); 1657 1658 Expectations expectations(isolate, FAST_SMI_ELEMENTS); 1659 1660 // Create a map, add required properties to it and initialize expectations. 1661 Handle<Map> initial_map = Map::Create(isolate, 0); 1662 initial_map->set_elements_kind(FAST_SMI_ELEMENTS); 1663 1664 Handle<Map> map = initial_map; 1665 map = expectations.AsElementsKind(map, FAST_ELEMENTS); 1666 for (int i = 0; i < kPropCount; i++) { 1667 map = expectations.AddDataField(map, NONE, from_representation, from_type); 1668 } 1669 CHECK(!map->is_deprecated()); 1670 CHECK(map->is_stable()); 1671 CHECK(expectations.Check(*map)); 1672 1673 // Create another branch in transition tree (property at index |kDiffProp| 1674 // has different attributes), initialize expectations. 1675 const int kDiffProp = kPropCount / 2; 1676 Expectations expectations2(isolate, FAST_SMI_ELEMENTS); 1677 1678 Handle<Map> map2 = initial_map; 1679 for (int i = 0; i < kPropCount; i++) { 1680 if (i == kDiffProp) { 1681 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type); 1682 } else { 1683 map2 = expectations2.AddDataField(map2, NONE, from_representation, 1684 from_type); 1685 } 1686 } 1687 CHECK(!map2->is_deprecated()); 1688 CHECK(map2->is_stable()); 1689 CHECK(expectations2.Check(*map2)); 1690 1691 Zone zone(isolate->allocator()); 1692 Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate); 1693 CompilationInfo info(ArrayVector("testing"), isolate, &zone); 1694 CHECK(!info.dependencies()->HasAborted()); 1695 info.dependencies()->AssumeFieldType(field_owner); 1696 1697 // Reconfigure elements kinds of |map2|, which should generalize 1698 // representations in |map|. 1699 Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS); 1700 1701 // |map2| should be left unchanged but marked unstable. 1702 CHECK(!map2->is_stable()); 1703 CHECK(!map2->is_deprecated()); 1704 CHECK_NE(*map2, *new_map); 1705 CHECK(expectations2.Check(*map2)); 1706 1707 // In trivial case |map| should be returned as a result of the elements 1708 // kind reconfiguration, respective field types should be generalized and 1709 // respective code dependencies should be invalidated. |map| should be NOT 1710 // deprecated and it should match new expectations. 1711 expectations.SetDataField(kDiffProp, expected_representation, expected_type); 1712 CHECK(!map->is_deprecated()); 1713 CHECK_EQ(*map, *new_map); 1714 CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted()); 1715 info.dependencies()->Rollback(); // Properly cleanup compilation info. 1716 1717 CHECK(!new_map->is_deprecated()); 1718 CHECK(expectations.Check(*new_map)); 1719 1720 Handle<Map> updated_map = Map::Update(map); 1721 CHECK_EQ(*new_map, *updated_map); 1722 1723 // Ensure Map::FindElementsKindTransitionedMap() is able to find the 1724 // transitioned map. 1725 { 1726 MapHandleList map_list; 1727 map_list.Add(updated_map); 1728 Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list); 1729 CHECK_EQ(*updated_map, transitioned_map); 1730 } 1731 } 1732 1733 TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToDouble) { 1734 CcTest::InitializeVM(); 1735 v8::HandleScope scope(CcTest::isolate()); 1736 Isolate* isolate = CcTest::i_isolate(); 1737 Handle<FieldType> any_type = FieldType::Any(isolate); 1738 1739 TestReconfigureElementsKind_GeneralizeRepresentation( 1740 Representation::Smi(), any_type, Representation::Double(), any_type, 1741 Representation::Double(), any_type); 1742 } 1743 1744 TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToTagged) { 1745 CcTest::InitializeVM(); 1746 v8::HandleScope scope(CcTest::isolate()); 1747 Isolate* isolate = CcTest::i_isolate(); 1748 Handle<FieldType> any_type = FieldType::Any(isolate); 1749 Handle<FieldType> value_type = 1750 FieldType::Class(Map::Create(isolate, 0), isolate); 1751 1752 TestReconfigureElementsKind_GeneralizeRepresentation( 1753 Representation::Smi(), any_type, Representation::HeapObject(), value_type, 1754 Representation::Tagged(), any_type); 1755 } 1756 1757 TEST(ReconfigureElementsKind_GeneralizeRepresentationDoubleToTagged) { 1758 CcTest::InitializeVM(); 1759 v8::HandleScope scope(CcTest::isolate()); 1760 Isolate* isolate = CcTest::i_isolate(); 1761 Handle<FieldType> any_type = FieldType::Any(isolate); 1762 Handle<FieldType> value_type = 1763 FieldType::Class(Map::Create(isolate, 0), isolate); 1764 1765 TestReconfigureElementsKind_GeneralizeRepresentation( 1766 Representation::Double(), any_type, Representation::HeapObject(), 1767 value_type, Representation::Tagged(), any_type); 1768 } 1769 1770 TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjToHeapObj) { 1771 CcTest::InitializeVM(); 1772 v8::HandleScope scope(CcTest::isolate()); 1773 Isolate* isolate = CcTest::i_isolate(); 1774 Handle<FieldType> any_type = FieldType::Any(isolate); 1775 1776 Handle<FieldType> current_type = 1777 FieldType::Class(Map::Create(isolate, 0), isolate); 1778 1779 Handle<FieldType> new_type = 1780 FieldType::Class(Map::Create(isolate, 0), isolate); 1781 1782 Handle<FieldType> expected_type = any_type; 1783 1784 TestReconfigureElementsKind_GeneralizeRepresentationTrivial( 1785 Representation::HeapObject(), current_type, Representation::HeapObject(), 1786 new_type, Representation::HeapObject(), expected_type); 1787 current_type = expected_type; 1788 1789 new_type = FieldType::Class(Map::Create(isolate, 0), isolate); 1790 1791 TestReconfigureElementsKind_GeneralizeRepresentationTrivial( 1792 Representation::HeapObject(), any_type, Representation::HeapObject(), 1793 new_type, Representation::HeapObject(), any_type, false); 1794 } 1795 1796 TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjectToTagged) { 1797 CcTest::InitializeVM(); 1798 v8::HandleScope scope(CcTest::isolate()); 1799 Isolate* isolate = CcTest::i_isolate(); 1800 Handle<FieldType> any_type = FieldType::Any(isolate); 1801 Handle<FieldType> value_type = 1802 FieldType::Class(Map::Create(isolate, 0), isolate); 1803 1804 TestReconfigureElementsKind_GeneralizeRepresentation( 1805 Representation::HeapObject(), value_type, Representation::Smi(), any_type, 1806 Representation::Tagged(), any_type); 1807 } 1808 1809 //////////////////////////////////////////////////////////////////////////////// 1810 // A set of tests checking split map deprecation. 1811 // 1812 1813 TEST(ReconfigurePropertySplitMapTransitionsOverflow) { 1814 CcTest::InitializeVM(); 1815 v8::HandleScope scope(CcTest::isolate()); 1816 Isolate* isolate = CcTest::i_isolate(); 1817 Handle<FieldType> any_type = FieldType::Any(isolate); 1818 1819 Expectations expectations(isolate); 1820 1821 // Create a map, add required properties to it and initialize expectations. 1822 Handle<Map> initial_map = Map::Create(isolate, 0); 1823 Handle<Map> map = initial_map; 1824 for (int i = 0; i < kPropCount; i++) { 1825 map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); 1826 } 1827 CHECK(!map->is_deprecated()); 1828 CHECK(map->is_stable()); 1829 1830 // Generalize representation of property at index |kSplitProp|. 1831 const int kSplitProp = kPropCount / 2; 1832 Handle<Map> split_map; 1833 Handle<Map> map2 = initial_map; 1834 { 1835 for (int i = 0; i < kSplitProp + 1; i++) { 1836 if (i == kSplitProp) { 1837 split_map = map2; 1838 } 1839 1840 Handle<String> name = MakeName("prop", i); 1841 Map* target = 1842 TransitionArray::SearchTransition(*map2, kData, *name, NONE); 1843 CHECK(target != NULL); 1844 map2 = handle(target); 1845 } 1846 1847 map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE, 1848 Representation::Double(), any_type, 1849 FORCE_FIELD); 1850 expectations.SetDataField(kSplitProp, Representation::Double(), any_type); 1851 1852 CHECK(expectations.Check(*split_map, kSplitProp)); 1853 CHECK(expectations.Check(*map2, kSplitProp + 1)); 1854 } 1855 1856 // At this point |map| should be deprecated and disconnected from the 1857 // transition tree. 1858 CHECK(map->is_deprecated()); 1859 CHECK(!split_map->is_deprecated()); 1860 CHECK(map2->is_stable()); 1861 CHECK(!map2->is_deprecated()); 1862 1863 // Fill in transition tree of |map2| so that it can't have more transitions. 1864 for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) { 1865 CHECK(TransitionArray::CanHaveMoreTransitions(map2)); 1866 Handle<String> name = MakeName("foo", i); 1867 Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(), 1868 INSERT_TRANSITION) 1869 .ToHandleChecked(); 1870 } 1871 CHECK(!TransitionArray::CanHaveMoreTransitions(map2)); 1872 1873 // Try to update |map|, since there is no place for propX transition at |map2| 1874 // |map| should become "copy-generalized". 1875 Handle<Map> updated_map = Map::Update(map); 1876 CHECK(updated_map->GetBackPointer()->IsUndefined(isolate)); 1877 1878 for (int i = 0; i < kPropCount; i++) { 1879 expectations.SetDataField(i, Representation::Tagged(), any_type); 1880 } 1881 CHECK(expectations.Check(*updated_map)); 1882 } 1883 1884 1885 //////////////////////////////////////////////////////////////////////////////// 1886 // A set of tests involving special transitions (such as elements kind 1887 // transition, observed transition or prototype transition). 1888 // 1889 1890 // This test ensures that representation/field type generalization is correctly 1891 // propagated from one branch of transition tree (|map2|) to another (|map|). 1892 // 1893 // p4B: |map2| 1894 // | 1895 // * - special transition 1896 // | 1897 // {} - p0 - p1 - p2A - p3 - p4A: |map| 1898 // 1899 // where "p4A" and "p4B" are exactly the same properties. 1900 // 1901 // TODO(ishell): unify this test template with 1902 // TestReconfigureDataFieldAttribute_GeneralizeRepresentation once 1903 // IS_PROTO_TRANS_ISSUE_FIXED and IS_NON_EQUIVALENT_TRANSITION_SUPPORTED are 1904 // fixed. 1905 template <typename TestConfig> 1906 static void TestGeneralizeRepresentationWithSpecialTransition( 1907 TestConfig& config, Representation from_representation, 1908 Handle<FieldType> from_type, Representation to_representation, 1909 Handle<FieldType> to_type, Representation expected_representation, 1910 Handle<FieldType> expected_type) { 1911 Isolate* isolate = CcTest::i_isolate(); 1912 1913 Expectations expectations(isolate); 1914 1915 // Create a map, add required properties to it and initialize expectations. 1916 Handle<Map> initial_map = Map::Create(isolate, 0); 1917 Handle<Map> map = initial_map; 1918 for (int i = 0; i < kPropCount; i++) { 1919 map = expectations.AddDataField(map, NONE, from_representation, from_type); 1920 } 1921 CHECK(!map->is_deprecated()); 1922 CHECK(map->is_stable()); 1923 CHECK(expectations.Check(*map)); 1924 1925 Expectations expectations2 = expectations; 1926 1927 // Apply some special transition to |map|. 1928 CHECK(map->owns_descriptors()); 1929 Handle<Map> map2 = config.Transition(map, expectations2); 1930 1931 // |map| should still match expectations. 1932 CHECK(!map->is_deprecated()); 1933 CHECK(expectations.Check(*map)); 1934 1935 if (config.generalizes_representations()) { 1936 for (int i = 0; i < kPropCount; i++) { 1937 expectations2.GeneralizeRepresentation(i); 1938 } 1939 } 1940 1941 CHECK(!map2->is_deprecated()); 1942 CHECK(map2->is_stable()); 1943 CHECK(expectations2.Check(*map2)); 1944 1945 // Create new maps by generalizing representation of propX field. 1946 Handle<Map> maps[kPropCount]; 1947 for (int i = 0; i < kPropCount; i++) { 1948 Handle<Map> new_map = Map::ReconfigureProperty( 1949 map, i, kData, NONE, to_representation, to_type, FORCE_FIELD); 1950 maps[i] = new_map; 1951 1952 expectations.SetDataField(i, expected_representation, expected_type); 1953 1954 CHECK(map->is_deprecated()); 1955 CHECK_NE(*map, *new_map); 1956 CHECK(i == 0 || maps[i - 1]->is_deprecated()); 1957 CHECK(expectations.Check(*new_map)); 1958 1959 Handle<Map> new_map2 = Map::Update(map2); 1960 CHECK(!new_map2->is_deprecated()); 1961 CHECK(!new_map2->is_dictionary_map()); 1962 1963 Handle<Map> tmp_map; 1964 if (Map::TryUpdate(map2).ToHandle(&tmp_map)) { 1965 // If Map::TryUpdate() manages to succeed the result must match the result 1966 // of Map::Update(). 1967 CHECK_EQ(*new_map2, *tmp_map); 1968 } 1969 1970 if (config.is_non_equevalent_transition()) { 1971 // In case of non-equivalent transition currently we generalize all 1972 // representations. 1973 for (int i = 0; i < kPropCount; i++) { 1974 expectations2.GeneralizeRepresentation(i); 1975 } 1976 CHECK(new_map2->GetBackPointer()->IsUndefined(isolate)); 1977 CHECK(expectations2.Check(*new_map2)); 1978 } else { 1979 CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate)); 1980 CHECK(expectations2.Check(*new_map2)); 1981 } 1982 } 1983 1984 Handle<Map> active_map = maps[kPropCount - 1]; 1985 CHECK(!active_map->is_deprecated()); 1986 1987 // Update all deprecated maps and check that they are now the same. 1988 Handle<Map> updated_map = Map::Update(map); 1989 CHECK_EQ(*active_map, *updated_map); 1990 for (int i = 0; i < kPropCount; i++) { 1991 updated_map = Map::Update(maps[i]); 1992 CHECK_EQ(*active_map, *updated_map); 1993 } 1994 } 1995 1996 1997 TEST(ElementsKindTransitionFromMapOwningDescriptor) { 1998 CcTest::InitializeVM(); 1999 v8::HandleScope scope(CcTest::isolate()); 2000 Isolate* isolate = CcTest::i_isolate(); 2001 Handle<FieldType> any_type = FieldType::Any(isolate); 2002 Handle<FieldType> value_type = 2003 FieldType::Class(Map::Create(isolate, 0), isolate); 2004 2005 struct TestConfig { 2006 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) { 2007 Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol()); 2008 expectations.SetElementsKind(DICTIONARY_ELEMENTS); 2009 return Map::CopyForPreventExtensions(map, NONE, frozen_symbol, 2010 "CopyForPreventExtensions"); 2011 } 2012 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. 2013 bool generalizes_representations() const { return false; } 2014 bool is_non_equevalent_transition() const { return true; } 2015 }; 2016 TestConfig config; 2017 TestGeneralizeRepresentationWithSpecialTransition( 2018 config, Representation::Smi(), any_type, Representation::HeapObject(), 2019 value_type, Representation::Tagged(), any_type); 2020 } 2021 2022 2023 TEST(ElementsKindTransitionFromMapNotOwningDescriptor) { 2024 CcTest::InitializeVM(); 2025 v8::HandleScope scope(CcTest::isolate()); 2026 Isolate* isolate = CcTest::i_isolate(); 2027 Handle<FieldType> any_type = FieldType::Any(isolate); 2028 Handle<FieldType> value_type = 2029 FieldType::Class(Map::Create(isolate, 0), isolate); 2030 2031 struct TestConfig { 2032 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) { 2033 Isolate* isolate = CcTest::i_isolate(); 2034 Handle<FieldType> any_type = FieldType::Any(isolate); 2035 2036 // Add one more transition to |map| in order to prevent descriptors 2037 // ownership. 2038 CHECK(map->owns_descriptors()); 2039 Map::CopyWithField(map, MakeString("foo"), any_type, NONE, 2040 Representation::Smi(), INSERT_TRANSITION) 2041 .ToHandleChecked(); 2042 CHECK(!map->owns_descriptors()); 2043 2044 Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol()); 2045 expectations.SetElementsKind(DICTIONARY_ELEMENTS); 2046 return Map::CopyForPreventExtensions(map, NONE, frozen_symbol, 2047 "CopyForPreventExtensions"); 2048 } 2049 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. 2050 bool generalizes_representations() const { return false; } 2051 bool is_non_equevalent_transition() const { return true; } 2052 }; 2053 TestConfig config; 2054 TestGeneralizeRepresentationWithSpecialTransition( 2055 config, Representation::Smi(), any_type, Representation::HeapObject(), 2056 value_type, Representation::Tagged(), any_type); 2057 } 2058 2059 2060 TEST(PrototypeTransitionFromMapOwningDescriptor) { 2061 CcTest::InitializeVM(); 2062 v8::HandleScope scope(CcTest::isolate()); 2063 Isolate* isolate = CcTest::i_isolate(); 2064 2065 Handle<FieldType> any_type = FieldType::Any(isolate); 2066 Handle<FieldType> value_type = 2067 FieldType::Class(Map::Create(isolate, 0), isolate); 2068 2069 struct TestConfig { 2070 Handle<JSObject> prototype_; 2071 2072 TestConfig() { 2073 Isolate* isolate = CcTest::i_isolate(); 2074 Factory* factory = isolate->factory(); 2075 prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0)); 2076 } 2077 2078 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) { 2079 return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE); 2080 } 2081 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. 2082 bool generalizes_representations() const { 2083 return !IS_PROTO_TRANS_ISSUE_FIXED; 2084 } 2085 bool is_non_equevalent_transition() const { return true; } 2086 }; 2087 TestConfig config; 2088 TestGeneralizeRepresentationWithSpecialTransition( 2089 config, Representation::Smi(), any_type, Representation::HeapObject(), 2090 value_type, Representation::Tagged(), any_type); 2091 } 2092 2093 2094 TEST(PrototypeTransitionFromMapNotOwningDescriptor) { 2095 CcTest::InitializeVM(); 2096 v8::HandleScope scope(CcTest::isolate()); 2097 Isolate* isolate = CcTest::i_isolate(); 2098 2099 Handle<FieldType> any_type = FieldType::Any(isolate); 2100 Handle<FieldType> value_type = 2101 FieldType::Class(Map::Create(isolate, 0), isolate); 2102 2103 struct TestConfig { 2104 Handle<JSObject> prototype_; 2105 2106 TestConfig() { 2107 Isolate* isolate = CcTest::i_isolate(); 2108 Factory* factory = isolate->factory(); 2109 prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0)); 2110 } 2111 2112 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) { 2113 Isolate* isolate = CcTest::i_isolate(); 2114 Handle<FieldType> any_type = FieldType::Any(isolate); 2115 2116 // Add one more transition to |map| in order to prevent descriptors 2117 // ownership. 2118 CHECK(map->owns_descriptors()); 2119 Map::CopyWithField(map, MakeString("foo"), any_type, NONE, 2120 Representation::Smi(), INSERT_TRANSITION) 2121 .ToHandleChecked(); 2122 CHECK(!map->owns_descriptors()); 2123 2124 return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE); 2125 } 2126 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. 2127 bool generalizes_representations() const { 2128 return !IS_PROTO_TRANS_ISSUE_FIXED; 2129 } 2130 bool is_non_equevalent_transition() const { return true; } 2131 }; 2132 TestConfig config; 2133 TestGeneralizeRepresentationWithSpecialTransition( 2134 config, Representation::Smi(), any_type, Representation::HeapObject(), 2135 value_type, Representation::Tagged(), any_type); 2136 } 2137 2138 2139 //////////////////////////////////////////////////////////////////////////////// 2140 // A set of tests for higher level transitioning mechanics. 2141 // 2142 2143 struct TransitionToDataFieldOperator { 2144 Representation representation_; 2145 PropertyAttributes attributes_; 2146 Handle<FieldType> heap_type_; 2147 Handle<Object> value_; 2148 2149 TransitionToDataFieldOperator(Representation representation, 2150 Handle<FieldType> heap_type, 2151 Handle<Object> value, 2152 PropertyAttributes attributes = NONE) 2153 : representation_(representation), 2154 attributes_(attributes), 2155 heap_type_(heap_type), 2156 value_(value) {} 2157 2158 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) { 2159 return expectations.TransitionToDataField(map, attributes_, representation_, 2160 heap_type_, value_); 2161 } 2162 }; 2163 2164 2165 struct TransitionToDataConstantOperator { 2166 PropertyAttributes attributes_; 2167 Handle<JSFunction> value_; 2168 2169 TransitionToDataConstantOperator(Handle<JSFunction> value, 2170 PropertyAttributes attributes = NONE) 2171 : attributes_(attributes), value_(value) {} 2172 2173 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) { 2174 return expectations.TransitionToDataConstant(map, attributes_, value_); 2175 } 2176 }; 2177 2178 2179 struct TransitionToAccessorConstantOperator { 2180 PropertyAttributes attributes_; 2181 Handle<AccessorPair> pair_; 2182 2183 TransitionToAccessorConstantOperator(Handle<AccessorPair> pair, 2184 PropertyAttributes attributes = NONE) 2185 : attributes_(attributes), pair_(pair) {} 2186 2187 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) { 2188 return expectations.TransitionToAccessorConstant(map, attributes_, pair_); 2189 } 2190 }; 2191 2192 2193 struct ReconfigureAsDataPropertyOperator { 2194 int descriptor_; 2195 Representation representation_; 2196 PropertyAttributes attributes_; 2197 Handle<FieldType> heap_type_; 2198 2199 ReconfigureAsDataPropertyOperator(int descriptor, 2200 Representation representation, 2201 Handle<FieldType> heap_type, 2202 PropertyAttributes attributes = NONE) 2203 : descriptor_(descriptor), 2204 representation_(representation), 2205 attributes_(attributes), 2206 heap_type_(heap_type) {} 2207 2208 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) { 2209 expectations.SetDataField(descriptor_, representation_, heap_type_); 2210 return Map::ReconfigureExistingProperty(map, descriptor_, kData, 2211 attributes_); 2212 } 2213 }; 2214 2215 2216 struct ReconfigureAsAccessorPropertyOperator { 2217 int descriptor_; 2218 PropertyAttributes attributes_; 2219 2220 ReconfigureAsAccessorPropertyOperator(int descriptor, 2221 PropertyAttributes attributes = NONE) 2222 : descriptor_(descriptor), attributes_(attributes) {} 2223 2224 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) { 2225 expectations.SetAccessorField(descriptor_); 2226 return Map::ReconfigureExistingProperty(map, descriptor_, kAccessor, 2227 attributes_); 2228 } 2229 }; 2230 2231 2232 // Checks that representation/field type generalization happened. 2233 struct FieldGeneralizationChecker { 2234 int descriptor_; 2235 Representation representation_; 2236 PropertyAttributes attributes_; 2237 Handle<FieldType> heap_type_; 2238 2239 FieldGeneralizationChecker(int descriptor, Representation representation, 2240 Handle<FieldType> heap_type, 2241 PropertyAttributes attributes = NONE) 2242 : descriptor_(descriptor), 2243 representation_(representation), 2244 attributes_(attributes), 2245 heap_type_(heap_type) {} 2246 2247 void Check(Expectations& expectations2, Handle<Map> map1, Handle<Map> map2) { 2248 CHECK(!map2->is_deprecated()); 2249 2250 CHECK(map1->is_deprecated()); 2251 CHECK_NE(*map1, *map2); 2252 Handle<Map> updated_map = Map::Update(map1); 2253 CHECK_EQ(*map2, *updated_map); 2254 2255 expectations2.SetDataField(descriptor_, attributes_, representation_, 2256 heap_type_); 2257 CHECK(expectations2.Check(*map2)); 2258 } 2259 }; 2260 2261 2262 // Checks that existing transition was taken as is. 2263 struct SameMapChecker { 2264 void Check(Expectations& expectations, Handle<Map> map1, Handle<Map> map2) { 2265 CHECK(!map2->is_deprecated()); 2266 CHECK_EQ(*map1, *map2); 2267 CHECK(expectations.Check(*map2)); 2268 } 2269 }; 2270 2271 2272 // Checks that both |map1| and |map2| should stays non-deprecated, this is 2273 // the case when property kind is change. 2274 struct PropertyKindReconfigurationChecker { 2275 void Check(Expectations& expectations, Handle<Map> map1, Handle<Map> map2) { 2276 CHECK(!map1->is_deprecated()); 2277 CHECK(!map2->is_deprecated()); 2278 CHECK_NE(*map1, *map2); 2279 CHECK(expectations.Check(*map2)); 2280 } 2281 }; 2282 2283 2284 // This test transitions to various property types under different 2285 // circumstances. 2286 // Plan: 2287 // 1) create a |map| with p0..p3 properties. 2288 // 2) create |map1| by adding "p4" to |map0|. 2289 // 3) create |map2| by transition to "p4" from |map0|. 2290 // 2291 // + - p4B: |map2| 2292 // | 2293 // {} - p0 - p1 - pA - p3: |map| 2294 // | 2295 // + - p4A: |map1| 2296 // 2297 // where "p4A" and "p4B" differ only in the attributes. 2298 // 2299 template <typename TransitionOp1, typename TransitionOp2, typename Checker> 2300 static void TestTransitionTo(TransitionOp1& transition_op1, 2301 TransitionOp2& transition_op2, Checker& checker) { 2302 Isolate* isolate = CcTest::i_isolate(); 2303 Handle<FieldType> any_type = FieldType::Any(isolate); 2304 2305 Expectations expectations(isolate); 2306 2307 // Create a map, add required properties to it and initialize expectations. 2308 Handle<Map> initial_map = Map::Create(isolate, 0); 2309 Handle<Map> map = initial_map; 2310 for (int i = 0; i < kPropCount - 1; i++) { 2311 map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type); 2312 } 2313 CHECK(expectations.Check(*map)); 2314 2315 Expectations expectations1 = expectations; 2316 Handle<Map> map1 = transition_op1.DoTransition(expectations1, map); 2317 CHECK(expectations1.Check(*map1)); 2318 2319 Expectations expectations2 = expectations; 2320 Handle<Map> map2 = transition_op2.DoTransition(expectations2, map); 2321 2322 // Let the test customization do the check. 2323 checker.Check(expectations2, map1, map2); 2324 } 2325 2326 2327 TEST(TransitionDataFieldToDataField) { 2328 CcTest::InitializeVM(); 2329 v8::HandleScope scope(CcTest::isolate()); 2330 Isolate* isolate = CcTest::i_isolate(); 2331 Handle<FieldType> any_type = FieldType::Any(isolate); 2332 2333 Handle<Object> value1 = handle(Smi::FromInt(0), isolate); 2334 TransitionToDataFieldOperator transition_op1(Representation::Smi(), any_type, 2335 value1); 2336 2337 Handle<Object> value2 = isolate->factory()->NewHeapNumber(0); 2338 TransitionToDataFieldOperator transition_op2(Representation::Double(), 2339 any_type, value2); 2340 2341 FieldGeneralizationChecker checker(kPropCount - 1, Representation::Double(), 2342 any_type); 2343 TestTransitionTo(transition_op1, transition_op2, checker); 2344 } 2345 2346 2347 TEST(TransitionDataConstantToSameDataConstant) { 2348 CcTest::InitializeVM(); 2349 v8::HandleScope scope(CcTest::isolate()); 2350 Isolate* isolate = CcTest::i_isolate(); 2351 Factory* factory = isolate->factory(); 2352 2353 Handle<JSFunction> js_func = factory->NewFunction(factory->empty_string()); 2354 TransitionToDataConstantOperator transition_op(js_func); 2355 2356 SameMapChecker checker; 2357 TestTransitionTo(transition_op, transition_op, checker); 2358 } 2359 2360 2361 TEST(TransitionDataConstantToAnotherDataConstant) { 2362 CcTest::InitializeVM(); 2363 v8::HandleScope scope(CcTest::isolate()); 2364 Isolate* isolate = CcTest::i_isolate(); 2365 Factory* factory = isolate->factory(); 2366 Handle<FieldType> function_type = 2367 FieldType::Class(isolate->sloppy_function_map(), isolate); 2368 2369 Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string()); 2370 TransitionToDataConstantOperator transition_op1(js_func1); 2371 2372 Handle<JSFunction> js_func2 = factory->NewFunction(factory->empty_string()); 2373 TransitionToDataConstantOperator transition_op2(js_func2); 2374 2375 FieldGeneralizationChecker checker( 2376 kPropCount - 1, Representation::HeapObject(), function_type); 2377 TestTransitionTo(transition_op1, transition_op2, checker); 2378 } 2379 2380 2381 TEST(TransitionDataConstantToDataField) { 2382 CcTest::InitializeVM(); 2383 v8::HandleScope scope(CcTest::isolate()); 2384 Isolate* isolate = CcTest::i_isolate(); 2385 Factory* factory = isolate->factory(); 2386 Handle<FieldType> any_type = FieldType::Any(isolate); 2387 2388 Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string()); 2389 TransitionToDataConstantOperator transition_op1(js_func1); 2390 2391 Handle<Object> value2 = isolate->factory()->NewHeapNumber(0); 2392 TransitionToDataFieldOperator transition_op2(Representation::Double(), 2393 any_type, value2); 2394 2395 FieldGeneralizationChecker checker(kPropCount - 1, Representation::Tagged(), 2396 any_type); 2397 TestTransitionTo(transition_op1, transition_op2, checker); 2398 } 2399 2400 2401 TEST(TransitionAccessorConstantToSameAccessorConstant) { 2402 CcTest::InitializeVM(); 2403 v8::HandleScope scope(CcTest::isolate()); 2404 2405 Handle<AccessorPair> pair = CreateAccessorPair(true, true); 2406 TransitionToAccessorConstantOperator transition_op(pair); 2407 2408 SameMapChecker checker; 2409 TestTransitionTo(transition_op, transition_op, checker); 2410 } 2411 2412 2413 // TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported. 2414 // TEST(TransitionAccessorConstantToAnotherAccessorConstant) 2415