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