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

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

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

Powered by Google App Engine
This is Rietveld 408576698