Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(487)

Side by Side Diff: test/cctest/test-migrations.cc

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

Powered by Google App Engine
This is Rietveld 408576698