Home | History | Annotate | Download | only in cctest
      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