LCOV - code coverage report
Current view: top level - test/cctest - test-field-type-tracking.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1159 1187 97.6 %
Date: 2019-04-17 Functions: 111 113 98.2 %

          Line data    Source code
       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/execution.h"
      13             : #include "src/field-type.h"
      14             : #include "src/global-handles.h"
      15             : #include "src/heap/factory.h"
      16             : #include "src/ic/stub-cache.h"
      17             : #include "src/objects-inl.h"
      18             : #include "src/objects/heap-number-inl.h"
      19             : #include "src/objects/struct-inl.h"
      20             : #include "src/ostreams.h"
      21             : #include "src/property.h"
      22             : #include "src/transitions.h"
      23             : 
      24             : namespace v8 {
      25             : namespace internal {
      26             : namespace compiler {
      27             : namespace test_field_type_tracking {
      28             : 
      29             : // TODO(ishell): fix this once TransitionToPrototype stops generalizing
      30             : // all field representations (similar to crbug/448711 where elements kind
      31             : // and observed transitions caused generalization of all fields).
      32             : const bool IS_PROTO_TRANS_ISSUE_FIXED = false;
      33             : 
      34             : 
      35             : // TODO(ishell): fix this once TransitionToAccessorProperty is able to always
      36             : // keep map in fast mode.
      37             : const bool IS_ACCESSOR_FIELD_SUPPORTED = false;
      38             : 
      39             : 
      40             : // Number of properties used in the tests.
      41             : const int kPropCount = 7;
      42             : 
      43             : 
      44             : //
      45             : // Helper functions.
      46             : //
      47             : 
      48             : static Handle<String> MakeString(const char* str) {
      49             :   Isolate* isolate = CcTest::i_isolate();
      50             :   Factory* factory = isolate->factory();
      51       11012 :   return factory->InternalizeUtf8String(str);
      52             : }
      53             : 
      54             : 
      55       10980 : static Handle<String> MakeName(const char* str, int suffix) {
      56             :   EmbeddedVector<char, 128> buffer;
      57       10980 :   SNPrintF(buffer, "%s%d", str, suffix);
      58       10980 :   return MakeString(buffer.start());
      59             : }
      60             : 
      61             : 
      62          32 : static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
      63             :                                                bool with_setter) {
      64             :   Isolate* isolate = CcTest::i_isolate();
      65             :   Factory* factory = isolate->factory();
      66          32 :   Handle<AccessorPair> pair = factory->NewAccessorPair();
      67          32 :   Handle<String> empty_string = factory->empty_string();
      68          32 :   if (with_getter) {
      69          32 :     Handle<JSFunction> func = factory->NewFunctionForTest(empty_string);
      70          64 :     pair->set_getter(*func);
      71             :   }
      72          32 :   if (with_setter) {
      73          32 :     Handle<JSFunction> func = factory->NewFunctionForTest(empty_string);
      74          64 :     pair->set_setter(*func);
      75             :   }
      76          32 :   return pair;
      77             : }
      78             : 
      79             : // Check cached migration target map after Map::Update() and Map::TryUpdate()
      80         856 : static void CheckMigrationTarget(Isolate* isolate, Map old_map, Map new_map) {
      81             :   Map target = TransitionsAccessor(isolate, handle(old_map, isolate))
      82         856 :                    .GetMigrationTarget();
      83        1712 :   if (target.is_null()) return;
      84           0 :   CHECK_EQ(new_map, target);
      85           0 :   CHECK_EQ(Map::TryUpdateSlow(isolate, old_map), target);
      86             : }
      87             : 
      88             : class Expectations {
      89             :   static const int MAX_PROPERTIES = 10;
      90             :   Isolate* isolate_;
      91             :   ElementsKind elements_kind_;
      92             :   PropertyKind kinds_[MAX_PROPERTIES];
      93             :   PropertyLocation locations_[MAX_PROPERTIES];
      94             :   PropertyConstness constnesses_[MAX_PROPERTIES];
      95             :   PropertyAttributes attributes_[MAX_PROPERTIES];
      96             :   Representation representations_[MAX_PROPERTIES];
      97             :   // FieldType for kField, value for DATA_CONSTANT and getter for
      98             :   // ACCESSOR_CONSTANT.
      99             :   Handle<Object> values_[MAX_PROPERTIES];
     100             :   // Setter for ACCESSOR_CONSTANT.
     101             :   Handle<Object> setter_values_[MAX_PROPERTIES];
     102             :   int number_of_properties_;
     103             : 
     104             :  public:
     105             :   explicit Expectations(Isolate* isolate, ElementsKind elements_kind)
     106             :       : isolate_(isolate),
     107             :         elements_kind_(elements_kind),
     108       20832 :         number_of_properties_(0) {}
     109             : 
     110         480 :   explicit Expectations(Isolate* isolate)
     111             :       : Expectations(
     112             :             isolate,
     113         960 :             isolate->object_function()->initial_map()->elements_kind()) {}
     114             : 
     115        6184 :   void Init(int index, PropertyKind kind, PropertyAttributes attributes,
     116             :             PropertyConstness constness, PropertyLocation location,
     117             :             Representation representation, Handle<Object> value) {
     118        6184 :     CHECK(index < MAX_PROPERTIES);
     119        6184 :     kinds_[index] = kind;
     120        6184 :     locations_[index] = location;
     121       12324 :     if (kind == kData && location == kField &&
     122        6140 :         IsTransitionableFastElementsKind(elements_kind_)) {
     123             :       // Maps with transitionable elements kinds must have the most general
     124             :       // field type.
     125        1440 :       value = FieldType::Any(isolate_);
     126             :     }
     127        6184 :     constnesses_[index] = constness;
     128        6184 :     attributes_[index] = attributes;
     129        6184 :     representations_[index] = representation;
     130        6184 :     values_[index] = value;
     131        6184 :   }
     132             : 
     133           0 :   void Print() const {
     134           0 :     StdoutStream os;
     135           0 :     os << "Expectations: #" << number_of_properties_ << "\n";
     136           0 :     for (int i = 0; i < number_of_properties_; i++) {
     137           0 :       os << " " << i << ": ";
     138           0 :       os << "Descriptor @ ";
     139             : 
     140           0 :       if (kinds_[i] == kData) {
     141           0 :         os << Brief(*values_[i]);
     142             :       } else {
     143             :         // kAccessor
     144           0 :         os << "(get: " << Brief(*values_[i])
     145           0 :            << ", set: " << Brief(*setter_values_[i]) << ") ";
     146             :       }
     147             : 
     148           0 :       os << " (";
     149           0 :       if (constnesses_[i] == PropertyConstness::kConst) os << "const ";
     150           0 :       os << (kinds_[i] == kData ? "data " : "accessor ");
     151           0 :       if (locations_[i] == kField) {
     152             :         os << "field"
     153           0 :            << ": " << representations_[i].Mnemonic();
     154             :       } else {
     155           0 :         os << "descriptor";
     156             :       }
     157           0 :       os << ", attrs: " << attributes_[i] << ")\n";
     158             :     }
     159           0 :     os << "\n";
     160           0 :   }
     161             : 
     162             :   void SetElementsKind(ElementsKind elements_kind) {
     163          48 :     elements_kind_ = elements_kind;
     164             :   }
     165             : 
     166             :   Handle<FieldType> GetFieldType(int index) {
     167             :     CHECK(index < MAX_PROPERTIES);
     168             :     CHECK_EQ(kField, locations_[index]);
     169             :     return Handle<FieldType>::cast(values_[index]);
     170             :   }
     171             : 
     172             :   void SetDataField(int index, PropertyAttributes attrs,
     173             :                     PropertyConstness constness, Representation representation,
     174             :                     Handle<FieldType> field_type) {
     175        6100 :     Init(index, kData, attrs, constness, kField, representation, field_type);
     176             :   }
     177             : 
     178             :   void SetDataField(int index, PropertyConstness constness,
     179             :                     Representation representation,
     180             :                     Handle<FieldType> field_type) {
     181        1348 :     SetDataField(index, attributes_[index], constness, representation,
     182             :                  field_type);
     183             :   }
     184             : 
     185             :   void SetAccessorField(int index, PropertyAttributes attrs) {
     186             :     Init(index, kAccessor, attrs, PropertyConstness::kConst, kDescriptor,
     187             :          Representation::Tagged(), FieldType::Any(isolate_));
     188             :   }
     189             : 
     190             :   void SetAccessorField(int index) {
     191             :     SetAccessorField(index, attributes_[index]);
     192             :   }
     193             : 
     194          40 :   void SetDataConstant(int index, PropertyAttributes attrs,
     195             :                        Handle<JSFunction> value) {
     196             :     if (FLAG_track_constant_fields) {
     197          80 :       Handle<FieldType> field_type(FieldType::Class(value->map()), isolate_);
     198          40 :       Init(index, kData, attrs, PropertyConstness::kConst, kField,
     199          40 :            Representation::HeapObject(), field_type);
     200             : 
     201             :     } else {
     202             :       Init(index, kData, attrs, PropertyConstness::kConst, kDescriptor,
     203             :            Representation::HeapObject(), value);
     204             :     }
     205          40 :   }
     206             : 
     207             :   void SetDataConstant(int index, Handle<JSFunction> value) {
     208             :     SetDataConstant(index, attributes_[index], value);
     209             :   }
     210             : 
     211             :   void SetAccessorConstant(int index, PropertyAttributes attrs,
     212             :                            Handle<Object> getter, Handle<Object> setter) {
     213             :     Init(index, kAccessor, attrs, PropertyConstness::kConst, kDescriptor,
     214          44 :          Representation::Tagged(), getter);
     215          44 :     setter_values_[index] = setter;
     216             :   }
     217             : 
     218             :   void SetAccessorConstantComponent(int index, PropertyAttributes attrs,
     219             :                                     AccessorComponent component,
     220             :                                     Handle<Object> accessor) {
     221             :     CHECK_EQ(kAccessor, kinds_[index]);
     222             :     CHECK_EQ(kDescriptor, locations_[index]);
     223             :     CHECK(index < number_of_properties_);
     224             :     if (component == ACCESSOR_GETTER) {
     225             :       values_[index] = accessor;
     226             :     } else {
     227             :       setter_values_[index] = accessor;
     228             :     }
     229             :   }
     230             : 
     231          40 :   void SetAccessorConstant(int index, PropertyAttributes attrs,
     232             :                            Handle<AccessorPair> pair) {
     233          40 :     Handle<Object> getter = handle(pair->getter(), isolate_);
     234          40 :     Handle<Object> setter = handle(pair->setter(), isolate_);
     235             :     SetAccessorConstant(index, attrs, getter, setter);
     236          40 :   }
     237             : 
     238           4 :   void SetAccessorConstant(int index, Handle<Object> getter,
     239             :                            Handle<Object> setter) {
     240           4 :     SetAccessorConstant(index, attributes_[index], getter, setter);
     241           4 :   }
     242             : 
     243           4 :   void SetAccessorConstant(int index, Handle<AccessorPair> pair) {
     244           8 :     Handle<Object> getter = handle(pair->getter(), isolate_);
     245           8 :     Handle<Object> setter = handle(pair->setter(), isolate_);
     246           4 :     SetAccessorConstant(index, getter, setter);
     247           4 :   }
     248             : 
     249         532 :   void GeneralizeField(int index) {
     250         532 :     CHECK(index < number_of_properties_);
     251         532 :     representations_[index] = Representation::Tagged();
     252         532 :     if (locations_[index] == kField) {
     253         528 :       values_[index] = FieldType::Any(isolate_);
     254             :     }
     255         532 :   }
     256             : 
     257       13788 :   bool Check(DescriptorArray descriptors, int descriptor) const {
     258       13788 :     PropertyDetails details = descriptors->GetDetails(descriptor);
     259             : 
     260       13788 :     if (details.kind() != kinds_[descriptor]) return false;
     261       13788 :     if (details.location() != locations_[descriptor]) return false;
     262       13788 :     if (details.constness() != constnesses_[descriptor]) return false;
     263             : 
     264       13788 :     PropertyAttributes expected_attributes = attributes_[descriptor];
     265       13788 :     if (details.attributes() != expected_attributes) return false;
     266             : 
     267       13788 :     Representation expected_representation = representations_[descriptor];
     268             : 
     269       13788 :     if (!details.representation().Equals(expected_representation)) return false;
     270             : 
     271       13788 :     Object expected_value = *values_[descriptor];
     272       13788 :     if (details.location() == kField) {
     273       13696 :       if (details.kind() == kData) {
     274       13696 :         FieldType type = descriptors->GetFieldType(descriptor);
     275       27392 :         return FieldType::cast(expected_value) == type;
     276             :       } else {
     277             :         // kAccessor
     278           0 :         UNREACHABLE();
     279             :       }
     280             :     } else {
     281             :       Object value = descriptors->GetStrongValue(descriptor);
     282             :       // kDescriptor
     283          92 :       if (details.kind() == kData) {
     284           0 :         CHECK(!FLAG_track_constant_fields);
     285             :         return value == expected_value;
     286             :       } else {
     287             :         // kAccessor
     288          92 :         if (value == expected_value) return true;
     289          92 :         if (!value->IsAccessorPair()) return false;
     290             :         AccessorPair pair = AccessorPair::cast(value);
     291         184 :         return pair->Equals(expected_value, *setter_values_[descriptor]);
     292             :       }
     293             :     }
     294             :     UNREACHABLE();
     295             :   }
     296             : 
     297        2028 :   bool Check(Map map, int expected_nof) const {
     298        2028 :     CHECK_EQ(elements_kind_, map->elements_kind());
     299        2028 :     CHECK(number_of_properties_ <= MAX_PROPERTIES);
     300        2028 :     CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors());
     301        2028 :     CHECK(!map->is_dictionary_map());
     302             : 
     303        2028 :     DescriptorArray descriptors = map->instance_descriptors();
     304        2028 :     CHECK(expected_nof <= number_of_properties_);
     305       29604 :     for (int i = 0; i < expected_nof; i++) {
     306       13788 :       if (!Check(descriptors, i)) {
     307           0 :         Print();
     308             : #ifdef OBJECT_PRINT
     309             :         descriptors->Print();
     310             : #endif
     311           0 :         Check(descriptors, i);
     312           0 :         return false;
     313             :       }
     314             :     }
     315             :     return true;
     316             :   }
     317             : 
     318        1972 :   bool Check(Map map) const { return Check(map, number_of_properties_); }
     319             : 
     320             :   //
     321             :   // Helper methods for initializing expectations and adding properties to
     322             :   // given |map|.
     323             :   //
     324             : 
     325          96 :   Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) {
     326          96 :     elements_kind_ = elements_kind;
     327          96 :     map = Map::AsElementsKind(isolate_, map, elements_kind);
     328          96 :     CHECK_EQ(elements_kind_, map->elements_kind());
     329          96 :     return map;
     330             :   }
     331             : 
     332             :   void ChangeAttributesForAllProperties(PropertyAttributes attributes) {
     333         720 :     for (int i = 0; i < number_of_properties_; i++) {
     334         336 :       attributes_[i] = attributes;
     335             :     }
     336             :   }
     337             : 
     338        4476 :   Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
     339             :                            PropertyConstness constness,
     340             :                            Representation representation,
     341             :                            Handle<FieldType> field_type) {
     342             :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     343        4476 :     int property_index = number_of_properties_++;
     344             :     SetDataField(property_index, attributes, constness, representation,
     345             :                  field_type);
     346             : 
     347        4476 :     Handle<String> name = MakeName("prop", property_index);
     348        8952 :     return Map::CopyWithField(isolate_, map, name, field_type, attributes,
     349        8952 :                               constness, representation, INSERT_TRANSITION)
     350        4476 :         .ToHandleChecked();
     351             :   }
     352             : 
     353          20 :   Handle<Map> AddDataConstant(Handle<Map> map, PropertyAttributes attributes,
     354             :                               Handle<JSFunction> value) {
     355          20 :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     356          20 :     int property_index = number_of_properties_++;
     357          20 :     SetDataConstant(property_index, attributes, value);
     358             : 
     359          20 :     Handle<String> name = MakeName("prop", property_index);
     360          40 :     return Map::CopyWithConstant(isolate_, map, name, value, attributes,
     361          40 :                                  INSERT_TRANSITION)
     362          20 :         .ToHandleChecked();
     363             :   }
     364             : 
     365          12 :   Handle<Map> TransitionToDataField(Handle<Map> map,
     366             :                                     PropertyAttributes attributes,
     367             :                                     PropertyConstness constness,
     368             :                                     Representation representation,
     369             :                                     Handle<FieldType> heap_type,
     370             :                                     Handle<Object> value) {
     371          12 :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     372          12 :     int property_index = number_of_properties_++;
     373             :     SetDataField(property_index, attributes, constness, representation,
     374             :                  heap_type);
     375             : 
     376          12 :     Handle<String> name = MakeName("prop", property_index);
     377             :     return Map::TransitionToDataProperty(isolate_, map, name, value, attributes,
     378          12 :                                          constness, StoreOrigin::kNamed);
     379             :   }
     380             : 
     381          20 :   Handle<Map> TransitionToDataConstant(Handle<Map> map,
     382             :                                        PropertyAttributes attributes,
     383             :                                        Handle<JSFunction> value) {
     384          20 :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     385          20 :     int property_index = number_of_properties_++;
     386          20 :     SetDataConstant(property_index, attributes, value);
     387             : 
     388          20 :     Handle<String> name = MakeName("prop", property_index);
     389             :     return Map::TransitionToDataProperty(isolate_, map, name, value, attributes,
     390             :                                          PropertyConstness::kConst,
     391          20 :                                          StoreOrigin::kNamed);
     392             :   }
     393             : 
     394         252 :   Handle<Map> FollowDataTransition(Handle<Map> map,
     395             :                                    PropertyAttributes attributes,
     396             :                                    PropertyConstness constness,
     397             :                                    Representation representation,
     398             :                                    Handle<FieldType> heap_type) {
     399         252 :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     400         252 :     int property_index = number_of_properties_++;
     401             :     SetDataField(property_index, attributes, constness, representation,
     402             :                  heap_type);
     403             : 
     404         252 :     Handle<String> name = MakeName("prop", property_index);
     405             :     Map target = TransitionsAccessor(isolate_, map)
     406         504 :                      .SearchTransition(*name, kData, attributes);
     407         252 :     CHECK(!target.is_null());
     408         504 :     return handle(target, isolate_);
     409             :   }
     410             : 
     411          32 :   Handle<Map> AddAccessorConstant(Handle<Map> map,
     412             :                                   PropertyAttributes attributes,
     413             :                                   Handle<AccessorPair> pair) {
     414          32 :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     415          32 :     int property_index = number_of_properties_++;
     416          32 :     SetAccessorConstant(property_index, attributes, pair);
     417             : 
     418          32 :     Handle<String> name = MakeName("prop", property_index);
     419             : 
     420          32 :     Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
     421          32 :     return Map::CopyInsertDescriptor(isolate_, map, &d, INSERT_TRANSITION);
     422             :   }
     423             : 
     424             :   Handle<Map> AddAccessorConstant(Handle<Map> map,
     425             :                                   PropertyAttributes attributes,
     426             :                                   Handle<Object> getter,
     427             :                                   Handle<Object> setter) {
     428             :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     429             :     int property_index = number_of_properties_++;
     430             :     SetAccessorConstant(property_index, attributes, getter, setter);
     431             : 
     432             :     Handle<String> name = MakeName("prop", property_index);
     433             : 
     434             :     CHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
     435             :     Factory* factory = isolate_->factory();
     436             : 
     437             :     if (!getter->IsNull(isolate_)) {
     438             :       Handle<AccessorPair> pair = factory->NewAccessorPair();
     439             :       pair->SetComponents(*getter, *factory->null_value());
     440             :       Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
     441             :       map = Map::CopyInsertDescriptor(isolate_, map, &d, INSERT_TRANSITION);
     442             :     }
     443             :     if (!setter->IsNull(isolate_)) {
     444             :       Handle<AccessorPair> pair = factory->NewAccessorPair();
     445             :       pair->SetComponents(*getter, *setter);
     446             :       Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
     447             :       map = Map::CopyInsertDescriptor(isolate_, map, &d, INSERT_TRANSITION);
     448             :     }
     449             :     return map;
     450             :   }
     451             : 
     452           8 :   Handle<Map> TransitionToAccessorConstant(Handle<Map> map,
     453             :                                            PropertyAttributes attributes,
     454             :                                            Handle<AccessorPair> pair) {
     455           8 :     CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
     456           8 :     int property_index = number_of_properties_++;
     457           8 :     SetAccessorConstant(property_index, attributes, pair);
     458             : 
     459           8 :     Handle<String> name = MakeName("prop", property_index);
     460             : 
     461             :     Isolate* isolate = CcTest::i_isolate();
     462             :     Handle<Object> getter(pair->getter(), isolate);
     463             :     Handle<Object> setter(pair->setter(), isolate);
     464             : 
     465             :     int descriptor =
     466          16 :         map->instance_descriptors()->SearchWithCache(isolate, *name, *map);
     467             :     map = Map::TransitionToAccessorProperty(isolate, map, name, descriptor,
     468           8 :                                             getter, setter, attributes);
     469           8 :     CHECK(!map->is_deprecated());
     470           8 :     CHECK(!map->is_dictionary_map());
     471           8 :     return map;
     472             :   }
     473             : };
     474             : 
     475             : 
     476             : ////////////////////////////////////////////////////////////////////////////////
     477             : // A set of tests for property reconfiguration that makes new transition tree
     478             : // branch.
     479             : //
     480             : 
     481       26643 : TEST(ReconfigureAccessorToNonExistingDataField) {
     482           4 :   CcTest::InitializeVM();
     483           8 :   v8::HandleScope scope(CcTest::isolate());
     484             :   Isolate* isolate = CcTest::i_isolate();
     485             : 
     486           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     487           4 :   Handle<FieldType> none_type = FieldType::None(isolate);
     488           4 :   Handle<AccessorPair> pair = CreateAccessorPair(true, true);
     489             : 
     490           4 :   Expectations expectations(isolate);
     491             : 
     492             :   // Create a map, add required properties to it and initialize expectations.
     493           4 :   Handle<Map> initial_map = Map::Create(isolate, 0);
     494           4 :   Handle<Map> map = initial_map;
     495           4 :   map = expectations.AddAccessorConstant(map, NONE, pair);
     496             : 
     497           4 :   CHECK(!map->is_deprecated());
     498           4 :   CHECK(map->is_stable());
     499           4 :   CHECK(expectations.Check(*map));
     500             : 
     501             :   Handle<Map> new_map = Map::ReconfigureProperty(
     502           4 :       isolate, map, 0, kData, NONE, Representation::None(), none_type);
     503             :   // |map| did not change except marked unstable.
     504           4 :   CHECK(!map->is_deprecated());
     505           4 :   CHECK(!map->is_stable());
     506           4 :   CHECK(expectations.Check(*map));
     507             : 
     508             :   // Property kind reconfiguration always makes the field mutable.
     509             :   expectations.SetDataField(0, NONE, PropertyConstness::kMutable,
     510             :                             Representation::None(), none_type);
     511             : 
     512           4 :   CHECK(!new_map->is_deprecated());
     513           4 :   CHECK(new_map->is_stable());
     514           4 :   CHECK(expectations.Check(*new_map));
     515             : 
     516             :   Handle<Map> new_map2 = Map::ReconfigureProperty(
     517           4 :       isolate, map, 0, kData, NONE, Representation::None(), none_type);
     518           4 :   CHECK_EQ(*new_map, *new_map2);
     519             : 
     520             :   Handle<Object> value(Smi::kZero, isolate);
     521             :   Handle<Map> prepared_map = Map::PrepareForDataProperty(
     522           4 :       isolate, new_map, 0, PropertyConstness::kConst, value);
     523             :   // None to Smi generalization is trivial, map does not change.
     524           4 :   CHECK_EQ(*new_map, *prepared_map);
     525             : 
     526             :   expectations.SetDataField(0, NONE, PropertyConstness::kMutable,
     527             :                             Representation::Smi(), any_type);
     528           4 :   CHECK(prepared_map->is_stable());
     529           4 :   CHECK(expectations.Check(*prepared_map));
     530             : 
     531             :   // Now create an object with |map|, migrate it to |prepared_map| and ensure
     532             :   // that the data property is uninitialized.
     533             :   Factory* factory = isolate->factory();
     534           4 :   Handle<JSObject> obj = factory->NewJSObjectFromMap(map);
     535           4 :   JSObject::MigrateToMap(obj, prepared_map);
     536           4 :   FieldIndex index = FieldIndex::ForDescriptor(*prepared_map, 0);
     537           8 :   CHECK(obj->RawFastPropertyAt(index)->IsUninitialized(isolate));
     538             : #ifdef VERIFY_HEAP
     539             :   obj->ObjectVerify(isolate);
     540             : #endif
     541           4 : }
     542             : 
     543             : 
     544             : // This test checks that the LookupIterator machinery involved in
     545             : // JSObject::SetOwnPropertyIgnoreAttributes() does not try to migrate object
     546             : // to a map with a property with None representation.
     547       26643 : TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {
     548           4 :   CcTest::InitializeVM();
     549           8 :   v8::HandleScope scope(CcTest::isolate());
     550             :   Isolate* isolate = CcTest::i_isolate();
     551             :   Factory* factory = isolate->factory();
     552             : 
     553             :   CompileRun(
     554             :       "function getter() { return 1; };"
     555             :       "function setter() {};"
     556             :       "var o = {};"
     557             :       "Object.defineProperty(o, 'foo', "
     558             :       "                      { get: getter, set: setter, "
     559             :       "                        configurable: true, enumerable: true});");
     560             : 
     561           4 :   Handle<String> foo_str = factory->InternalizeUtf8String("foo");
     562           4 :   Handle<String> obj_name = factory->InternalizeUtf8String("o");
     563             : 
     564             :   Handle<Object> obj_value =
     565          12 :       Object::GetProperty(isolate, isolate->global_object(), obj_name)
     566             :           .ToHandleChecked();
     567           4 :   CHECK(obj_value->IsJSObject());
     568             :   Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
     569             : 
     570           4 :   CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
     571           4 :   CHECK(
     572             :       obj->map()->instance_descriptors()->GetStrongValue(0)->IsAccessorPair());
     573             : 
     574             :   Handle<Object> value(Smi::FromInt(42), isolate);
     575           8 :   JSObject::SetOwnPropertyIgnoreAttributes(obj, foo_str, value, NONE).Check();
     576             : 
     577             :   // Check that the property contains |value|.
     578           4 :   CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
     579           4 :   FieldIndex index = FieldIndex::ForDescriptor(obj->map(), 0);
     580           4 :   Object the_value = obj->RawFastPropertyAt(index);
     581           4 :   CHECK(the_value->IsSmi());
     582           4 :   CHECK_EQ(42, Smi::ToInt(the_value));
     583           4 : }
     584             : 
     585             : 
     586             : ////////////////////////////////////////////////////////////////////////////////
     587             : // A set of tests for field generalization case.
     588             : //
     589             : 
     590             : namespace {
     591             : 
     592             : // <Constness, Representation, FieldType> data.
     593             : struct CRFTData {
     594             :   PropertyConstness constness;
     595             :   Representation representation;
     596             :   Handle<FieldType> type;
     597             : };
     598             : 
     599         372 : Handle<Code> CreateDummyOptimizedCode(Isolate* isolate) {
     600             :   byte buffer[1];
     601         372 :   CodeDesc desc;
     602         372 :   desc.buffer = buffer;
     603         372 :   desc.buffer_size = arraysize(buffer);
     604         372 :   desc.instr_size = arraysize(buffer);
     605             :   return isolate->factory()->NewCode(
     606             :       desc, Code::OPTIMIZED_FUNCTION, Handle<Object>(), Builtins::kNoBuiltinId,
     607             :       MaybeHandle<ByteArray>(), MaybeHandle<DeoptimizationData>(), kMovable,
     608         744 :       true);
     609             : }
     610             : 
     611             : // This test ensures that field generalization at |property_index| is done
     612             : // correctly independently of the fact that the |map| is detached from
     613             : // transition tree or not.
     614             : //
     615             : //  {} - p0 - p1 - p2: |detach_point_map|
     616             : //                  |
     617             : //                  X - detached at |detach_property_at_index|
     618             : //                  |
     619             : //                  + - p3 - p4: |map|
     620             : //
     621             : // Detaching does not happen if |detach_property_at_index| is -1.
     622             : //
     623         192 : void TestGeneralizeField(int detach_property_at_index, int property_index,
     624             :                          const CRFTData& from, const CRFTData& to,
     625             :                          const CRFTData& expected, bool expected_deprecation,
     626             :                          bool expected_field_owner_dependency) {
     627             :   Isolate* isolate = CcTest::i_isolate();
     628         192 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     629             : 
     630         192 :   CHECK(detach_property_at_index >= -1 &&
     631             :         detach_property_at_index < kPropCount);
     632         192 :   CHECK_LT(property_index, kPropCount);
     633         192 :   CHECK_NE(detach_property_at_index, property_index);
     634             : 
     635             :   const bool is_detached_map = detach_property_at_index >= 0;
     636             : 
     637         192 :   Expectations expectations(isolate);
     638             : 
     639             :   // Create a map, add required properties to it and initialize expectations.
     640         192 :   Handle<Map> initial_map = Map::Create(isolate, 0);
     641         192 :   Handle<Map> map = initial_map;
     642             :   Handle<Map> detach_point_map;
     643        2880 :   for (int i = 0; i < kPropCount; i++) {
     644        1344 :     if (i == property_index) {
     645         192 :       map = expectations.AddDataField(map, NONE, from.constness,
     646         192 :                                       from.representation, from.type);
     647             :     } else {
     648             :       map = expectations.AddDataField(map, NONE, kDefaultFieldConstness,
     649        1152 :                                       Representation::Double(), any_type);
     650        1152 :       if (i == detach_property_at_index) {
     651             :         detach_point_map = map;
     652             :       }
     653             :     }
     654             :   }
     655         192 :   CHECK(!map->is_deprecated());
     656         192 :   CHECK(map->is_stable());
     657         192 :   CHECK(expectations.Check(*map));
     658             : 
     659         192 :   if (is_detached_map) {
     660             :     detach_point_map = Map::ReconfigureProperty(
     661             :         isolate, detach_point_map, detach_property_at_index, kData, NONE,
     662          48 :         Representation::Tagged(), any_type);
     663             :     expectations.SetDataField(detach_property_at_index, kDefaultFieldConstness,
     664             :                               Representation::Tagged(), any_type);
     665          48 :     CHECK(map->is_deprecated());
     666          48 :     CHECK(expectations.Check(*detach_point_map,
     667             :                              detach_point_map->NumberOfOwnDescriptors()));
     668             :   }
     669             : 
     670             :   // Create dummy optimized code object to test correct dependencies
     671             :   // on the field owner.
     672         192 :   Handle<Code> code = CreateDummyOptimizedCode(isolate);
     673             :   Handle<Map> field_owner(map->FindFieldOwner(isolate, property_index),
     674         384 :                           isolate);
     675         384 :   DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
     676             :                                    field_owner,
     677         192 :                                    DependentCode::kFieldOwnerGroup);
     678         192 :   CHECK(!code->marked_for_deoptimization());
     679             : 
     680             :   // Create new maps by generalizing representation of propX field.
     681             :   Handle<Map> new_map = Map::ReconfigureProperty(
     682         192 :       isolate, map, property_index, kData, NONE, to.representation, to.type);
     683             : 
     684         192 :   expectations.SetDataField(property_index, expected.constness,
     685             :                             expected.representation, expected.type);
     686             : 
     687         192 :   CHECK(!new_map->is_deprecated());
     688         192 :   CHECK(expectations.Check(*new_map));
     689             : 
     690         192 :   if (is_detached_map) {
     691          48 :     CHECK(!map->is_stable());
     692          48 :     CHECK(map->is_deprecated());
     693          48 :     CHECK_NE(*map, *new_map);
     694          72 :     CHECK_EQ(expected_field_owner_dependency && !field_owner->is_deprecated(),
     695             :              code->marked_for_deoptimization());
     696             : 
     697         144 :   } else if (expected_deprecation) {
     698          36 :     CHECK(!map->is_stable());
     699          36 :     CHECK(map->is_deprecated());
     700          36 :     CHECK(field_owner->is_deprecated());
     701          36 :     CHECK_NE(*map, *new_map);
     702          36 :     CHECK(!code->marked_for_deoptimization());
     703             : 
     704             :   } else {
     705         108 :     CHECK(!field_owner->is_deprecated());
     706         108 :     CHECK(map->is_stable());  // Map did not change, must be left stable.
     707         108 :     CHECK_EQ(*map, *new_map);
     708             : 
     709         108 :     CHECK_EQ(expected_field_owner_dependency,
     710             :              code->marked_for_deoptimization());
     711             :   }
     712             : 
     713             :   {
     714             :     // Check that all previous maps are not stable.
     715         192 :     Map tmp = *new_map;
     716             :     while (true) {
     717        1536 :       Object back = tmp->GetBackPointer();
     718        1536 :       if (back->IsUndefined(isolate)) break;
     719        1344 :       tmp = Map::cast(back);
     720        1344 :       CHECK(!tmp->is_stable());
     721             :     }
     722             :   }
     723             : 
     724             :   // Update all deprecated maps and check that they are now the same.
     725         192 :   Handle<Map> updated_map = Map::Update(isolate, map);
     726         192 :   CHECK_EQ(*new_map, *updated_map);
     727         192 :   CheckMigrationTarget(isolate, *map, *updated_map);
     728         192 : }
     729             : 
     730          40 : void TestGeneralizeField(const CRFTData& from, const CRFTData& to,
     731             :                          const CRFTData& expected, bool expected_deprecation,
     732             :                          bool expected_field_owner_dependency) {
     733             :   // Check the cases when the map being reconfigured is a part of the
     734             :   // transition tree.
     735             :   STATIC_ASSERT(kPropCount > 4);
     736          40 :   int indices[] = {0, 2, kPropCount - 1};
     737         280 :   for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
     738         120 :     TestGeneralizeField(-1, indices[i], from, to, expected,
     739         120 :                         expected_deprecation, expected_field_owner_dependency);
     740             :   }
     741             : 
     742          40 :   if (!from.representation.IsNone()) {
     743             :     // Check the cases when the map being reconfigured is NOT a part of the
     744             :     // transition tree. "None -> anything" representation changes make sense
     745             :     // only for "attached" maps.
     746          24 :     int indices[] = {0, kPropCount - 1};
     747         120 :     for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
     748          48 :       TestGeneralizeField(indices[i], 2, from, to, expected,
     749             :                           expected_deprecation,
     750          48 :                           expected_field_owner_dependency);
     751             :     }
     752             : 
     753             :     // Check that reconfiguration to the very same field works correctly.
     754          24 :     CRFTData data = from;
     755          24 :     TestGeneralizeField(-1, 2, data, data, data, false, false);
     756             :   }
     757          40 : }
     758             : 
     759             : void TestGeneralizeField(const CRFTData& from, const CRFTData& to,
     760             :                          const CRFTData& expected) {
     761             :   const bool expected_deprecation = true;
     762             :   const bool expected_field_owner_dependency = false;
     763             : 
     764             :   TestGeneralizeField(from, to, expected, expected_deprecation,
     765          12 :                       expected_field_owner_dependency);
     766             : }
     767             : 
     768             : void TestGeneralizeFieldTrivial(const CRFTData& from, const CRFTData& to,
     769             :                                 const CRFTData& expected,
     770             :                                 bool expected_field_owner_dependency = true) {
     771             :   const bool expected_deprecation = false;
     772             : 
     773             :   TestGeneralizeField(from, to, expected, expected_deprecation,
     774          20 :                       expected_field_owner_dependency);
     775             : }
     776             : 
     777             : }  // namespace
     778             : 
     779       26643 : TEST(GeneralizeSmiFieldToDouble) {
     780           4 :   CcTest::InitializeVM();
     781           8 :   v8::HandleScope scope(CcTest::isolate());
     782             :   Isolate* isolate = CcTest::i_isolate();
     783             : 
     784           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     785             : 
     786           8 :   TestGeneralizeField(
     787             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
     788             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
     789             :       {PropertyConstness::kMutable, Representation::Double(), any_type});
     790           4 : }
     791             : 
     792       26643 : TEST(GeneralizeSmiFieldToTagged) {
     793           4 :   CcTest::InitializeVM();
     794           8 :   v8::HandleScope scope(CcTest::isolate());
     795             :   Isolate* isolate = CcTest::i_isolate();
     796             : 
     797           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     798             :   Handle<FieldType> value_type =
     799           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
     800             : 
     801          12 :   TestGeneralizeField(
     802             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
     803             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
     804             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type},
     805           4 :       !FLAG_modify_field_representation_inplace,
     806           4 :       FLAG_modify_field_representation_inplace);
     807           4 : }
     808             : 
     809       26643 : TEST(GeneralizeDoubleFieldToTagged) {
     810           4 :   CcTest::InitializeVM();
     811           8 :   v8::HandleScope scope(CcTest::isolate());
     812             :   Isolate* isolate = CcTest::i_isolate();
     813             : 
     814           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     815             :   Handle<FieldType> value_type =
     816           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
     817             : 
     818           8 :   TestGeneralizeField(
     819             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
     820             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
     821             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
     822           4 : }
     823             : 
     824       26643 : TEST(GeneralizeHeapObjectFieldToTagged) {
     825           4 :   CcTest::InitializeVM();
     826           8 :   v8::HandleScope scope(CcTest::isolate());
     827             :   Isolate* isolate = CcTest::i_isolate();
     828             : 
     829           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     830             :   Handle<FieldType> value_type =
     831           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
     832             : 
     833          12 :   TestGeneralizeField(
     834             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
     835             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
     836             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type},
     837           4 :       !FLAG_modify_field_representation_inplace,
     838           4 :       FLAG_modify_field_representation_inplace);
     839           4 : }
     840             : 
     841       26643 : TEST(GeneralizeHeapObjectFieldToHeapObject) {
     842           4 :   CcTest::InitializeVM();
     843           8 :   v8::HandleScope scope(CcTest::isolate());
     844             :   Isolate* isolate = CcTest::i_isolate();
     845             : 
     846           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     847             : 
     848             :   Handle<FieldType> current_type =
     849           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
     850             : 
     851             :   Handle<FieldType> new_type =
     852           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
     853             : 
     854           4 :   Handle<FieldType> expected_type = any_type;
     855             : 
     856           8 :   TestGeneralizeFieldTrivial(
     857             :       {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
     858             :       {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
     859             :       {PropertyConstness::kMutable, Representation::HeapObject(),
     860             :        expected_type});
     861             :   current_type = expected_type;
     862             : 
     863           4 :   new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
     864             : 
     865           8 :   TestGeneralizeFieldTrivial(
     866             :       {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
     867             :       {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
     868             :       {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
     869             :       false);
     870           4 : }
     871             : 
     872       26643 : TEST(GeneralizeNoneFieldToSmi) {
     873           4 :   CcTest::InitializeVM();
     874           8 :   v8::HandleScope scope(CcTest::isolate());
     875             :   Isolate* isolate = CcTest::i_isolate();
     876             : 
     877           4 :   Handle<FieldType> none_type = FieldType::None(isolate);
     878           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     879             : 
     880             :   // None -> Smi representation change is trivial.
     881           8 :   TestGeneralizeFieldTrivial(
     882             :       {PropertyConstness::kMutable, Representation::None(), none_type},
     883             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
     884             :       {PropertyConstness::kMutable, Representation::Smi(), any_type});
     885           4 : }
     886             : 
     887       26643 : TEST(GeneralizeNoneFieldToDouble) {
     888           4 :   CcTest::InitializeVM();
     889           8 :   v8::HandleScope scope(CcTest::isolate());
     890             :   Isolate* isolate = CcTest::i_isolate();
     891             : 
     892           4 :   Handle<FieldType> none_type = FieldType::None(isolate);
     893           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     894             : 
     895             :   // None -> Double representation change is NOT trivial.
     896           8 :   TestGeneralizeField(
     897             :       {PropertyConstness::kMutable, Representation::None(), none_type},
     898             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
     899             :       {PropertyConstness::kMutable, Representation::Double(), any_type});
     900           4 : }
     901             : 
     902       26643 : TEST(GeneralizeNoneFieldToHeapObject) {
     903           4 :   CcTest::InitializeVM();
     904           8 :   v8::HandleScope scope(CcTest::isolate());
     905             :   Isolate* isolate = CcTest::i_isolate();
     906             : 
     907           4 :   Handle<FieldType> none_type = FieldType::None(isolate);
     908             :   Handle<FieldType> value_type =
     909           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
     910             : 
     911             :   // None -> HeapObject representation change is trivial.
     912           8 :   TestGeneralizeFieldTrivial(
     913             :       {PropertyConstness::kMutable, Representation::None(), none_type},
     914             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
     915             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type});
     916           4 : }
     917             : 
     918       26643 : TEST(GeneralizeNoneFieldToTagged) {
     919           4 :   CcTest::InitializeVM();
     920           8 :   v8::HandleScope scope(CcTest::isolate());
     921             :   Isolate* isolate = CcTest::i_isolate();
     922             : 
     923           4 :   Handle<FieldType> none_type = FieldType::None(isolate);
     924           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     925             : 
     926             :   // None -> HeapObject representation change is trivial.
     927           8 :   TestGeneralizeFieldTrivial(
     928             :       {PropertyConstness::kMutable, Representation::None(), none_type},
     929             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type},
     930             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
     931           4 : }
     932             : 
     933             : 
     934             : ////////////////////////////////////////////////////////////////////////////////
     935             : // A set of tests for field generalization case with kAccessor properties.
     936             : //
     937             : 
     938       26643 : TEST(GeneralizeFieldWithAccessorProperties) {
     939           4 :   CcTest::InitializeVM();
     940           8 :   v8::HandleScope scope(CcTest::isolate());
     941             :   Isolate* isolate = CcTest::i_isolate();
     942             : 
     943           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     944           4 :   Handle<AccessorPair> pair = CreateAccessorPair(true, true);
     945             : 
     946             :   const int kAccessorProp = kPropCount / 2;
     947           4 :   Expectations expectations(isolate);
     948             : 
     949             :   // Create a map, add required properties to it and initialize expectations.
     950           4 :   Handle<Map> initial_map = Map::Create(isolate, 0);
     951           4 :   Handle<Map> map = initial_map;
     952          60 :   for (int i = 0; i < kPropCount; i++) {
     953          28 :     if (i == kAccessorProp) {
     954           4 :       map = expectations.AddAccessorConstant(map, NONE, pair);
     955             :     } else {
     956             :       map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
     957          24 :                                       Representation::Smi(), any_type);
     958             :     }
     959             :   }
     960           4 :   CHECK(!map->is_deprecated());
     961           4 :   CHECK(map->is_stable());
     962           4 :   CHECK(expectations.Check(*map));
     963             : 
     964             :   // Create new maps by generalizing representation of propX field.
     965          60 :   Handle<Map> maps[kPropCount];
     966          60 :   for (int i = 0; i < kPropCount; i++) {
     967          28 :     if (i == kAccessorProp) {
     968             :       // Skip accessor property reconfiguration.
     969           4 :       maps[i] = maps[i - 1];
     970             :       continue;
     971             :     }
     972             :     Handle<Map> new_map = Map::ReconfigureProperty(
     973          24 :         isolate, map, i, kData, NONE, Representation::Double(), any_type);
     974          24 :     maps[i] = new_map;
     975             : 
     976             :     expectations.SetDataField(i, PropertyConstness::kMutable,
     977             :                               Representation::Double(), any_type);
     978             : 
     979          24 :     CHECK(!map->is_stable());
     980          24 :     CHECK(map->is_deprecated());
     981          24 :     CHECK_NE(*map, *new_map);
     982          44 :     CHECK(i == 0 || maps[i - 1]->is_deprecated());
     983             : 
     984          24 :     CHECK(!new_map->is_deprecated());
     985          24 :     CHECK(expectations.Check(*new_map));
     986             :   }
     987             : 
     988           4 :   Handle<Map> active_map = maps[kPropCount - 1];
     989           4 :   CHECK(!active_map->is_deprecated());
     990             : 
     991             :   // Update all deprecated maps and check that they are now the same.
     992           4 :   Handle<Map> updated_map = Map::Update(isolate, map);
     993           4 :   CHECK_EQ(*active_map, *updated_map);
     994           4 :   CheckMigrationTarget(isolate, *map, *updated_map);
     995          60 :   for (int i = 0; i < kPropCount; i++) {
     996          28 :     updated_map = Map::Update(isolate, maps[i]);
     997          28 :     CHECK_EQ(*active_map, *updated_map);
     998          56 :     CheckMigrationTarget(isolate, *maps[i], *updated_map);
     999             :   }
    1000           4 : }
    1001             : 
    1002             : 
    1003             : ////////////////////////////////////////////////////////////////////////////////
    1004             : // A set of tests for attribute reconfiguration case.
    1005             : //
    1006             : 
    1007             : namespace {
    1008             : 
    1009             : // This test ensures that field generalization is correctly propagated from one
    1010             : // branch of transition tree (|map2|) to another (|map|).
    1011             : //
    1012             : //             + - p2B - p3 - p4: |map2|
    1013             : //             |
    1014             : //  {} - p0 - p1 - p2A - p3 - p4: |map|
    1015             : //
    1016             : // where "p2A" and "p2B" differ only in the attributes.
    1017             : //
    1018          52 : void TestReconfigureDataFieldAttribute_GeneralizeField(
    1019             :     const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
    1020             :   Isolate* isolate = CcTest::i_isolate();
    1021             : 
    1022          52 :   Expectations expectations(isolate);
    1023             : 
    1024             :   // Create a map, add required properties to it and initialize expectations.
    1025          52 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    1026          52 :   Handle<Map> map = initial_map;
    1027         780 :   for (int i = 0; i < kPropCount; i++) {
    1028         364 :     map = expectations.AddDataField(map, NONE, from.constness,
    1029         364 :                                     from.representation, from.type);
    1030             :   }
    1031          52 :   CHECK(!map->is_deprecated());
    1032          52 :   CHECK(map->is_stable());
    1033          52 :   CHECK(expectations.Check(*map));
    1034             : 
    1035             : 
    1036             :   // Create another branch in transition tree (property at index |kSplitProp|
    1037             :   // has different attributes), initialize expectations.
    1038             :   const int kSplitProp = kPropCount / 2;
    1039          52 :   Expectations expectations2(isolate);
    1040             : 
    1041             :   Handle<Map> map2 = initial_map;
    1042         364 :   for (int i = 0; i < kSplitProp; i++) {
    1043         156 :     map2 = expectations2.FollowDataTransition(map2, NONE, from.constness,
    1044         156 :                                               from.representation, from.type);
    1045             :   }
    1046          52 :   map2 = expectations2.AddDataField(map2, READ_ONLY, to.constness,
    1047          52 :                                     to.representation, to.type);
    1048             : 
    1049         364 :   for (int i = kSplitProp + 1; i < kPropCount; i++) {
    1050         156 :     map2 = expectations2.AddDataField(map2, NONE, to.constness,
    1051         156 :                                       to.representation, to.type);
    1052             :   }
    1053          52 :   CHECK(!map2->is_deprecated());
    1054          52 :   CHECK(map2->is_stable());
    1055          52 :   CHECK(expectations2.Check(*map2));
    1056             : 
    1057             :   // Create dummy optimized code object to test correct dependencies
    1058             :   // on the field owner.
    1059          52 :   Handle<Code> code = CreateDummyOptimizedCode(isolate);
    1060         104 :   Handle<Map> field_owner(map->FindFieldOwner(isolate, kSplitProp), isolate);
    1061         104 :   DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
    1062             :                                    field_owner,
    1063          52 :                                    DependentCode::kFieldOwnerGroup);
    1064          52 :   CHECK(!code->marked_for_deoptimization());
    1065             : 
    1066             :   // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
    1067             :   // should generalize representations in |map1|.
    1068             :   Handle<Map> new_map =
    1069          52 :       Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
    1070             : 
    1071             :   // |map2| should be left unchanged but marked unstable.
    1072          52 :   CHECK(!map2->is_stable());
    1073          52 :   CHECK(!map2->is_deprecated());
    1074          52 :   CHECK_NE(*map2, *new_map);
    1075          52 :   CHECK(expectations2.Check(*map2));
    1076             : 
    1077             :   // |map| should be deprecated and |new_map| should match new expectations.
    1078         468 :   for (int i = kSplitProp; i < kPropCount; i++) {
    1079         208 :     expectations.SetDataField(i, expected.constness, expected.representation,
    1080             :                               expected.type);
    1081             :   }
    1082          52 :   CHECK(map->is_deprecated());
    1083          52 :   CHECK(!code->marked_for_deoptimization());
    1084          52 :   CHECK_NE(*map, *new_map);
    1085             : 
    1086          52 :   CHECK(!new_map->is_deprecated());
    1087          52 :   CHECK(expectations.Check(*new_map));
    1088             : 
    1089             :   // Update deprecated |map|, it should become |new_map|.
    1090          52 :   Handle<Map> updated_map = Map::Update(isolate, map);
    1091          52 :   CHECK_EQ(*new_map, *updated_map);
    1092          52 :   CheckMigrationTarget(isolate, *map, *updated_map);
    1093          52 : }
    1094             : 
    1095             : // This test ensures that trivial field generalization (from HeapObject to
    1096             : // HeapObject) is correctly propagated from one branch of transition tree
    1097             : // (|map2|) to another (|map|).
    1098             : //
    1099             : //             + - p2B - p3 - p4: |map2|
    1100             : //             |
    1101             : //  {} - p0 - p1 - p2A - p3 - p4: |map|
    1102             : //
    1103             : // where "p2A" and "p2B" differ only in the attributes.
    1104             : //
    1105          32 : void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1106             :     const CRFTData& from, const CRFTData& to, const CRFTData& expected,
    1107             :     bool expected_field_owner_dependency = true) {
    1108             :   Isolate* isolate = CcTest::i_isolate();
    1109             : 
    1110          32 :   Expectations expectations(isolate);
    1111             : 
    1112             :   // Create a map, add required properties to it and initialize expectations.
    1113          32 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    1114          32 :   Handle<Map> map = initial_map;
    1115         480 :   for (int i = 0; i < kPropCount; i++) {
    1116         224 :     map = expectations.AddDataField(map, NONE, from.constness,
    1117         224 :                                     from.representation, from.type);
    1118             :   }
    1119          32 :   CHECK(!map->is_deprecated());
    1120          32 :   CHECK(map->is_stable());
    1121          32 :   CHECK(expectations.Check(*map));
    1122             : 
    1123             : 
    1124             :   // Create another branch in transition tree (property at index |kSplitProp|
    1125             :   // has different attributes), initialize expectations.
    1126             :   const int kSplitProp = kPropCount / 2;
    1127          32 :   Expectations expectations2(isolate);
    1128             : 
    1129             :   Handle<Map> map2 = initial_map;
    1130         224 :   for (int i = 0; i < kSplitProp; i++) {
    1131          96 :     map2 = expectations2.FollowDataTransition(map2, NONE, from.constness,
    1132          96 :                                               from.representation, from.type);
    1133             :   }
    1134          32 :   map2 = expectations2.AddDataField(map2, READ_ONLY, to.constness,
    1135          32 :                                     to.representation, to.type);
    1136             : 
    1137         224 :   for (int i = kSplitProp + 1; i < kPropCount; i++) {
    1138          96 :     map2 = expectations2.AddDataField(map2, NONE, to.constness,
    1139          96 :                                       to.representation, to.type);
    1140             :   }
    1141          32 :   CHECK(!map2->is_deprecated());
    1142          32 :   CHECK(map2->is_stable());
    1143          32 :   CHECK(expectations2.Check(*map2));
    1144             : 
    1145             :   // Create dummy optimized code object to test correct dependencies
    1146             :   // on the field owner.
    1147          32 :   Handle<Code> code = CreateDummyOptimizedCode(isolate);
    1148          64 :   Handle<Map> field_owner(map->FindFieldOwner(isolate, kSplitProp), isolate);
    1149          64 :   DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
    1150             :                                    field_owner,
    1151          32 :                                    DependentCode::kFieldOwnerGroup);
    1152          32 :   CHECK(!code->marked_for_deoptimization());
    1153             : 
    1154             :   // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
    1155             :   // should generalize representations in |map1|.
    1156             :   Handle<Map> new_map =
    1157          32 :       Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
    1158             : 
    1159             :   // |map2| should be left unchanged but marked unstable.
    1160          32 :   CHECK(!map2->is_stable());
    1161          32 :   CHECK(!map2->is_deprecated());
    1162          32 :   CHECK_NE(*map2, *new_map);
    1163          32 :   CHECK(expectations2.Check(*map2));
    1164             : 
    1165             :   // In trivial case |map| should be returned as a result of the property
    1166             :   // reconfiguration, respective field types should be generalized and
    1167             :   // respective code dependencies should be invalidated. |map| should be NOT
    1168             :   // deprecated and it should match new expectations.
    1169         288 :   for (int i = kSplitProp; i < kPropCount; i++) {
    1170         128 :     expectations.SetDataField(i, expected.constness, expected.representation,
    1171             :                               expected.type);
    1172             :   }
    1173          32 :   CHECK(!map->is_deprecated());
    1174          32 :   CHECK_EQ(*map, *new_map);
    1175          32 :   CHECK_EQ(expected_field_owner_dependency, code->marked_for_deoptimization());
    1176             : 
    1177          32 :   CHECK(!new_map->is_deprecated());
    1178          32 :   CHECK(expectations.Check(*new_map));
    1179             : 
    1180          32 :   Handle<Map> updated_map = Map::Update(isolate, map);
    1181          32 :   CHECK_EQ(*new_map, *updated_map);
    1182          32 : }
    1183             : 
    1184             : }  // namespace
    1185             : 
    1186       26643 : TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToDouble) {
    1187           4 :   CcTest::InitializeVM();
    1188           8 :   v8::HandleScope scope(CcTest::isolate());
    1189             :   Isolate* isolate = CcTest::i_isolate();
    1190             : 
    1191           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1192             : 
    1193             :   if (FLAG_track_constant_fields) {
    1194           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1195             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    1196             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    1197           4 :         {PropertyConstness::kConst, Representation::Double(), any_type});
    1198             : 
    1199           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1200             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    1201             :         {PropertyConstness::kMutable, Representation::Double(), any_type},
    1202           4 :         {PropertyConstness::kMutable, Representation::Double(), any_type});
    1203             : 
    1204           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1205             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1206             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    1207           4 :         {PropertyConstness::kMutable, Representation::Double(), any_type});
    1208             :   }
    1209             : 
    1210           8 :   TestReconfigureDataFieldAttribute_GeneralizeField(
    1211             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1212             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
    1213           4 :       {PropertyConstness::kMutable, Representation::Double(), any_type});
    1214           4 : }
    1215             : 
    1216       26643 : TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) {
    1217           4 :   CcTest::InitializeVM();
    1218           8 :   v8::HandleScope scope(CcTest::isolate());
    1219             :   Isolate* isolate = CcTest::i_isolate();
    1220             : 
    1221           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1222             :   Handle<FieldType> value_type =
    1223           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    1224             : 
    1225             :   if (FLAG_track_constant_fields) {
    1226           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1227             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    1228             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    1229           4 :         {PropertyConstness::kConst, Representation::Tagged(), any_type});
    1230             : 
    1231           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1232             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    1233             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    1234           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1235             : 
    1236           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1237             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1238             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    1239           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1240             :   }
    1241             : 
    1242           8 :   TestReconfigureDataFieldAttribute_GeneralizeField(
    1243             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1244             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    1245           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1246           4 : }
    1247             : 
    1248       26643 : TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) {
    1249           4 :   CcTest::InitializeVM();
    1250           8 :   v8::HandleScope scope(CcTest::isolate());
    1251             :   Isolate* isolate = CcTest::i_isolate();
    1252             : 
    1253           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1254             :   Handle<FieldType> value_type =
    1255           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    1256             : 
    1257             :   if (FLAG_track_constant_fields) {
    1258           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1259             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    1260             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    1261           4 :         {PropertyConstness::kConst, Representation::Tagged(), any_type});
    1262             : 
    1263           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1264             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    1265             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    1266           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1267             : 
    1268           8 :     TestReconfigureDataFieldAttribute_GeneralizeField(
    1269             :         {PropertyConstness::kMutable, Representation::Double(), any_type},
    1270             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    1271           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1272             :   }
    1273             : 
    1274           8 :   TestReconfigureDataFieldAttribute_GeneralizeField(
    1275             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
    1276             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    1277           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1278           4 : }
    1279             : 
    1280       26643 : TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
    1281           4 :   CcTest::InitializeVM();
    1282           8 :   v8::HandleScope scope(CcTest::isolate());
    1283             :   Isolate* isolate = CcTest::i_isolate();
    1284             : 
    1285           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1286             : 
    1287             :   Handle<FieldType> current_type =
    1288           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    1289             : 
    1290             :   Handle<FieldType> new_type =
    1291           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    1292             : 
    1293           4 :   Handle<FieldType> expected_type = any_type;
    1294             : 
    1295             :   // Check generalizations that trigger deopts.
    1296             :   if (FLAG_track_constant_fields) {
    1297           8 :     TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1298             :         {PropertyConstness::kConst, Representation::HeapObject(), current_type},
    1299             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    1300             :         {PropertyConstness::kConst, Representation::HeapObject(),
    1301           4 :          expected_type});
    1302             : 
    1303             :       // PropertyConstness::kConst to PropertyConstness::kMutable migration does
    1304             :       // not create a new map, therefore trivial generalization.
    1305           8 :       TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1306             :           {PropertyConstness::kConst, Representation::HeapObject(),
    1307             :            current_type},
    1308             :           {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    1309             :           {PropertyConstness::kMutable, Representation::HeapObject(),
    1310           4 :            expected_type});
    1311           8 :     TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1312             :         {PropertyConstness::kMutable, Representation::HeapObject(),
    1313             :          current_type},
    1314             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    1315             :         {PropertyConstness::kMutable, Representation::HeapObject(),
    1316           4 :          expected_type});
    1317             :   }
    1318           8 :   TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1319             :       {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
    1320             :       {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    1321             :       {PropertyConstness::kMutable, Representation::HeapObject(),
    1322           4 :        expected_type});
    1323             :   current_type = expected_type;
    1324             : 
    1325             :   // Check generalizations that do not trigger deopts.
    1326           4 :   new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
    1327             : 
    1328             :   if (FLAG_track_constant_fields) {
    1329           8 :     TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1330             :         {PropertyConstness::kConst, Representation::HeapObject(), any_type},
    1331             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    1332             :         {PropertyConstness::kConst, Representation::HeapObject(), any_type},
    1333           4 :         false);
    1334             : 
    1335             :       // PropertyConstness::kConst to PropertyConstness::kMutable migration does
    1336             :       // not create a new map, therefore trivial generalization.
    1337           8 :       TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1338             :           {PropertyConstness::kConst, Representation::HeapObject(), any_type},
    1339             :           {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    1340             :           {PropertyConstness::kMutable, Representation::HeapObject(),
    1341           4 :            any_type});
    1342             : 
    1343           8 :     TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1344             :         {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
    1345             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    1346             :         {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
    1347           4 :         false);
    1348             :   }
    1349           8 :   TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
    1350             :       {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
    1351             :       {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    1352             :       {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
    1353           4 :       false);
    1354           4 : }
    1355             : 
    1356       26643 : TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) {
    1357           4 :   CcTest::InitializeVM();
    1358           8 :   v8::HandleScope scope(CcTest::isolate());
    1359             :   Isolate* isolate = CcTest::i_isolate();
    1360             : 
    1361           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1362             :   Handle<FieldType> value_type =
    1363           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    1364             : 
    1365           8 :   TestReconfigureDataFieldAttribute_GeneralizeField(
    1366             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    1367             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1368           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    1369           4 : }
    1370             : 
    1371             : 
    1372             : // Checks that given |map| is deprecated and that it updates to given |new_map|
    1373             : // which in turn should match expectations.
    1374             : struct CheckDeprecated {
    1375             :   void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
    1376             :              const Expectations& expectations) {
    1377             :     CHECK(map->is_deprecated());
    1378             :     CHECK_NE(*map, *new_map);
    1379             : 
    1380             :     CHECK(!new_map->is_deprecated());
    1381             :     CHECK(expectations.Check(*new_map));
    1382             : 
    1383             :     // Update deprecated |map|, it should become |new_map|.
    1384             :     Handle<Map> updated_map = Map::Update(isolate, map);
    1385             :     CHECK_EQ(*new_map, *updated_map);
    1386             :     CheckMigrationTarget(isolate, *map, *updated_map);
    1387             :   }
    1388             : };
    1389             : 
    1390             : 
    1391             : // Checks that given |map| is NOT deprecated, equals to given |new_map| and
    1392             : // matches expectations.
    1393             : struct CheckSameMap {
    1394          12 :   void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
    1395             :              const Expectations& expectations) {
    1396             :     // |map| was not reconfigured, therefore it should stay stable.
    1397          12 :     CHECK(map->is_stable());
    1398          12 :     CHECK(!map->is_deprecated());
    1399          12 :     CHECK_EQ(*map, *new_map);
    1400             : 
    1401          12 :     CHECK(!new_map->is_deprecated());
    1402          12 :     CHECK(expectations.Check(*new_map));
    1403             : 
    1404             :     // Update deprecated |map|, it should become |new_map|.
    1405          12 :     Handle<Map> updated_map = Map::Update(isolate, map);
    1406          12 :     CHECK_EQ(*new_map, *updated_map);
    1407          12 :   }
    1408             : };
    1409             : 
    1410             : 
    1411             : // Checks that given |map| is NOT deprecated and matches expectations.
    1412             : // |new_map| is unrelated to |map|.
    1413             : struct CheckUnrelated {
    1414           8 :   void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
    1415             :              const Expectations& expectations) {
    1416           8 :     CHECK(!map->is_deprecated());
    1417           8 :     CHECK_NE(*map, *new_map);
    1418           8 :     CHECK(expectations.Check(*map));
    1419             : 
    1420           8 :     CHECK(new_map->is_stable());
    1421           8 :     CHECK(!new_map->is_deprecated());
    1422           8 :   }
    1423             : };
    1424             : 
    1425             : 
    1426             : // Checks that given |map| is NOT deprecated, and |new_map| is a result of
    1427             : // copy-generalize-all-representations.
    1428             : struct CheckCopyGeneralizeAllFields {
    1429           4 :   void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
    1430             :              Expectations& expectations) {
    1431           4 :     CHECK(!map->is_deprecated());
    1432           4 :     CHECK_NE(*map, *new_map);
    1433             : 
    1434           8 :     CHECK(new_map->GetBackPointer()->IsUndefined(isolate));
    1435          60 :     for (int i = 0; i < kPropCount; i++) {
    1436          28 :       expectations.GeneralizeField(i);
    1437             :     }
    1438             : 
    1439           4 :     CHECK(!new_map->is_deprecated());
    1440           4 :     CHECK(expectations.Check(*new_map));
    1441           4 :   }
    1442             : };
    1443             : 
    1444             : // This test ensures that field generalization is correctly propagated from one
    1445             : // branch of transition tree (|map2|) to another (|map1|).
    1446             : //
    1447             : //             + - p2B - p3 - p4: |map2|
    1448             : //             |
    1449             : //  {} - p0 - p1: |map|
    1450             : //             |
    1451             : //             + - p2A - p3 - p4: |map1|
    1452             : //                        |
    1453             : //                        + - the property customized by the TestConfig provided
    1454             : //
    1455             : // where "p2A" and "p2B" differ only in the attributes.
    1456             : //
    1457             : template <typename TestConfig, typename Checker>
    1458          24 : static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
    1459             :     TestConfig& config, Checker& checker) {
    1460             :   Isolate* isolate = CcTest::i_isolate();
    1461          24 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1462             : 
    1463             :   const int kCustomPropIndex = kPropCount - 2;
    1464          24 :   Expectations expectations(isolate);
    1465             : 
    1466             :   const int kSplitProp = 2;
    1467             :   CHECK_LT(kSplitProp, kCustomPropIndex);
    1468             : 
    1469             :   const PropertyConstness constness = PropertyConstness::kMutable;
    1470          24 :   const Representation representation = Representation::Smi();
    1471             : 
    1472             :   // Create common part of transition tree.
    1473          24 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    1474          24 :   Handle<Map> map = initial_map;
    1475         120 :   for (int i = 0; i < kSplitProp; i++) {
    1476          48 :     map = expectations.AddDataField(map, NONE, constness, representation,
    1477             :                                     any_type);
    1478             :   }
    1479          24 :   CHECK(!map->is_deprecated());
    1480          24 :   CHECK(map->is_stable());
    1481          24 :   CHECK(expectations.Check(*map));
    1482             : 
    1483             : 
    1484             :   // Create branch to |map1|.
    1485             :   Handle<Map> map1 = map;
    1486          24 :   Expectations expectations1 = expectations;
    1487         168 :   for (int i = kSplitProp; i < kCustomPropIndex; i++) {
    1488          72 :     map1 = expectations1.AddDataField(map1, NONE, constness, representation,
    1489             :                                       any_type);
    1490             :   }
    1491          24 :   map1 = config.AddPropertyAtBranch(1, expectations1, map1);
    1492          72 :   for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
    1493          24 :     map1 = expectations1.AddDataField(map1, NONE, constness, representation,
    1494             :                                       any_type);
    1495             :   }
    1496          24 :   CHECK(!map1->is_deprecated());
    1497          24 :   CHECK(map1->is_stable());
    1498          24 :   CHECK(expectations1.Check(*map1));
    1499             : 
    1500             : 
    1501             :   // Create another branch in transition tree (property at index |kSplitProp|
    1502             :   // has different attributes), initialize expectations.
    1503             :   Handle<Map> map2 = map;
    1504          24 :   Expectations expectations2 = expectations;
    1505          24 :   map2 = expectations2.AddDataField(map2, READ_ONLY, constness, representation,
    1506             :                                     any_type);
    1507         120 :   for (int i = kSplitProp + 1; i < kCustomPropIndex; i++) {
    1508          48 :     map2 = expectations2.AddDataField(map2, NONE, constness, representation,
    1509             :                                       any_type);
    1510             :   }
    1511          24 :   map2 = config.AddPropertyAtBranch(2, expectations2, map2);
    1512          72 :   for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
    1513          24 :     map2 = expectations2.AddDataField(map2, NONE, constness, representation,
    1514             :                                       any_type);
    1515             :   }
    1516          24 :   CHECK(!map2->is_deprecated());
    1517          24 :   CHECK(map2->is_stable());
    1518          24 :   CHECK(expectations2.Check(*map2));
    1519             : 
    1520             : 
    1521             :   // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
    1522             :   // should generalize representations in |map1|.
    1523             :   Handle<Map> new_map =
    1524          24 :       Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
    1525             : 
    1526             :   // |map2| should be left unchanged but marked unstable.
    1527          24 :   CHECK(!map2->is_stable());
    1528          24 :   CHECK(!map2->is_deprecated());
    1529          24 :   CHECK_NE(*map2, *new_map);
    1530          24 :   CHECK(expectations2.Check(*map2));
    1531             : 
    1532           4 :   config.UpdateExpectations(kCustomPropIndex, expectations1);
    1533          24 :   checker.Check(isolate, map1, new_map, expectations1);
    1534          24 : }
    1535             : 
    1536             : 
    1537       26643 : TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) {
    1538           4 :   CcTest::InitializeVM();
    1539           8 :   v8::HandleScope scope(CcTest::isolate());
    1540             : 
    1541             :   struct TestConfig {
    1542             :     Handle<JSFunction> js_func_;
    1543           4 :     TestConfig() {
    1544             :       Isolate* isolate = CcTest::i_isolate();
    1545             :       Factory* factory = isolate->factory();
    1546           4 :       js_func_ = factory->NewFunctionForTest(factory->empty_string());
    1547           4 :     }
    1548             : 
    1549           8 :     Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
    1550             :                                     Handle<Map> map) {
    1551           8 :       CHECK(branch_id == 1 || branch_id == 2);
    1552             :       // Add the same data constant property at both transition tree branches.
    1553           8 :       return expectations.AddDataConstant(map, NONE, js_func_);
    1554             :     }
    1555             : 
    1556             :     void UpdateExpectations(int property_index, Expectations& expectations) {
    1557             :       // Expectations stay the same.
    1558             :     }
    1559             :   };
    1560             : 
    1561           4 :   TestConfig config;
    1562             :   // Two branches are "compatible" so the |map1| should NOT be deprecated.
    1563             :   CheckSameMap checker;
    1564           4 :   TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1565           4 : }
    1566             : 
    1567             : 
    1568       26643 : TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
    1569           4 :   CcTest::InitializeVM();
    1570           8 :   v8::HandleScope scope(CcTest::isolate());
    1571             : 
    1572             :   struct TestConfig {
    1573             :     Handle<JSFunction> js_func1_;
    1574             :     Handle<JSFunction> js_func2_;
    1575             :     Handle<FieldType> function_type_;
    1576           4 :     TestConfig() {
    1577             :       Isolate* isolate = CcTest::i_isolate();
    1578             :       Factory* factory = isolate->factory();
    1579             :       Handle<String> name = factory->empty_string();
    1580             :       Handle<Map> sloppy_map =
    1581           4 :           Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
    1582             :       Handle<SharedFunctionInfo> info =
    1583           4 :           factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
    1584           4 :       function_type_ = FieldType::Class(sloppy_map, isolate);
    1585           4 :       CHECK(sloppy_map->is_stable());
    1586             : 
    1587             :       js_func1_ =
    1588           8 :           factory->NewFunction(sloppy_map, info, isolate->native_context());
    1589             : 
    1590             :       js_func2_ =
    1591           8 :           factory->NewFunction(sloppy_map, info, isolate->native_context());
    1592           4 :     }
    1593             : 
    1594           8 :     Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
    1595             :                                     Handle<Map> map) {
    1596           8 :       CHECK(branch_id == 1 || branch_id == 2);
    1597           8 :       Handle<JSFunction> js_func = branch_id == 1 ? js_func1_ : js_func2_;
    1598           8 :       return expectations.AddDataConstant(map, NONE, js_func);
    1599             :     }
    1600             : 
    1601           4 :     void UpdateExpectations(int property_index, Expectations& expectations) {
    1602             :       PropertyConstness expected_constness = FLAG_track_constant_fields
    1603             :                                                  ? PropertyConstness::kConst
    1604             :                                                  : PropertyConstness::kMutable;
    1605             :       expectations.SetDataField(property_index, expected_constness,
    1606             :                                 Representation::HeapObject(), function_type_);
    1607           4 :     }
    1608             :   };
    1609             : 
    1610           4 :   TestConfig config;
    1611             :   if (FLAG_track_constant_fields) {
    1612             :     CheckSameMap checker;
    1613           4 :     TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1614             : 
    1615             :   } else {
    1616             :     // Two branches are "incompatible" so the |map1| should be deprecated.
    1617             :     CheckDeprecated checker;
    1618             :     TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1619             :   }
    1620           4 : }
    1621             : 
    1622             : 
    1623       26643 : TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {
    1624           4 :   CcTest::InitializeVM();
    1625           8 :   v8::HandleScope scope(CcTest::isolate());
    1626             : 
    1627             :   struct TestConfig {
    1628             :     Handle<JSFunction> js_func_;
    1629             :     Handle<AccessorPair> pair_;
    1630           4 :     TestConfig() {
    1631             :       Isolate* isolate = CcTest::i_isolate();
    1632             :       Factory* factory = isolate->factory();
    1633           4 :       js_func_ = factory->NewFunctionForTest(factory->empty_string());
    1634           4 :       pair_ = CreateAccessorPair(true, true);
    1635           4 :     }
    1636             : 
    1637           8 :     Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
    1638             :                                     Handle<Map> map) {
    1639           8 :       CHECK(branch_id == 1 || branch_id == 2);
    1640           8 :       if (branch_id == 1) {
    1641           4 :         return expectations.AddDataConstant(map, NONE, js_func_);
    1642             :       } else {
    1643           4 :         return expectations.AddAccessorConstant(map, NONE, pair_);
    1644             :       }
    1645             :     }
    1646             : 
    1647             :     void UpdateExpectations(int property_index, Expectations& expectations) {}
    1648             :   };
    1649             : 
    1650           4 :   TestConfig config;
    1651             :   // These are completely separate branches in transition tree.
    1652             :   CheckUnrelated checker;
    1653           4 :   TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1654           4 : }
    1655             : 
    1656             : 
    1657       26643 : TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
    1658           4 :   CcTest::InitializeVM();
    1659           8 :   v8::HandleScope scope(CcTest::isolate());
    1660             : 
    1661             :   struct TestConfig {
    1662             :     Handle<AccessorPair> pair_;
    1663           4 :     TestConfig() { pair_ = CreateAccessorPair(true, true); }
    1664             : 
    1665           8 :     Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
    1666             :                                     Handle<Map> map) {
    1667           8 :       CHECK(branch_id == 1 || branch_id == 2);
    1668             :       // Add the same accessor constant property at both transition tree
    1669             :       // branches.
    1670           8 :       return expectations.AddAccessorConstant(map, NONE, pair_);
    1671             :     }
    1672             : 
    1673             :     void UpdateExpectations(int property_index, Expectations& expectations) {
    1674             :       // Two branches are "compatible" so the |map1| should NOT be deprecated.
    1675             :     }
    1676             :   };
    1677             : 
    1678             :   TestConfig config;
    1679             :   CheckSameMap checker;
    1680           4 :   TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1681           4 : }
    1682             : 
    1683             : 
    1684       26643 : TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
    1685           4 :   CcTest::InitializeVM();
    1686           8 :   v8::HandleScope scope(CcTest::isolate());
    1687             : 
    1688             :   struct TestConfig {
    1689             :     Handle<AccessorPair> pair1_;
    1690             :     Handle<AccessorPair> pair2_;
    1691           4 :     TestConfig() {
    1692           4 :       pair1_ = CreateAccessorPair(true, true);
    1693           4 :       pair2_ = CreateAccessorPair(true, true);
    1694           4 :     }
    1695             : 
    1696           8 :     Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
    1697             :                                     Handle<Map> map) {
    1698           8 :       CHECK(branch_id == 1 || branch_id == 2);
    1699           8 :       Handle<AccessorPair> pair = branch_id == 1 ? pair1_ : pair2_;
    1700           8 :       return expectations.AddAccessorConstant(map, NONE, pair);
    1701             :     }
    1702             : 
    1703             :     void UpdateExpectations(int property_index, Expectations& expectations) {
    1704             :       if (IS_ACCESSOR_FIELD_SUPPORTED) {
    1705             :         expectations.SetAccessorField(property_index);
    1706             :       } else {
    1707             :         // Currently we have a copy-generalize-all-representations case and
    1708             :         // ACCESSOR property becomes ACCESSOR_CONSTANT.
    1709           4 :         expectations.SetAccessorConstant(property_index, pair2_);
    1710             :       }
    1711             :     }
    1712             :   };
    1713             : 
    1714           4 :   TestConfig config;
    1715             :   if (IS_ACCESSOR_FIELD_SUPPORTED) {
    1716             :     CheckCopyGeneralizeAllFields checker;
    1717             :     TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1718             :   } else {
    1719             :     // Currently we have a copy-generalize-all-representations case.
    1720             :     CheckCopyGeneralizeAllFields checker;
    1721           4 :     TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1722             :   }
    1723           4 : }
    1724             : 
    1725             : 
    1726       26643 : TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {
    1727           4 :   CcTest::InitializeVM();
    1728           8 :   v8::HandleScope scope(CcTest::isolate());
    1729             : 
    1730             :   struct TestConfig {
    1731             :     Handle<AccessorPair> pair_;
    1732           4 :     TestConfig() { pair_ = CreateAccessorPair(true, true); }
    1733             : 
    1734           8 :     Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
    1735             :                                     Handle<Map> map) {
    1736           8 :       CHECK(branch_id == 1 || branch_id == 2);
    1737           8 :       if (branch_id == 1) {
    1738           4 :         return expectations.AddAccessorConstant(map, NONE, pair_);
    1739             :       } else {
    1740             :         Isolate* isolate = CcTest::i_isolate();
    1741           4 :         Handle<FieldType> any_type = FieldType::Any(isolate);
    1742             :         return expectations.AddDataField(map, NONE, kDefaultFieldConstness,
    1743           4 :                                          Representation::Smi(), any_type);
    1744             :       }
    1745             :     }
    1746             : 
    1747             :     void UpdateExpectations(int property_index, Expectations& expectations) {}
    1748             :   };
    1749             : 
    1750             :   TestConfig config;
    1751             :   // These are completely separate branches in transition tree.
    1752             :   CheckUnrelated checker;
    1753           4 :   TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
    1754           4 : }
    1755             : 
    1756             : 
    1757             : ////////////////////////////////////////////////////////////////////////////////
    1758             : // A set of tests for elements kind reconfiguration case.
    1759             : //
    1760             : 
    1761             : namespace {
    1762             : 
    1763             : // This test ensures that field generalization is correctly propagated from one
    1764             : // branch of transition tree (|map2) to another (|map|).
    1765             : //
    1766             : //   + - p0 - p1 - p2A - p3 - p4: |map|
    1767             : //   |
    1768             : //  ek
    1769             : //   |
    1770             : //  {} - p0 - p1 - p2B - p3 - p4: |map2|
    1771             : //
    1772             : // where "p2A" and "p2B" differ only in the representation/field type.
    1773             : //
    1774          64 : static void TestReconfigureElementsKind_GeneralizeField(
    1775             :     const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
    1776             :   Isolate* isolate = CcTest::i_isolate();
    1777             : 
    1778             :   Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
    1779             : 
    1780             :   // Create a map, add required properties to it and initialize expectations.
    1781          64 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    1782             :   initial_map->set_instance_type(JS_ARRAY_TYPE);
    1783          64 :   initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
    1784             : 
    1785             :   Handle<Map> map = initial_map;
    1786          64 :   map = expectations.AsElementsKind(map, PACKED_ELEMENTS);
    1787         960 :   for (int i = 0; i < kPropCount; i++) {
    1788         448 :     map = expectations.AddDataField(map, NONE, from.constness,
    1789         448 :                                     from.representation, from.type);
    1790             :   }
    1791          64 :   CHECK(!map->is_deprecated());
    1792          64 :   CHECK(map->is_stable());
    1793          64 :   CHECK(expectations.Check(*map));
    1794             : 
    1795             :   // Create another branch in transition tree (property at index |kDiffProp|
    1796             :   // has different representatio/field type), initialize expectations.
    1797             :   const int kDiffProp = kPropCount / 2;
    1798             :   Expectations expectations2(isolate, PACKED_SMI_ELEMENTS);
    1799             : 
    1800             :   Handle<Map> map2 = initial_map;
    1801         960 :   for (int i = 0; i < kPropCount; i++) {
    1802         448 :     if (i == kDiffProp) {
    1803          64 :       map2 = expectations2.AddDataField(map2, NONE, to.constness,
    1804          64 :                                         to.representation, to.type);
    1805             :     } else {
    1806         384 :       map2 = expectations2.AddDataField(map2, NONE, from.constness,
    1807         384 :                                         from.representation, from.type);
    1808             :     }
    1809             :   }
    1810          64 :   CHECK(!map2->is_deprecated());
    1811          64 :   CHECK(map2->is_stable());
    1812          64 :   CHECK(expectations2.Check(*map2));
    1813             : 
    1814             :   // Create dummy optimized code object to test correct dependencies
    1815             :   // on the field owner.
    1816          64 :   Handle<Code> code = CreateDummyOptimizedCode(isolate);
    1817         128 :   Handle<Map> field_owner(map->FindFieldOwner(isolate, kDiffProp), isolate);
    1818         128 :   DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
    1819             :                                    field_owner,
    1820          64 :                                    DependentCode::kFieldOwnerGroup);
    1821          64 :   CHECK(!code->marked_for_deoptimization());
    1822             : 
    1823             :   // Reconfigure elements kinds of |map2|, which should generalize
    1824             :   // representations in |map|.
    1825             :   Handle<Map> new_map =
    1826          64 :       Map::ReconfigureElementsKind(isolate, map2, PACKED_ELEMENTS);
    1827             : 
    1828             :   // |map2| should be left unchanged but marked unstable.
    1829          64 :   CHECK(!map2->is_stable());
    1830          64 :   CHECK(!map2->is_deprecated());
    1831          64 :   CHECK_NE(*map2, *new_map);
    1832          64 :   CHECK(expectations2.Check(*map2));
    1833             : 
    1834             :   // |map| should be deprecated and |new_map| should match new expectations.
    1835          64 :   expectations.SetDataField(kDiffProp, expected.constness,
    1836             :                             expected.representation, expected.type);
    1837             : 
    1838          64 :   CHECK(map->is_deprecated());
    1839          64 :   CHECK(!code->marked_for_deoptimization());
    1840          64 :   CHECK_NE(*map, *new_map);
    1841             : 
    1842          64 :   CHECK(!new_map->is_deprecated());
    1843          64 :   CHECK(expectations.Check(*new_map));
    1844             : 
    1845             :   // Update deprecated |map|, it should become |new_map|.
    1846          64 :   Handle<Map> updated_map = Map::Update(isolate, map);
    1847          64 :   CHECK_EQ(*new_map, *updated_map);
    1848          64 :   CheckMigrationTarget(isolate, *map, *updated_map);
    1849             : 
    1850             :   // Ensure Map::FindElementsKindTransitionedMap() is able to find the
    1851             :   // transitioned map.
    1852             :   {
    1853             :     MapHandles map_list;
    1854          64 :     map_list.push_back(updated_map);
    1855             :     Map transitioned_map =
    1856          64 :         map2->FindElementsKindTransitionedMap(isolate, map_list);
    1857          64 :     CHECK_EQ(*updated_map, transitioned_map);
    1858             :   }
    1859          64 : }
    1860             : 
    1861             : // This test ensures that trivial field generalization (from HeapObject to
    1862             : // HeapObject) is correctly propagated from one branch of transition tree
    1863             : // (|map2|) to another (|map|).
    1864             : //
    1865             : //   + - p0 - p1 - p2A - p3 - p4: |map|
    1866             : //   |
    1867             : //  ek
    1868             : //   |
    1869             : //  {} - p0 - p1 - p2B - p3 - p4: |map2|
    1870             : //
    1871             : // where "p2A" and "p2B" differ only in the representation/field type.
    1872             : //
    1873          32 : static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
    1874             :     const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
    1875             :   Isolate* isolate = CcTest::i_isolate();
    1876             : 
    1877             :   Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
    1878             : 
    1879             :   // Create a map, add required properties to it and initialize expectations.
    1880          32 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    1881             :   initial_map->set_instance_type(JS_ARRAY_TYPE);
    1882          32 :   initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
    1883             : 
    1884             :   Handle<Map> map = initial_map;
    1885          32 :   map = expectations.AsElementsKind(map, PACKED_ELEMENTS);
    1886         480 :   for (int i = 0; i < kPropCount; i++) {
    1887         224 :     map = expectations.AddDataField(map, NONE, from.constness,
    1888         224 :                                     from.representation, from.type);
    1889             :   }
    1890          32 :   CHECK(!map->is_deprecated());
    1891          32 :   CHECK(map->is_stable());
    1892          32 :   CHECK(expectations.Check(*map));
    1893             : 
    1894             :   // Create another branch in transition tree (property at index |kDiffProp|
    1895             :   // has different attributes), initialize expectations.
    1896             :   const int kDiffProp = kPropCount / 2;
    1897             :   Expectations expectations2(isolate, PACKED_SMI_ELEMENTS);
    1898             : 
    1899             :   Handle<Map> map2 = initial_map;
    1900         480 :   for (int i = 0; i < kPropCount; i++) {
    1901         224 :     if (i == kDiffProp) {
    1902          32 :       map2 = expectations2.AddDataField(map2, NONE, to.constness,
    1903          32 :                                         to.representation, to.type);
    1904             :     } else {
    1905         192 :       map2 = expectations2.AddDataField(map2, NONE, from.constness,
    1906         192 :                                         from.representation, from.type);
    1907             :     }
    1908             :   }
    1909          32 :   CHECK(!map2->is_deprecated());
    1910          32 :   CHECK(map2->is_stable());
    1911          32 :   CHECK(expectations2.Check(*map2));
    1912             : 
    1913             :   // Create dummy optimized code object to test correct dependencies
    1914             :   // on the field owner.
    1915          32 :   Handle<Code> code = CreateDummyOptimizedCode(isolate);
    1916          64 :   Handle<Map> field_owner(map->FindFieldOwner(isolate, kDiffProp), isolate);
    1917          64 :   DependentCode::InstallDependency(isolate, MaybeObjectHandle::Weak(code),
    1918             :                                    field_owner,
    1919          32 :                                    DependentCode::kFieldOwnerGroup);
    1920          32 :   CHECK(!code->marked_for_deoptimization());
    1921             : 
    1922             :   // Reconfigure elements kinds of |map2|, which should generalize
    1923             :   // representations in |map|.
    1924             :   Handle<Map> new_map =
    1925          32 :       Map::ReconfigureElementsKind(isolate, map2, PACKED_ELEMENTS);
    1926             : 
    1927             :   // |map2| should be left unchanged but marked unstable.
    1928          32 :   CHECK(!map2->is_stable());
    1929          32 :   CHECK(!map2->is_deprecated());
    1930          32 :   CHECK_NE(*map2, *new_map);
    1931          32 :   CHECK(expectations2.Check(*map2));
    1932             : 
    1933             :   // In trivial case |map| should be returned as a result of the elements
    1934             :   // kind reconfiguration, respective field types should be generalized and
    1935             :   // respective code dependencies should be invalidated. |map| should be NOT
    1936             :   // deprecated and it should match new expectations.
    1937          32 :   expectations.SetDataField(kDiffProp, expected.constness,
    1938             :                             expected.representation, expected.type);
    1939          32 :   CHECK(!map->is_deprecated());
    1940          32 :   CHECK_EQ(*map, *new_map);
    1941          64 :   CHECK_EQ(IsGeneralizableTo(to.constness, from.constness),
    1942             :            !code->marked_for_deoptimization());
    1943             : 
    1944          32 :   CHECK(!new_map->is_deprecated());
    1945          32 :   CHECK(expectations.Check(*new_map));
    1946             : 
    1947          32 :   Handle<Map> updated_map = Map::Update(isolate, map);
    1948          32 :   CHECK_EQ(*new_map, *updated_map);
    1949             : 
    1950             :   // Ensure Map::FindElementsKindTransitionedMap() is able to find the
    1951             :   // transitioned map.
    1952             :   {
    1953             :     MapHandles map_list;
    1954          32 :     map_list.push_back(updated_map);
    1955             :     Map transitioned_map =
    1956          32 :         map2->FindElementsKindTransitionedMap(isolate, map_list);
    1957          32 :     CHECK_EQ(*updated_map, transitioned_map);
    1958             :   }
    1959          32 : }
    1960             : 
    1961             : }  // namespace
    1962             : 
    1963       26643 : TEST(ReconfigureElementsKind_GeneralizeSmiFieldToDouble) {
    1964           4 :   CcTest::InitializeVM();
    1965           8 :   v8::HandleScope scope(CcTest::isolate());
    1966             :   Isolate* isolate = CcTest::i_isolate();
    1967             : 
    1968           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1969             : 
    1970             :   if (FLAG_track_constant_fields) {
    1971           8 :     TestReconfigureElementsKind_GeneralizeField(
    1972             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    1973             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    1974           4 :         {PropertyConstness::kConst, Representation::Double(), any_type});
    1975             : 
    1976           8 :     TestReconfigureElementsKind_GeneralizeField(
    1977             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    1978             :         {PropertyConstness::kMutable, Representation::Double(), any_type},
    1979           4 :         {PropertyConstness::kMutable, Representation::Double(), any_type});
    1980             : 
    1981           8 :     TestReconfigureElementsKind_GeneralizeField(
    1982             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1983             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    1984           4 :         {PropertyConstness::kMutable, Representation::Double(), any_type});
    1985             :   }
    1986           8 :   TestReconfigureElementsKind_GeneralizeField(
    1987             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
    1988             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
    1989           4 :       {PropertyConstness::kMutable, Representation::Double(), any_type});
    1990           4 : }
    1991             : 
    1992       26643 : TEST(ReconfigureElementsKind_GeneralizeSmiFieldToTagged) {
    1993           4 :   CcTest::InitializeVM();
    1994           8 :   v8::HandleScope scope(CcTest::isolate());
    1995             :   Isolate* isolate = CcTest::i_isolate();
    1996             : 
    1997           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1998             :   Handle<FieldType> value_type =
    1999           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2000             : 
    2001             :   if (FLAG_track_constant_fields) {
    2002           8 :     TestReconfigureElementsKind_GeneralizeField(
    2003             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    2004             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    2005           4 :         {PropertyConstness::kConst, Representation::Tagged(), any_type});
    2006             : 
    2007           8 :     TestReconfigureElementsKind_GeneralizeField(
    2008             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    2009             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2010           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2011             : 
    2012           8 :     TestReconfigureElementsKind_GeneralizeField(
    2013             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2014             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    2015           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2016             :   }
    2017           8 :   TestReconfigureElementsKind_GeneralizeField(
    2018             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2019             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2020           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2021           4 : }
    2022             : 
    2023       26643 : TEST(ReconfigureElementsKind_GeneralizeDoubleFieldToTagged) {
    2024           4 :   CcTest::InitializeVM();
    2025           8 :   v8::HandleScope scope(CcTest::isolate());
    2026             :   Isolate* isolate = CcTest::i_isolate();
    2027             : 
    2028           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2029             :   Handle<FieldType> value_type =
    2030           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2031             : 
    2032             :   if (FLAG_track_constant_fields) {
    2033           8 :     TestReconfigureElementsKind_GeneralizeField(
    2034             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    2035             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    2036           4 :         {PropertyConstness::kConst, Representation::Tagged(), any_type});
    2037             : 
    2038           8 :     TestReconfigureElementsKind_GeneralizeField(
    2039             :         {PropertyConstness::kConst, Representation::Double(), any_type},
    2040             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2041           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2042             : 
    2043           8 :     TestReconfigureElementsKind_GeneralizeField(
    2044             :         {PropertyConstness::kMutable, Representation::Double(), any_type},
    2045             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    2046           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2047             :   }
    2048           8 :   TestReconfigureElementsKind_GeneralizeField(
    2049             :       {PropertyConstness::kMutable, Representation::Double(), any_type},
    2050             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2051           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2052           4 : }
    2053             : 
    2054       26643 : TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
    2055           4 :   CcTest::InitializeVM();
    2056           8 :   v8::HandleScope scope(CcTest::isolate());
    2057             :   Isolate* isolate = CcTest::i_isolate();
    2058             : 
    2059           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2060             : 
    2061             :   Handle<FieldType> current_type =
    2062           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2063             : 
    2064             :   Handle<FieldType> new_type =
    2065           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2066             : 
    2067           4 :   Handle<FieldType> expected_type = any_type;
    2068             : 
    2069             :   // Check generalizations that trigger deopts.
    2070             :   if (FLAG_track_constant_fields) {
    2071           8 :     TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2072             :         {PropertyConstness::kConst, Representation::HeapObject(), current_type},
    2073             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    2074             :         {PropertyConstness::kConst, Representation::HeapObject(),
    2075           4 :          expected_type});
    2076             :       // PropertyConstness::kConst to PropertyConstness::kMutable migration does
    2077             :       // not create a new map, therefore trivial generalization.
    2078           8 :       TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2079             :           {PropertyConstness::kConst, Representation::HeapObject(),
    2080             :            current_type},
    2081             :           {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    2082             :           {PropertyConstness::kMutable, Representation::HeapObject(),
    2083           4 :            expected_type});
    2084             : 
    2085           8 :     TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2086             :         {PropertyConstness::kMutable, Representation::HeapObject(),
    2087             :          current_type},
    2088             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    2089             :         {PropertyConstness::kMutable, Representation::HeapObject(),
    2090           4 :          expected_type});
    2091             :   }
    2092           8 :   TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2093             :       {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
    2094             :       {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    2095             :       {PropertyConstness::kMutable, Representation::HeapObject(),
    2096           4 :        expected_type});
    2097             :   current_type = expected_type;
    2098             : 
    2099             :   // Check generalizations that do not trigger deopts.
    2100           4 :   new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
    2101             : 
    2102             :   if (FLAG_track_constant_fields) {
    2103           8 :     TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2104             :         {PropertyConstness::kConst, Representation::HeapObject(), any_type},
    2105             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    2106           4 :         {PropertyConstness::kConst, Representation::HeapObject(), any_type});
    2107             : 
    2108             :       // PropertyConstness::kConst to PropertyConstness::kMutable migration does
    2109             :       // not create a new map, therefore trivial generalization.
    2110           8 :       TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2111             :           {PropertyConstness::kConst, Representation::HeapObject(), any_type},
    2112             :           {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    2113             :           {PropertyConstness::kMutable, Representation::HeapObject(),
    2114           4 :            any_type});
    2115             : 
    2116           8 :     TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2117             :         {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
    2118             :         {PropertyConstness::kConst, Representation::HeapObject(), new_type},
    2119           4 :         {PropertyConstness::kMutable, Representation::HeapObject(), any_type});
    2120             :   }
    2121           8 :   TestReconfigureElementsKind_GeneralizeFieldTrivial(
    2122             :       {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
    2123             :       {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
    2124           4 :       {PropertyConstness::kMutable, Representation::HeapObject(), any_type});
    2125           4 : }
    2126             : 
    2127       26643 : TEST(ReconfigureElementsKind_GeneralizeHeapObjectFieldToTagged) {
    2128           4 :   CcTest::InitializeVM();
    2129           8 :   v8::HandleScope scope(CcTest::isolate());
    2130             :   Isolate* isolate = CcTest::i_isolate();
    2131             : 
    2132           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2133             :   Handle<FieldType> value_type =
    2134           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2135             : 
    2136             :   if (FLAG_track_constant_fields) {
    2137           8 :     TestReconfigureElementsKind_GeneralizeField(
    2138             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    2139             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    2140           4 :         {PropertyConstness::kConst, Representation::Tagged(), any_type});
    2141             : 
    2142           8 :     TestReconfigureElementsKind_GeneralizeField(
    2143             :         {PropertyConstness::kConst, Representation::HeapObject(), value_type},
    2144             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2145           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2146             : 
    2147           8 :     TestReconfigureElementsKind_GeneralizeField(
    2148             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2149             :         {PropertyConstness::kConst, Representation::Smi(), any_type},
    2150           4 :         {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2151             :   }
    2152           8 :   TestReconfigureElementsKind_GeneralizeField(
    2153             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2154             :       {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2155           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type});
    2156           4 : }
    2157             : 
    2158             : ////////////////////////////////////////////////////////////////////////////////
    2159             : // A set of tests checking split map deprecation.
    2160             : //
    2161             : 
    2162       26643 : TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
    2163           4 :   CcTest::InitializeVM();
    2164           8 :   v8::HandleScope scope(CcTest::isolate());
    2165             :   Isolate* isolate = CcTest::i_isolate();
    2166             : 
    2167           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2168             : 
    2169           4 :   Expectations expectations(isolate);
    2170             : 
    2171             :   // Create a map, add required properties to it and initialize expectations.
    2172           4 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    2173           4 :   Handle<Map> map = initial_map;
    2174          60 :   for (int i = 0; i < kPropCount; i++) {
    2175             :     map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
    2176          28 :                                     Representation::Smi(), any_type);
    2177             :   }
    2178           4 :   CHECK(!map->is_deprecated());
    2179           4 :   CHECK(map->is_stable());
    2180             : 
    2181             :   // Generalize representation of property at index |kSplitProp|.
    2182             :   const int kSplitProp = kPropCount / 2;
    2183             :   Handle<Map> split_map;
    2184             :   Handle<Map> map2 = initial_map;
    2185             :   {
    2186          36 :     for (int i = 0; i < kSplitProp + 1; i++) {
    2187          16 :       if (i == kSplitProp) {
    2188             :         split_map = map2;
    2189             :       }
    2190             : 
    2191          16 :       Handle<String> name = MakeName("prop", i);
    2192             :       Map target = TransitionsAccessor(isolate, map2)
    2193          32 :                        .SearchTransition(*name, kData, NONE);
    2194          16 :       CHECK(!target.is_null());
    2195             :       map2 = handle(target, isolate);
    2196             :     }
    2197             : 
    2198             :     map2 = Map::ReconfigureProperty(isolate, map2, kSplitProp, kData, NONE,
    2199           4 :                                     Representation::Double(), any_type);
    2200             :     expectations.SetDataField(kSplitProp, PropertyConstness::kMutable,
    2201             :                               Representation::Double(), any_type);
    2202             : 
    2203           4 :     CHECK(expectations.Check(*split_map, kSplitProp));
    2204           4 :     CHECK(expectations.Check(*map2, kSplitProp + 1));
    2205             :   }
    2206             : 
    2207             :   // At this point |map| should be deprecated and disconnected from the
    2208             :   // transition tree.
    2209           4 :   CHECK(map->is_deprecated());
    2210           4 :   CHECK(!split_map->is_deprecated());
    2211           4 :   CHECK(map2->is_stable());
    2212           4 :   CHECK(!map2->is_deprecated());
    2213             : 
    2214             :   // Fill in transition tree of |map2| so that it can't have more transitions.
    2215       12292 :   for (int i = 0; i < TransitionsAccessor::kMaxNumberOfTransitions; i++) {
    2216        6144 :     CHECK(TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
    2217        6144 :     Handle<String> name = MakeName("foo", i);
    2218       12288 :     Map::CopyWithField(isolate, map2, name, any_type, NONE,
    2219             :                        PropertyConstness::kMutable, Representation::Smi(),
    2220        6144 :                        INSERT_TRANSITION)
    2221             :         .ToHandleChecked();
    2222             :   }
    2223           4 :   CHECK(!TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
    2224             : 
    2225             :   // Try to update |map|, since there is no place for propX transition at |map2|
    2226             :   // |map| should become "copy-generalized".
    2227           4 :   Handle<Map> updated_map = Map::Update(isolate, map);
    2228           8 :   CHECK(updated_map->GetBackPointer()->IsUndefined(isolate));
    2229             : 
    2230          60 :   for (int i = 0; i < kPropCount; i++) {
    2231             :     expectations.SetDataField(i, PropertyConstness::kMutable,
    2232             :                               Representation::Tagged(), any_type);
    2233             :   }
    2234           4 :   CHECK(expectations.Check(*updated_map));
    2235           4 : }
    2236             : 
    2237             : 
    2238             : ////////////////////////////////////////////////////////////////////////////////
    2239             : // A set of tests involving special transitions (such as elements kind
    2240             : // transition, observed transition or prototype transition).
    2241             : //
    2242             : 
    2243             : // This test ensures that field generalization is correctly propagated from one
    2244             : // branch of transition tree (|map2|) to another (|map|).
    2245             : //
    2246             : //                            p4B: |map2|
    2247             : //                             |
    2248             : //                             * - special transition
    2249             : //                             |
    2250             : //  {} - p0 - p1 - p2A - p3 - p4A: |map|
    2251             : //
    2252             : // where "p4A" and "p4B" are exactly the same properties.
    2253             : //
    2254             : // TODO(ishell): unify this test template with
    2255             : // TestReconfigureDataFieldAttribute_GeneralizeField once
    2256             : // IS_PROTO_TRANS_ISSUE_FIXED and IS_NON_EQUIVALENT_TRANSITION_SUPPORTED are
    2257             : // fixed.
    2258             : template <typename TestConfig>
    2259          64 : static void TestGeneralizeFieldWithSpecialTransition(
    2260             :     TestConfig& config, const CRFTData& from, const CRFTData& to,
    2261             :     const CRFTData& expected, bool expected_deprecation) {
    2262             :   Isolate* isolate = CcTest::i_isolate();
    2263             : 
    2264          64 :   Expectations expectations(isolate);
    2265             : 
    2266             :   // Create a map, add required properties to it and initialize expectations.
    2267          64 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    2268          64 :   Handle<Map> map = initial_map;
    2269         960 :   for (int i = 0; i < kPropCount; i++) {
    2270         448 :     map = expectations.AddDataField(map, NONE, from.constness,
    2271             :                                     from.representation, from.type);
    2272             :   }
    2273          64 :   CHECK(!map->is_deprecated());
    2274          64 :   CHECK(map->is_stable());
    2275          64 :   CHECK(expectations.Check(*map));
    2276             : 
    2277          64 :   Expectations expectations2 = expectations;
    2278             : 
    2279             :   // Apply some special transition to |map|.
    2280          64 :   CHECK(map->owns_descriptors());
    2281          64 :   Handle<Map> map2 = config.Transition(map, expectations2);
    2282             : 
    2283             :   // |map| should still match expectations.
    2284          64 :   CHECK(!map->is_deprecated());
    2285          64 :   CHECK(expectations.Check(*map));
    2286             : 
    2287             :   if (config.generalizes_representations()) {
    2288         240 :     for (int i = 0; i < kPropCount; i++) {
    2289         112 :       expectations2.GeneralizeField(i);
    2290             :     }
    2291             :   }
    2292             : 
    2293          64 :   CHECK(!map2->is_deprecated());
    2294          64 :   CHECK(map2->is_stable());
    2295          64 :   CHECK(expectations2.Check(*map2));
    2296             : 
    2297             :   // Create new maps by generalizing representation of propX field.
    2298         960 :   Handle<Map> maps[kPropCount];
    2299         960 :   for (int i = 0; i < kPropCount; i++) {
    2300             :     Handle<Map> new_map = Map::ReconfigureProperty(isolate, map, i, kData, NONE,
    2301         448 :                                                    to.representation, to.type);
    2302         448 :     maps[i] = new_map;
    2303             : 
    2304         448 :     expectations.SetDataField(i, expected.constness, expected.representation,
    2305             :                               expected.type);
    2306             : 
    2307         448 :     if (expected_deprecation) {
    2308         224 :       CHECK(map->is_deprecated());
    2309         224 :       CHECK_NE(*map, *new_map);
    2310         416 :       CHECK(i == 0 || maps[i - 1]->is_deprecated());
    2311         224 :       CHECK(expectations.Check(*new_map));
    2312             : 
    2313         224 :       Handle<Map> new_map2 = Map::Update(isolate, map2);
    2314         224 :       CHECK(!new_map2->is_deprecated());
    2315         224 :       CHECK(!new_map2->is_dictionary_map());
    2316             : 
    2317             :       Handle<Map> tmp_map;
    2318         448 :       if (Map::TryUpdate(isolate, map2).ToHandle(&tmp_map)) {
    2319             :         // If Map::TryUpdate() manages to succeed the result must match the
    2320             :         // result of Map::Update().
    2321         224 :         CHECK_EQ(*new_map2, *tmp_map);
    2322             :       } else {
    2323             :         // Equivalent transitions should always find the updated map.
    2324           0 :         CHECK(config.is_non_equivalent_transition());
    2325             :       }
    2326             : 
    2327             :       if (config.is_non_equivalent_transition()) {
    2328             :         // In case of non-equivalent transition currently we generalize all
    2329             :         // representations.
    2330         840 :         for (int i = 0; i < kPropCount; i++) {
    2331         392 :           expectations2.GeneralizeField(i);
    2332             :         }
    2333         112 :         CHECK(new_map2->GetBackPointer()->IsUndefined(isolate));
    2334          56 :         CHECK(expectations2.Check(*new_map2));
    2335             :       } else {
    2336         168 :         expectations2.SetDataField(i, expected.constness,
    2337             :                                    expected.representation, expected.type);
    2338             : 
    2339         336 :         CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate));
    2340         168 :         CHECK(expectations2.Check(*new_map2));
    2341             :       }
    2342             :     } else {
    2343         224 :       CHECK(!map->is_deprecated());
    2344             :       // TODO(ishell): Update test expectations properly.
    2345             :       // CHECK_EQ(*map2, *new_map);
    2346             :       // CHECK(expectations2.Check(*new_map));
    2347             :     }
    2348             :   }
    2349             : 
    2350          64 :   Handle<Map> active_map = maps[kPropCount - 1];
    2351          64 :   CHECK(!active_map->is_deprecated());
    2352             : 
    2353             :   // Update all deprecated maps and check that they are now the same.
    2354          64 :   Handle<Map> updated_map = Map::Update(isolate, map);
    2355          64 :   CHECK_EQ(*active_map, *updated_map);
    2356          64 :   CheckMigrationTarget(isolate, *map, *updated_map);
    2357         960 :   for (int i = 0; i < kPropCount; i++) {
    2358         448 :     updated_map = Map::Update(isolate, maps[i]);
    2359         448 :     CHECK_EQ(*active_map, *updated_map);
    2360         896 :     CheckMigrationTarget(isolate, *maps[i], *updated_map);
    2361             :   }
    2362          64 : }
    2363             : 
    2364       26643 : TEST(ElementsKindTransitionFromMapOwningDescriptor) {
    2365           4 :   CcTest::InitializeVM();
    2366           8 :   v8::HandleScope scope(CcTest::isolate());
    2367             :   Isolate* isolate = CcTest::i_isolate();
    2368             : 
    2369           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2370             :   Handle<FieldType> value_type =
    2371           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2372             : 
    2373             :   struct TestConfig {
    2374             :     TestConfig(PropertyAttributes attributes, Handle<Symbol> symbol)
    2375          12 :         : attributes(attributes), symbol(symbol) {}
    2376             : 
    2377          24 :     Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
    2378             :       expectations.SetElementsKind(DICTIONARY_ELEMENTS);
    2379          24 :       expectations.ChangeAttributesForAllProperties(attributes);
    2380             :       return Map::CopyForPreventExtensions(CcTest::i_isolate(), map, attributes,
    2381          48 :                                            symbol, "CopyForPreventExtensions");
    2382             :     }
    2383             :     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
    2384             :     bool generalizes_representations() const { return false; }
    2385             :     bool is_non_equivalent_transition() const { return false; }
    2386             : 
    2387             :     PropertyAttributes attributes;
    2388             :     Handle<Symbol> symbol;
    2389             :   };
    2390             :   Factory* factory = isolate->factory();
    2391             :   TestConfig configs[] = {{FROZEN, factory->frozen_symbol()},
    2392             :                           {SEALED, factory->sealed_symbol()},
    2393             :                           {NONE, factory->nonextensible_symbol()}};
    2394          28 :   for (size_t i = 0; i < arraysize(configs); i++) {
    2395          24 :     TestGeneralizeFieldWithSpecialTransition(
    2396             :         configs[i],
    2397             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2398             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2399             :         {PropertyConstness::kMutable, Representation::Tagged(), any_type},
    2400          24 :         !FLAG_modify_field_representation_inplace);
    2401          24 :     TestGeneralizeFieldWithSpecialTransition(
    2402             :         configs[i],
    2403             :         {PropertyConstness::kMutable, Representation::Double(), any_type},
    2404             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2405             :         {PropertyConstness::kMutable, Representation::Tagged(), any_type},
    2406          12 :         true);
    2407             :   }
    2408           4 : }
    2409             : 
    2410             : 
    2411       26643 : TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
    2412           4 :   CcTest::InitializeVM();
    2413           8 :   v8::HandleScope scope(CcTest::isolate());
    2414             :   Isolate* isolate = CcTest::i_isolate();
    2415             : 
    2416           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2417             :   Handle<FieldType> value_type =
    2418           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2419             : 
    2420             :   struct TestConfig {
    2421             :     TestConfig(PropertyAttributes attributes, Handle<Symbol> symbol)
    2422          12 :         : attributes(attributes), symbol(symbol) {}
    2423             : 
    2424          24 :     Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
    2425             :       Isolate* isolate = CcTest::i_isolate();
    2426          24 :       Handle<FieldType> any_type = FieldType::Any(isolate);
    2427             : 
    2428             :       // Add one more transition to |map| in order to prevent descriptors
    2429             :       // ownership.
    2430          24 :       CHECK(map->owns_descriptors());
    2431          48 :       Map::CopyWithField(isolate, map, MakeString("foo"), any_type, NONE,
    2432             :                          PropertyConstness::kMutable, Representation::Smi(),
    2433          24 :                          INSERT_TRANSITION)
    2434             :           .ToHandleChecked();
    2435          24 :       CHECK(!map->owns_descriptors());
    2436             : 
    2437             :       expectations.SetElementsKind(DICTIONARY_ELEMENTS);
    2438          24 :       expectations.ChangeAttributesForAllProperties(attributes);
    2439             :       return Map::CopyForPreventExtensions(isolate, map, attributes, symbol,
    2440          24 :                                            "CopyForPreventExtensions");
    2441             :     }
    2442             :     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
    2443             :     bool generalizes_representations() const { return false; }
    2444             :     bool is_non_equivalent_transition() const { return false; }
    2445             : 
    2446             :     PropertyAttributes attributes;
    2447             :     Handle<Symbol> symbol;
    2448             :   };
    2449             :   Factory* factory = isolate->factory();
    2450             :   TestConfig configs[] = {{FROZEN, factory->frozen_symbol()},
    2451             :                           {SEALED, factory->sealed_symbol()},
    2452             :                           {NONE, factory->nonextensible_symbol()}};
    2453          28 :   for (size_t i = 0; i < arraysize(configs); i++) {
    2454          24 :     TestGeneralizeFieldWithSpecialTransition(
    2455             :         configs[i],
    2456             :         {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2457             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2458             :         {PropertyConstness::kMutable, Representation::Tagged(), any_type},
    2459          24 :         !FLAG_modify_field_representation_inplace);
    2460          24 :     TestGeneralizeFieldWithSpecialTransition(
    2461             :         configs[i],
    2462             :         {PropertyConstness::kMutable, Representation::Double(), any_type},
    2463             :         {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2464             :         {PropertyConstness::kMutable, Representation::Tagged(), any_type},
    2465          12 :         true);
    2466             :   }
    2467           4 : }
    2468             : 
    2469             : 
    2470       26643 : TEST(PrototypeTransitionFromMapOwningDescriptor) {
    2471           4 :   CcTest::InitializeVM();
    2472           8 :   v8::HandleScope scope(CcTest::isolate());
    2473             :   Isolate* isolate = CcTest::i_isolate();
    2474             : 
    2475           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2476             :   Handle<FieldType> value_type =
    2477           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2478             : 
    2479             :   struct TestConfig {
    2480             :     Handle<JSObject> prototype_;
    2481             : 
    2482           4 :     TestConfig() {
    2483             :       Isolate* isolate = CcTest::i_isolate();
    2484             :       Factory* factory = isolate->factory();
    2485           4 :       prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
    2486           4 :     }
    2487             : 
    2488           8 :     Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
    2489           8 :       return Map::TransitionToPrototype(CcTest::i_isolate(), map, prototype_);
    2490             :     }
    2491             :     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
    2492             :     bool generalizes_representations() const {
    2493             :       return !IS_PROTO_TRANS_ISSUE_FIXED;
    2494             :     }
    2495             :     bool is_non_equivalent_transition() const { return true; }
    2496             :   };
    2497           4 :   TestConfig config;
    2498           8 :   TestGeneralizeFieldWithSpecialTransition(
    2499             :       config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2500             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2501             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type},
    2502           8 :       !FLAG_modify_field_representation_inplace);
    2503           8 :   TestGeneralizeFieldWithSpecialTransition(
    2504             :       config, {PropertyConstness::kMutable, Representation::Double(), any_type},
    2505             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2506           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type}, true);
    2507           4 : }
    2508             : 
    2509             : 
    2510       26643 : TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
    2511           4 :   CcTest::InitializeVM();
    2512           8 :   v8::HandleScope scope(CcTest::isolate());
    2513             :   Isolate* isolate = CcTest::i_isolate();
    2514             : 
    2515           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2516             :   Handle<FieldType> value_type =
    2517           4 :       FieldType::Class(Map::Create(isolate, 0), isolate);
    2518             : 
    2519             :   struct TestConfig {
    2520             :     Handle<JSObject> prototype_;
    2521             : 
    2522           4 :     TestConfig() {
    2523             :       Isolate* isolate = CcTest::i_isolate();
    2524             :       Factory* factory = isolate->factory();
    2525           4 :       prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
    2526           4 :     }
    2527             : 
    2528           8 :     Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
    2529             :       Isolate* isolate = CcTest::i_isolate();
    2530           8 :       Handle<FieldType> any_type = FieldType::Any(isolate);
    2531             : 
    2532             :       // Add one more transition to |map| in order to prevent descriptors
    2533             :       // ownership.
    2534           8 :       CHECK(map->owns_descriptors());
    2535          16 :       Map::CopyWithField(isolate, map, MakeString("foo"), any_type, NONE,
    2536             :                          PropertyConstness::kMutable, Representation::Smi(),
    2537           8 :                          INSERT_TRANSITION)
    2538             :           .ToHandleChecked();
    2539           8 :       CHECK(!map->owns_descriptors());
    2540             : 
    2541           8 :       return Map::TransitionToPrototype(isolate, map, prototype_);
    2542             :     }
    2543             :     // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
    2544             :     bool generalizes_representations() const {
    2545             :       return !IS_PROTO_TRANS_ISSUE_FIXED;
    2546             :     }
    2547             :     bool is_non_equivalent_transition() const { return true; }
    2548             :   };
    2549           4 :   TestConfig config;
    2550           8 :   TestGeneralizeFieldWithSpecialTransition(
    2551             :       config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
    2552             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2553             :       {PropertyConstness::kMutable, Representation::Tagged(), any_type},
    2554           8 :       !FLAG_modify_field_representation_inplace);
    2555           8 :   TestGeneralizeFieldWithSpecialTransition(
    2556             :       config, {PropertyConstness::kMutable, Representation::Double(), any_type},
    2557             :       {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
    2558           4 :       {PropertyConstness::kMutable, Representation::Tagged(), any_type}, true);
    2559           4 : }
    2560             : 
    2561             : 
    2562             : ////////////////////////////////////////////////////////////////////////////////
    2563             : // A set of tests for higher level transitioning mechanics.
    2564             : //
    2565             : 
    2566             : struct TransitionToDataFieldOperator {
    2567             :   PropertyConstness constness_;
    2568             :   Representation representation_;
    2569             :   PropertyAttributes attributes_;
    2570             :   Handle<FieldType> heap_type_;
    2571             :   Handle<Object> value_;
    2572             : 
    2573             :   TransitionToDataFieldOperator(PropertyConstness constness,
    2574             :                                 Representation representation,
    2575             :                                 Handle<FieldType> heap_type,
    2576             :                                 Handle<Object> value,
    2577             :                                 PropertyAttributes attributes = NONE)
    2578             :       : constness_(constness),
    2579             :         representation_(representation),
    2580             :         attributes_(attributes),
    2581             :         heap_type_(heap_type),
    2582          12 :         value_(value) {}
    2583             : 
    2584             :   Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
    2585             :     return expectations.TransitionToDataField(
    2586          12 :         map, attributes_, constness_, representation_, heap_type_, value_);
    2587             :   }
    2588             : };
    2589             : 
    2590             : 
    2591             : struct TransitionToDataConstantOperator {
    2592             :   PropertyAttributes attributes_;
    2593             :   Handle<JSFunction> value_;
    2594             : 
    2595             :   TransitionToDataConstantOperator(Handle<JSFunction> value,
    2596             :                                    PropertyAttributes attributes = NONE)
    2597          16 :       : attributes_(attributes), value_(value) {}
    2598             : 
    2599             :   Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
    2600          20 :     return expectations.TransitionToDataConstant(map, attributes_, value_);
    2601             :   }
    2602             : };
    2603             : 
    2604             : 
    2605             : struct TransitionToAccessorConstantOperator {
    2606             :   PropertyAttributes attributes_;
    2607             :   Handle<AccessorPair> pair_;
    2608             : 
    2609             :   TransitionToAccessorConstantOperator(Handle<AccessorPair> pair,
    2610             :                                        PropertyAttributes attributes = NONE)
    2611           4 :       : attributes_(attributes), pair_(pair) {}
    2612             : 
    2613             :   Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
    2614           8 :     return expectations.TransitionToAccessorConstant(map, attributes_, pair_);
    2615             :   }
    2616             : };
    2617             : 
    2618             : 
    2619             : struct ReconfigureAsDataPropertyOperator {
    2620             :   int descriptor_;
    2621             :   Representation representation_;
    2622             :   PropertyAttributes attributes_;
    2623             :   Handle<FieldType> heap_type_;
    2624             : 
    2625             :   ReconfigureAsDataPropertyOperator(int descriptor,
    2626             :                                     Representation representation,
    2627             :                                     Handle<FieldType> heap_type,
    2628             :                                     PropertyAttributes attributes = NONE)
    2629             :       : descriptor_(descriptor),
    2630             :         representation_(representation),
    2631             :         attributes_(attributes),
    2632             :         heap_type_(heap_type) {}
    2633             : 
    2634             :   Handle<Map> DoTransition(Isolate* isolate, Expectations& expectations,
    2635             :                            Handle<Map> map) {
    2636             :     expectations.SetDataField(descriptor_, PropertyConstness::kMutable,
    2637             :                               representation_, heap_type_);
    2638             :     return Map::ReconfigureExistingProperty(isolate, map, descriptor_, kData,
    2639             :                                             attributes_);
    2640             :   }
    2641             : };
    2642             : 
    2643             : 
    2644             : struct ReconfigureAsAccessorPropertyOperator {
    2645             :   int descriptor_;
    2646             :   PropertyAttributes attributes_;
    2647             : 
    2648             :   ReconfigureAsAccessorPropertyOperator(int descriptor,
    2649             :                                         PropertyAttributes attributes = NONE)
    2650             :       : descriptor_(descriptor), attributes_(attributes) {}
    2651             : 
    2652             :   Handle<Map> DoTransition(Isolate* isolate, Expectations& expectations,
    2653             :                            Handle<Map> map) {
    2654             :     expectations.SetAccessorField(descriptor_);
    2655             :     return Map::ReconfigureExistingProperty(isolate, map, descriptor_,
    2656             :                                             kAccessor, attributes_);
    2657             :   }
    2658             : };
    2659             : 
    2660             : // Checks that field generalization happened.
    2661             : struct FieldGeneralizationChecker {
    2662             :   int descriptor_;
    2663             :   PropertyConstness constness_;
    2664             :   Representation representation_;
    2665             :   PropertyAttributes attributes_;
    2666             :   Handle<FieldType> heap_type_;
    2667             : 
    2668             :   FieldGeneralizationChecker(int descriptor, PropertyConstness constness,
    2669             :                              Representation representation,
    2670             :                              Handle<FieldType> heap_type,
    2671             :                              PropertyAttributes attributes = NONE)
    2672             :       : descriptor_(descriptor),
    2673             :         constness_(constness),
    2674             :         representation_(representation),
    2675             :         attributes_(attributes),
    2676           4 :         heap_type_(heap_type) {}
    2677             : 
    2678           4 :   void Check(Isolate* isolate, Expectations& expectations2, Handle<Map> map1,
    2679             :              Handle<Map> map2) {
    2680           4 :     CHECK(!map2->is_deprecated());
    2681             : 
    2682           4 :     CHECK(map1->is_deprecated());
    2683           4 :     CHECK_NE(*map1, *map2);
    2684           4 :     Handle<Map> updated_map = Map::Update(isolate, map1);
    2685           4 :     CHECK_EQ(*map2, *updated_map);
    2686           4 :     CheckMigrationTarget(isolate, *map1, *updated_map);
    2687             : 
    2688           4 :     expectations2.SetDataField(descriptor_, attributes_, constness_,
    2689             :                                representation_, heap_type_);
    2690           4 :     CHECK(expectations2.Check(*map2));
    2691           4 :   }
    2692             : };
    2693             : 
    2694             : 
    2695             : // Checks that existing transition was taken as is.
    2696             : struct SameMapChecker {
    2697          16 :   void Check(Isolate* isolate, Expectations& expectations, Handle<Map> map1,
    2698             :              Handle<Map> map2) {
    2699          16 :     CHECK(!map2->is_deprecated());
    2700          16 :     CHECK_EQ(*map1, *map2);
    2701          16 :     CHECK(expectations.Check(*map2));
    2702          16 :   }
    2703             : };
    2704             : 
    2705             : 
    2706             : // Checks that both |map1| and |map2| should stays non-deprecated, this is
    2707             : // the case when property kind is change.
    2708             : struct PropertyKindReconfigurationChecker {
    2709             :   void Check(Expectations& expectations, Handle<Map> map1, Handle<Map> map2) {
    2710             :     CHECK(!map1->is_deprecated());
    2711             :     CHECK(!map2->is_deprecated());
    2712             :     CHECK_NE(*map1, *map2);
    2713             :     CHECK(expectations.Check(*map2));
    2714             :   }
    2715             : };
    2716             : 
    2717             : 
    2718             : // This test transitions to various property types under different
    2719             : // circumstances.
    2720             : // Plan:
    2721             : // 1) create a |map| with p0..p3 properties.
    2722             : // 2) create |map1| by adding "p4" to |map0|.
    2723             : // 3) create |map2| by transition to "p4" from |map0|.
    2724             : //
    2725             : //                       + - p4B: |map2|
    2726             : //                       |
    2727             : //  {} - p0 - p1 - pA - p3: |map|
    2728             : //                       |
    2729             : //                       + - p4A: |map1|
    2730             : //
    2731             : // where "p4A" and "p4B" differ only in the attributes.
    2732             : //
    2733             : template <typename TransitionOp1, typename TransitionOp2, typename Checker>
    2734          20 : static void TestTransitionTo(TransitionOp1& transition_op1,
    2735             :                              TransitionOp2& transition_op2, Checker& checker) {
    2736             :   Isolate* isolate = CcTest::i_isolate();
    2737          20 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2738             : 
    2739          20 :   Expectations expectations(isolate);
    2740             : 
    2741             :   // Create a map, add required properties to it and initialize expectations.
    2742          20 :   Handle<Map> initial_map = Map::Create(isolate, 0);
    2743          20 :   Handle<Map> map = initial_map;
    2744         260 :   for (int i = 0; i < kPropCount - 1; i++) {
    2745         120 :     map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
    2746             :                                     Representation::Smi(), any_type);
    2747             :   }
    2748          20 :   CHECK(expectations.Check(*map));
    2749             : 
    2750          20 :   Expectations expectations1 = expectations;
    2751             :   Handle<Map> map1 = transition_op1.DoTransition(expectations1, map);
    2752          20 :   CHECK(expectations1.Check(*map1));
    2753             : 
    2754          20 :   Expectations expectations2 = expectations;
    2755          20 :   Handle<Map> map2 = transition_op2.DoTransition(expectations2, map);
    2756             : 
    2757             :   // Let the test customization do the check.
    2758          20 :   checker.Check(isolate, expectations2, map1, map2);
    2759          20 : }
    2760             : 
    2761             : 
    2762       26643 : TEST(TransitionDataFieldToDataField) {
    2763           4 :   CcTest::InitializeVM();
    2764           8 :   v8::HandleScope scope(CcTest::isolate());
    2765             :   Isolate* isolate = CcTest::i_isolate();
    2766             : 
    2767           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2768             : 
    2769             :   Handle<Object> value1 = handle(Smi::kZero, isolate);
    2770             :   TransitionToDataFieldOperator transition_op1(
    2771             :       PropertyConstness::kMutable, Representation::Smi(), any_type, value1);
    2772             : 
    2773           4 :   Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
    2774             :   TransitionToDataFieldOperator transition_op2(
    2775             :       PropertyConstness::kMutable, Representation::Double(), any_type, value2);
    2776             : 
    2777             :   FieldGeneralizationChecker checker(kPropCount - 1,
    2778             :                                      PropertyConstness::kMutable,
    2779             :                                      Representation::Double(), any_type);
    2780           4 :   TestTransitionTo(transition_op1, transition_op2, checker);
    2781           4 : }
    2782             : 
    2783       26643 : TEST(TransitionDataConstantToSameDataConstant) {
    2784           4 :   CcTest::InitializeVM();
    2785           8 :   v8::HandleScope scope(CcTest::isolate());
    2786             :   Isolate* isolate = CcTest::i_isolate();
    2787             :   Factory* factory = isolate->factory();
    2788             : 
    2789             :   Handle<JSFunction> js_func =
    2790           4 :       factory->NewFunctionForTest(factory->empty_string());
    2791             :   TransitionToDataConstantOperator transition_op(js_func);
    2792             : 
    2793             :   SameMapChecker checker;
    2794           4 :   TestTransitionTo(transition_op, transition_op, checker);
    2795           4 : }
    2796             : 
    2797             : 
    2798       26643 : TEST(TransitionDataConstantToAnotherDataConstant) {
    2799           4 :   CcTest::InitializeVM();
    2800           8 :   v8::HandleScope scope(CcTest::isolate());
    2801             :   Isolate* isolate = CcTest::i_isolate();
    2802             :   Factory* factory = isolate->factory();
    2803             : 
    2804             :   Handle<String> name = factory->empty_string();
    2805             :   Handle<Map> sloppy_map =
    2806           4 :       Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
    2807             :   Handle<SharedFunctionInfo> info =
    2808           4 :       factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
    2809           4 :   Handle<FieldType> function_type = FieldType::Class(sloppy_map, isolate);
    2810           4 :   CHECK(sloppy_map->is_stable());
    2811             : 
    2812             :   Handle<JSFunction> js_func1 =
    2813           8 :       factory->NewFunction(sloppy_map, info, isolate->native_context());
    2814             :   TransitionToDataConstantOperator transition_op1(js_func1);
    2815             : 
    2816             :   Handle<JSFunction> js_func2 =
    2817           8 :       factory->NewFunction(sloppy_map, info, isolate->native_context());
    2818             :   TransitionToDataConstantOperator transition_op2(js_func2);
    2819             : 
    2820             :   if (FLAG_track_constant_fields) {
    2821             :     SameMapChecker checker;
    2822           4 :     TestTransitionTo(transition_op1, transition_op2, checker);
    2823             : 
    2824             :   } else {
    2825             :     FieldGeneralizationChecker checker(
    2826             :         kPropCount - 1, PropertyConstness::kMutable,
    2827             :         Representation::HeapObject(), function_type);
    2828             :     TestTransitionTo(transition_op1, transition_op2, checker);
    2829             :   }
    2830           4 : }
    2831             : 
    2832             : 
    2833       26643 : TEST(TransitionDataConstantToDataField) {
    2834           4 :   CcTest::InitializeVM();
    2835           8 :   v8::HandleScope scope(CcTest::isolate());
    2836             :   Isolate* isolate = CcTest::i_isolate();
    2837             :   Factory* factory = isolate->factory();
    2838             : 
    2839           4 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    2840             : 
    2841             :   Handle<JSFunction> js_func1 =
    2842           4 :       factory->NewFunctionForTest(factory->empty_string());
    2843             :   TransitionToDataConstantOperator transition_op1(js_func1);
    2844             : 
    2845           4 :   Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
    2846             :   TransitionToDataFieldOperator transition_op2(
    2847             :       PropertyConstness::kMutable, Representation::Tagged(), any_type, value2);
    2848             : 
    2849           4 :   if (FLAG_track_constant_fields && FLAG_modify_field_representation_inplace) {
    2850             :     SameMapChecker checker;
    2851           4 :     TestTransitionTo(transition_op1, transition_op2, checker);
    2852             :   } else {
    2853             :     FieldGeneralizationChecker checker(kPropCount - 1,
    2854             :                                        PropertyConstness::kMutable,
    2855             :                                        Representation::Tagged(), any_type);
    2856           0 :     TestTransitionTo(transition_op1, transition_op2, checker);
    2857             :   }
    2858           4 : }
    2859             : 
    2860             : 
    2861       26643 : TEST(TransitionAccessorConstantToSameAccessorConstant) {
    2862           4 :   CcTest::InitializeVM();
    2863           8 :   v8::HandleScope scope(CcTest::isolate());
    2864             : 
    2865           4 :   Handle<AccessorPair> pair = CreateAccessorPair(true, true);
    2866             :   TransitionToAccessorConstantOperator transition_op(pair);
    2867             : 
    2868             :   SameMapChecker checker;
    2869           4 :   TestTransitionTo(transition_op, transition_op, checker);
    2870           4 : }
    2871             : 
    2872             : // TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported.
    2873             : // TEST(TransitionAccessorConstantToAnotherAccessorConstant)
    2874             : 
    2875       26643 : TEST(HoleyMutableHeapNumber) {
    2876           4 :   CcTest::InitializeVM();
    2877           8 :   v8::HandleScope scope(CcTest::isolate());
    2878             :   Isolate* isolate = CcTest::i_isolate();
    2879             : 
    2880             :   auto mhn = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
    2881           4 :   CHECK_EQ(kHoleNanInt64, mhn->value_as_bits());
    2882             : 
    2883           4 :   mhn = isolate->factory()->NewMutableHeapNumber(0.0);
    2884           4 :   CHECK_EQ(uint64_t{0}, mhn->value_as_bits());
    2885             : 
    2886             :   mhn->set_value_as_bits(kHoleNanInt64);
    2887           4 :   CHECK_EQ(kHoleNanInt64, mhn->value_as_bits());
    2888             : 
    2889             :   // Ensure that new storage for uninitialized value or mutable heap number
    2890             :   // with uninitialized sentinel (kHoleNanInt64) is a mutable heap number
    2891             :   // with uninitialized sentinel.
    2892             :   Handle<Object> obj =
    2893             :       Object::NewStorageFor(isolate, isolate->factory()->uninitialized_value(),
    2894           4 :                             Representation::Double());
    2895           4 :   CHECK(obj->IsMutableHeapNumber());
    2896           4 :   CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj)->value_as_bits());
    2897             : 
    2898           4 :   obj = Object::NewStorageFor(isolate, mhn, Representation::Double());
    2899           4 :   CHECK(obj->IsMutableHeapNumber());
    2900           4 :   CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj)->value_as_bits());
    2901           4 : }
    2902             : 
    2903             : namespace {
    2904             : 
    2905             : template <class... Args>
    2906             : MaybeHandle<Object> Call(Isolate* isolate, Handle<JSFunction> function,
    2907             :                          Args... args) {
    2908         240 :   Handle<Object> argv[] = {args...};
    2909         240 :   return Execution::Call(isolate, function,
    2910             :                          isolate->factory()->undefined_value(), sizeof...(args),
    2911         240 :                          argv);
    2912             : }
    2913             : 
    2914          64 : void TestStoreToConstantField(const char* store_func_source,
    2915             :                               Handle<Object> value1, Handle<Object> value2,
    2916             :                               Representation expected_rep,
    2917             :                               PropertyConstness expected_constness,
    2918             :                               int store_repetitions) {
    2919             :   Isolate* isolate = CcTest::i_isolate();
    2920             :   CompileRun(store_func_source);
    2921             : 
    2922          64 :   Handle<JSFunction> store_func = GetGlobal<JSFunction>("store");
    2923             : 
    2924             :   const PropertyConstness kExpectedInitialFieldConstness =
    2925             :       FLAG_track_constant_fields ? PropertyConstness::kConst
    2926             :                                  : PropertyConstness::kMutable;
    2927             : 
    2928          64 :   Handle<Map> initial_map = Map::Create(isolate, 4);
    2929             : 
    2930             :   // Store value1 to obj1 and check that it got property with expected
    2931             :   // representation and constness.
    2932          64 :   Handle<JSObject> obj1 = isolate->factory()->NewJSObjectFromMap(initial_map);
    2933         288 :   for (int i = 0; i < store_repetitions; i++) {
    2934             :     Call(isolate, store_func, obj1, value1).Check();
    2935             :   }
    2936             : 
    2937             :   Handle<Map> map(obj1->map(), isolate);
    2938          64 :   CHECK(!map->is_dictionary_map());
    2939          64 :   CHECK(!map->is_deprecated());
    2940          64 :   CHECK_EQ(1, map->NumberOfOwnDescriptors());
    2941             : 
    2942          64 :   CHECK(map->instance_descriptors()->GetDetails(0).representation().Equals(
    2943             :       expected_rep));
    2944          64 :   CHECK_EQ(kExpectedInitialFieldConstness,
    2945             :            map->instance_descriptors()->GetDetails(0).constness());
    2946             : 
    2947             :   // Store value2 to obj2 and check that it got same map and property details
    2948             :   // did not change.
    2949          64 :   Handle<JSObject> obj2 = isolate->factory()->NewJSObjectFromMap(initial_map);
    2950             :   Call(isolate, store_func, obj2, value2).Check();
    2951             : 
    2952          64 :   CHECK_EQ(*map, obj2->map());
    2953          64 :   CHECK(!map->is_dictionary_map());
    2954          64 :   CHECK(!map->is_deprecated());
    2955          64 :   CHECK_EQ(1, map->NumberOfOwnDescriptors());
    2956             : 
    2957          64 :   CHECK(map->instance_descriptors()->GetDetails(0).representation().Equals(
    2958             :       expected_rep));
    2959          64 :   CHECK_EQ(kExpectedInitialFieldConstness,
    2960             :            map->instance_descriptors()->GetDetails(0).constness());
    2961             : 
    2962             :   // Store value2 to obj1 and check that property became mutable.
    2963             :   Call(isolate, store_func, obj1, value2).Check();
    2964             : 
    2965          64 :   CHECK_EQ(*map, obj1->map());
    2966          64 :   CHECK(!map->is_dictionary_map());
    2967          64 :   CHECK(!map->is_deprecated());
    2968          64 :   CHECK_EQ(1, map->NumberOfOwnDescriptors());
    2969             : 
    2970          64 :   CHECK(map->instance_descriptors()->GetDetails(0).representation().Equals(
    2971             :       expected_rep));
    2972          64 :   CHECK_EQ(expected_constness,
    2973             :            map->instance_descriptors()->GetDetails(0).constness());
    2974          64 : }
    2975             : 
    2976          32 : void TestStoreToConstantField_PlusMinusZero(const char* store_func_source,
    2977             :                                             int store_repetitions) {
    2978             :   Isolate* isolate = CcTest::i_isolate();
    2979             :   CompileRun(store_func_source);
    2980             : 
    2981          32 :   Handle<Object> minus_zero = isolate->factory()->NewNumber(-0.0);
    2982          32 :   Handle<Object> plus_zero = isolate->factory()->NewNumber(0.0);
    2983             : 
    2984             :   // +0 and -0 are treated as not equal upon stores.
    2985             :   const PropertyConstness kExpectedFieldConstness = PropertyConstness::kMutable;
    2986             : 
    2987             :   TestStoreToConstantField(store_func_source, minus_zero, plus_zero,
    2988             :                            Representation::Double(), kExpectedFieldConstness,
    2989          32 :                            store_repetitions);
    2990          32 : }
    2991             : 
    2992          32 : void TestStoreToConstantField_NaN(const char* store_func_source,
    2993             :                                   int store_repetitions) {
    2994             :   Isolate* isolate = CcTest::i_isolate();
    2995             :   CompileRun(store_func_source);
    2996             : 
    2997             :   uint64_t nan_bits = uint64_t{0x7FF8000000000001};
    2998             :   double nan_double1 = bit_cast<double>(nan_bits);
    2999             :   double nan_double2 = bit_cast<double>(nan_bits | 0x12300);
    3000             :   CHECK(std::isnan(nan_double1));
    3001             :   CHECK(std::isnan(nan_double2));
    3002             :   CHECK_NE(nan_double1, nan_double2);
    3003             :   CHECK_NE(bit_cast<uint64_t>(nan_double1), bit_cast<uint64_t>(nan_double2));
    3004             : 
    3005          32 :   Handle<Object> nan1 = isolate->factory()->NewNumber(nan_double1);
    3006          32 :   Handle<Object> nan2 = isolate->factory()->NewNumber(nan_double2);
    3007             : 
    3008             :   // NaNs with different bit patters are treated as equal upon stores.
    3009             :   const PropertyConstness kExpectedFieldConstness =
    3010             :       FLAG_track_constant_fields ? PropertyConstness::kConst
    3011             :                                  : PropertyConstness::kMutable;
    3012             : 
    3013             :   TestStoreToConstantField(store_func_source, nan1, nan2,
    3014             :                            Representation::Double(), kExpectedFieldConstness,
    3015          32 :                            store_repetitions);
    3016          32 : }
    3017             : 
    3018             : }  // namespace
    3019             : 
    3020       26643 : TEST(StoreToConstantField_PlusMinusZero) {
    3021           4 :   FLAG_allow_natives_syntax = true;
    3022           4 :   CcTest::InitializeVM();
    3023           8 :   v8::HandleScope scope(CcTest::isolate());
    3024             : 
    3025             :   const char* store_func_source =
    3026             :       "function store(o, v) {"
    3027             :       "  %SetNamedProperty(o, 'v', v);"
    3028             :       "}";
    3029             : 
    3030           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 1);
    3031           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 3);
    3032             : 
    3033           4 :   TestStoreToConstantField_NaN(store_func_source, 1);
    3034           4 :   TestStoreToConstantField_NaN(store_func_source, 2);
    3035           4 : }
    3036             : 
    3037       26643 : TEST(StoreToConstantField_ObjectDefineProperty) {
    3038           4 :   CcTest::InitializeVM();
    3039           8 :   v8::HandleScope scope(CcTest::isolate());
    3040             : 
    3041             :   const char* store_func_source =
    3042             :       "function store(o, v) {"
    3043             :       "  Object.defineProperty(o, 'v', "
    3044             :       "                        {value: v, "
    3045             :       "                         writable: true, "
    3046             :       "                         configurable: true, "
    3047             :       "                         enumerable: true});"
    3048             :       "}";
    3049             : 
    3050           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 1);
    3051           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 3);
    3052             : 
    3053           4 :   TestStoreToConstantField_NaN(store_func_source, 1);
    3054           4 :   TestStoreToConstantField_NaN(store_func_source, 2);
    3055           4 : }
    3056             : 
    3057       26643 : TEST(StoreToConstantField_ReflectSet) {
    3058           4 :   CcTest::InitializeVM();
    3059           8 :   v8::HandleScope scope(CcTest::isolate());
    3060             : 
    3061             :   const char* store_func_source =
    3062             :       "function store(o, v) {"
    3063             :       "  Reflect.set(o, 'v', v);"
    3064             :       "}";
    3065             : 
    3066           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 1);
    3067           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 3);
    3068             : 
    3069           4 :   TestStoreToConstantField_NaN(store_func_source, 1);
    3070           4 :   TestStoreToConstantField_NaN(store_func_source, 2);
    3071           4 : }
    3072             : 
    3073       26643 : TEST(StoreToConstantField_StoreIC) {
    3074           4 :   CcTest::InitializeVM();
    3075           8 :   v8::HandleScope scope(CcTest::isolate());
    3076             : 
    3077             :   const char* store_func_source =
    3078             :       "function store(o, v) {"
    3079             :       "  o.v = v;"
    3080             :       "}";
    3081             : 
    3082           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 1);
    3083           4 :   TestStoreToConstantField_PlusMinusZero(store_func_source, 3);
    3084             : 
    3085           4 :   TestStoreToConstantField_NaN(store_func_source, 1);
    3086           4 :   TestStoreToConstantField_NaN(store_func_source, 2);
    3087           4 : }
    3088             : 
    3089             : }  // namespace test_field_type_tracking
    3090             : }  // namespace compiler
    3091             : }  // namespace internal
    3092       79917 : }  // namespace v8

Generated by: LCOV version 1.10