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