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