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