blob: 33a2dac2513fe2740763b5a72e40a33482701a1f [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdlib.h>
6#include <utility>
7
8#include "test/cctest/test-api.h"
9
10#include "src/v8.h"
11
12#include "src/compilation-cache.h"
13#include "src/execution.h"
14#include "src/factory.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010015#include "src/field-type.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016#include "src/global-handles.h"
17#include "src/ic/stub-cache.h"
18#include "src/macro-assembler.h"
19
20using namespace v8::internal;
21
22
23// TODO(ishell): fix this once TransitionToPrototype stops generalizing
24// all field representations (similar to crbug/448711 where elements kind
25// and observed transitions caused generalization of all field representations).
26const bool IS_PROTO_TRANS_ISSUE_FIXED = false;
27
28
29// TODO(ishell): fix this once TransitionToAccessorProperty is able to always
30// keep map in fast mode.
31const bool IS_ACCESSOR_FIELD_SUPPORTED = false;
32
33
34// Number of properties used in the tests.
35const int kPropCount = 7;
36
37
38//
39// Helper functions.
40//
41
42static Handle<String> MakeString(const char* str) {
43 Isolate* isolate = CcTest::i_isolate();
44 Factory* factory = isolate->factory();
45 return factory->InternalizeUtf8String(str);
46}
47
48
49static Handle<String> MakeName(const char* str, int suffix) {
50 EmbeddedVector<char, 128> buffer;
51 SNPrintF(buffer, "%s%d", str, suffix);
52 return MakeString(buffer.start());
53}
54
55
56static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
57 bool with_setter) {
58 Isolate* isolate = CcTest::i_isolate();
59 Factory* factory = isolate->factory();
60 Handle<AccessorPair> pair = factory->NewAccessorPair();
61 Handle<String> empty_string = factory->empty_string();
62 if (with_getter) {
63 Handle<JSFunction> func = factory->NewFunction(empty_string);
64 pair->set_getter(*func);
65 }
66 if (with_setter) {
67 Handle<JSFunction> func = factory->NewFunction(empty_string);
68 pair->set_setter(*func);
69 }
70 return pair;
71}
72
73
74static bool EqualDetails(DescriptorArray* descriptors, int descriptor,
75 PropertyType type, PropertyAttributes attributes,
76 Representation representation, int field_index = -1) {
77 PropertyDetails details = descriptors->GetDetails(descriptor);
78 if (details.type() != type) return false;
79 if (details.attributes() != attributes) return false;
80 if (!details.representation().Equals(representation)) return false;
81 if (field_index >= 0 && details.field_index() != field_index) return false;
82 return true;
83}
84
85
86class Expectations {
87 static const int MAX_PROPERTIES = 10;
88 Isolate* isolate_;
Ben Murdochc5610432016-08-08 18:44:38 +010089 ElementsKind elements_kind_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090 PropertyType types_[MAX_PROPERTIES];
91 PropertyAttributes attributes_[MAX_PROPERTIES];
92 Representation representations_[MAX_PROPERTIES];
Ben Murdoch097c5b22016-05-18 11:27:45 +010093 // FieldType for kField, value for DATA_CONSTANT and getter for
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 // ACCESSOR_CONSTANT.
95 Handle<Object> values_[MAX_PROPERTIES];
96 // Setter for ACCESSOR_CONSTANT.
97 Handle<Object> setter_values_[MAX_PROPERTIES];
98 int number_of_properties_;
99
100 public:
Ben Murdochc5610432016-08-08 18:44:38 +0100101 explicit Expectations(Isolate* isolate, ElementsKind elements_kind)
102 : isolate_(isolate),
103 elements_kind_(elements_kind),
104 number_of_properties_(0) {}
105
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 explicit Expectations(Isolate* isolate)
Ben Murdochc5610432016-08-08 18:44:38 +0100107 : Expectations(
108 isolate,
109 isolate->object_function()->initial_map()->elements_kind()) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110
111 void Init(int index, PropertyType type, PropertyAttributes attributes,
112 Representation representation, Handle<Object> value) {
113 CHECK(index < MAX_PROPERTIES);
114 types_[index] = type;
115 attributes_[index] = attributes;
116 representations_[index] = representation;
117 values_[index] = value;
118 }
119
120 void Print() const {
121 OFStream os(stdout);
122 os << "Expectations: #" << number_of_properties_ << "\n";
123 for (int i = 0; i < number_of_properties_; i++) {
124 os << " " << i << ": ";
125 os << "Descriptor @ ";
126 if (types_[i] == ACCESSOR_CONSTANT) {
127 os << "(get: " << Brief(*values_[i])
128 << ", set: " << Brief(*setter_values_[i]) << ") ";
129 } else {
130 os << Brief(*values_[i]);
131 }
132 os << " (";
133 switch (types_[i]) {
134 case DATA_CONSTANT:
135 os << "immutable ";
136 // Fall through.
137 case DATA:
138 os << "data";
139 break;
140
141 case ACCESSOR_CONSTANT:
142 os << "immutable ";
143 // Fall through.
144 case ACCESSOR:
145 os << "accessor";
146 break;
147 }
148 os << ": " << representations_[i].Mnemonic();
149 os << ", attrs: " << attributes_[i] << ")\n";
150 }
151 os << "\n";
152 }
153
Ben Murdochc5610432016-08-08 18:44:38 +0100154 void SetElementsKind(ElementsKind elements_kind) {
155 elements_kind_ = elements_kind;
156 }
157
Ben Murdoch097c5b22016-05-18 11:27:45 +0100158 Handle<FieldType> GetFieldType(int index) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 CHECK(index < MAX_PROPERTIES);
160 CHECK(types_[index] == DATA || types_[index] == ACCESSOR);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161 return Handle<FieldType>::cast(values_[index]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 }
163
164 void SetDataField(int index, PropertyAttributes attrs,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100165 Representation representation, Handle<FieldType> value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 Init(index, DATA, attrs, representation, value);
167 }
168
169 void SetDataField(int index, Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100170 Handle<FieldType> value) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 SetDataField(index, attributes_[index], representation, value);
172 }
173
174 void SetAccessorField(int index, PropertyAttributes attrs) {
175 Init(index, ACCESSOR, attrs, Representation::Tagged(),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100176 FieldType::Any(isolate_));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177 }
178
179 void SetAccessorField(int index) {
180 SetAccessorField(index, attributes_[index]);
181 }
182
183 void SetDataConstant(int index, PropertyAttributes attrs,
184 Handle<JSFunction> value) {
185 Init(index, DATA_CONSTANT, attrs, Representation::HeapObject(), value);
186 }
187
188 void SetDataConstant(int index, Handle<JSFunction> value) {
189 SetDataConstant(index, attributes_[index], value);
190 }
191
192 void SetAccessorConstant(int index, PropertyAttributes attrs,
193 Handle<Object> getter, Handle<Object> setter) {
194 Init(index, ACCESSOR_CONSTANT, attrs, Representation::Tagged(), getter);
195 setter_values_[index] = setter;
196 }
197
198 void SetAccessorConstantComponent(int index, PropertyAttributes attrs,
199 AccessorComponent component,
200 Handle<Object> accessor) {
201 CHECK_EQ(ACCESSOR_CONSTANT, types_[index]);
202 CHECK(index < number_of_properties_);
203 if (component == ACCESSOR_GETTER) {
204 values_[index] = accessor;
205 } else {
206 setter_values_[index] = accessor;
207 }
208 }
209
210 void SetAccessorConstant(int index, PropertyAttributes attrs,
211 Handle<AccessorPair> pair) {
212 Handle<Object> getter = handle(pair->getter(), isolate_);
213 Handle<Object> setter = handle(pair->setter(), isolate_);
214 SetAccessorConstant(index, attrs, getter, setter);
215 }
216
217 void SetAccessorConstant(int index, Handle<Object> getter,
218 Handle<Object> setter) {
219 SetAccessorConstant(index, attributes_[index], getter, setter);
220 }
221
222 void SetAccessorConstant(int index, Handle<AccessorPair> pair) {
223 Handle<Object> getter = handle(pair->getter(), isolate_);
224 Handle<Object> setter = handle(pair->setter(), isolate_);
225 SetAccessorConstant(index, getter, setter);
226 }
227
228 void GeneralizeRepresentation(int index) {
229 CHECK(index < number_of_properties_);
230 representations_[index] = Representation::Tagged();
231 if (types_[index] == DATA || types_[index] == ACCESSOR) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100232 values_[index] = FieldType::Any(isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 }
234 }
235
236
237 bool Check(DescriptorArray* descriptors, int descriptor) const {
238 PropertyType type = types_[descriptor];
239 if (!EqualDetails(descriptors, descriptor, type, attributes_[descriptor],
240 representations_[descriptor])) {
241 return false;
242 }
243 Object* value = descriptors->GetValue(descriptor);
244 Object* expected_value = *values_[descriptor];
245 switch (type) {
246 case DATA:
247 case ACCESSOR: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100248 FieldType* type = descriptors->GetFieldType(descriptor);
249 return FieldType::cast(expected_value) == type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250 }
251
252 case DATA_CONSTANT:
253 return value == expected_value;
254
255 case ACCESSOR_CONSTANT: {
256 if (value == expected_value) return true;
257 if (!value->IsAccessorPair()) return false;
258 AccessorPair* pair = AccessorPair::cast(value);
259 return pair->Equals(expected_value, *setter_values_[descriptor]);
260 }
261 }
262 UNREACHABLE();
263 return false;
264 }
265
266 bool Check(Map* map, int expected_nof) const {
Ben Murdochc5610432016-08-08 18:44:38 +0100267 CHECK_EQ(elements_kind_, map->elements_kind());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 CHECK(number_of_properties_ <= MAX_PROPERTIES);
269 CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors());
270 CHECK(!map->is_dictionary_map());
271
272 DescriptorArray* descriptors = map->instance_descriptors();
273 CHECK(expected_nof <= number_of_properties_);
274 for (int i = 0; i < expected_nof; i++) {
275 if (!Check(descriptors, i)) {
276 Print();
277#ifdef OBJECT_PRINT
278 descriptors->Print();
279#endif
280 Check(descriptors, i);
281 return false;
282 }
283 }
284 return true;
285 }
286
287 bool Check(Map* map) const { return Check(map, number_of_properties_); }
288
289
290 //
291 // Helper methods for initializing expectations and adding properties to
292 // given |map|.
293 //
294
Ben Murdochc5610432016-08-08 18:44:38 +0100295 Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) {
296 elements_kind_ = elements_kind;
297 map = Map::AsElementsKind(map, elements_kind);
298 CHECK_EQ(elements_kind_, map->elements_kind());
299 return map;
300 }
301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302 Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
303 Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 Handle<FieldType> heap_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
306 int property_index = number_of_properties_++;
307 SetDataField(property_index, attributes, representation, heap_type);
308
309 Handle<String> name = MakeName("prop", property_index);
310 return Map::CopyWithField(map, name, heap_type, attributes, representation,
311 INSERT_TRANSITION)
312 .ToHandleChecked();
313 }
314
315 Handle<Map> AddDataConstant(Handle<Map> map, PropertyAttributes attributes,
316 Handle<JSFunction> value) {
317 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
318 int property_index = number_of_properties_++;
319 SetDataConstant(property_index, attributes, value);
320
321 Handle<String> name = MakeName("prop", property_index);
322 return Map::CopyWithConstant(map, name, value, attributes,
323 INSERT_TRANSITION)
324 .ToHandleChecked();
325 }
326
327 Handle<Map> TransitionToDataField(Handle<Map> map,
328 PropertyAttributes attributes,
329 Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100330 Handle<FieldType> heap_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 Handle<Object> value) {
332 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
333 int property_index = number_of_properties_++;
334 SetDataField(property_index, attributes, representation, heap_type);
335
336 Handle<String> name = MakeName("prop", property_index);
337 return Map::TransitionToDataProperty(
338 map, name, value, attributes, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
339 }
340
341 Handle<Map> TransitionToDataConstant(Handle<Map> map,
342 PropertyAttributes attributes,
343 Handle<JSFunction> value) {
344 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
345 int property_index = number_of_properties_++;
346 SetDataConstant(property_index, attributes, value);
347
348 Handle<String> name = MakeName("prop", property_index);
349 return Map::TransitionToDataProperty(
350 map, name, value, attributes, Object::CERTAINLY_NOT_STORE_FROM_KEYED);
351 }
352
353 Handle<Map> FollowDataTransition(Handle<Map> map,
354 PropertyAttributes attributes,
355 Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100356 Handle<FieldType> heap_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
358 int property_index = number_of_properties_++;
359 SetDataField(property_index, attributes, representation, heap_type);
360
361 Handle<String> name = MakeName("prop", property_index);
362 Map* target =
363 TransitionArray::SearchTransition(*map, kData, *name, attributes);
364 CHECK(target != NULL);
365 return handle(target);
366 }
367
368 Handle<Map> AddAccessorConstant(Handle<Map> map,
369 PropertyAttributes attributes,
370 Handle<AccessorPair> pair) {
371 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
372 int property_index = number_of_properties_++;
373 SetAccessorConstant(property_index, attributes, pair);
374
375 Handle<String> name = MakeName("prop", property_index);
376
377 AccessorConstantDescriptor new_desc(name, pair, attributes);
378 return Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION);
379 }
380
381 Handle<Map> AddAccessorConstant(Handle<Map> map,
382 PropertyAttributes attributes,
383 Handle<Object> getter,
384 Handle<Object> setter) {
385 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
386 int property_index = number_of_properties_++;
387 SetAccessorConstant(property_index, attributes, getter, setter);
388
389 Handle<String> name = MakeName("prop", property_index);
390
Ben Murdoch61f157c2016-09-16 13:49:30 +0100391 CHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 Factory* factory = isolate_->factory();
393
Ben Murdoch61f157c2016-09-16 13:49:30 +0100394 if (!getter->IsNull(isolate_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 Handle<AccessorPair> pair = factory->NewAccessorPair();
396 pair->SetComponents(*getter, *factory->null_value());
397 AccessorConstantDescriptor new_desc(name, pair, attributes);
398 map = Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION);
399 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100400 if (!setter->IsNull(isolate_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401 Handle<AccessorPair> pair = factory->NewAccessorPair();
402 pair->SetComponents(*getter, *setter);
403 AccessorConstantDescriptor new_desc(name, pair, attributes);
404 map = Map::CopyInsertDescriptor(map, &new_desc, INSERT_TRANSITION);
405 }
406 return map;
407 }
408
409 Handle<Map> TransitionToAccessorConstant(Handle<Map> map,
410 PropertyAttributes attributes,
411 Handle<AccessorPair> pair) {
412 CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
413 int property_index = number_of_properties_++;
414 SetAccessorConstant(property_index, attributes, pair);
415
416 Handle<String> name = MakeName("prop", property_index);
417
418 Isolate* isolate = CcTest::i_isolate();
419 Handle<Object> getter(pair->getter(), isolate);
420 Handle<Object> setter(pair->setter(), isolate);
421
Ben Murdochda12d292016-06-02 14:46:10 +0100422 int descriptor =
423 map->instance_descriptors()->SearchWithCache(isolate, *name, *map);
Ben Murdochc5610432016-08-08 18:44:38 +0100424 map = Map::TransitionToAccessorProperty(isolate, map, name, descriptor,
425 getter, setter, attributes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 CHECK(!map->is_deprecated());
427 CHECK(!map->is_dictionary_map());
428 return map;
429 }
430};
431
432
433////////////////////////////////////////////////////////////////////////////////
434// A set of tests for property reconfiguration that makes new transition tree
435// branch.
436//
437
438TEST(ReconfigureAccessorToNonExistingDataField) {
439 CcTest::InitializeVM();
440 v8::HandleScope scope(CcTest::isolate());
441 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100442 Handle<FieldType> any_type = FieldType::Any(isolate);
443 Handle<FieldType> none_type = FieldType::None(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444 Handle<AccessorPair> pair = CreateAccessorPair(true, true);
445
446 Expectations expectations(isolate);
447
448 // Create a map, add required properties to it and initialize expectations.
449 Handle<Map> initial_map = Map::Create(isolate, 0);
450 Handle<Map> map = initial_map;
451 map = expectations.AddAccessorConstant(map, NONE, pair);
452
453 CHECK(!map->is_deprecated());
454 CHECK(map->is_stable());
455 CHECK(expectations.Check(*map));
456
457 Handle<Map> new_map = Map::ReconfigureProperty(
458 map, 0, kData, NONE, Representation::None(), none_type, FORCE_FIELD);
459 // |map| did not change except marked unstable.
460 CHECK(!map->is_deprecated());
461 CHECK(!map->is_stable());
462 CHECK(expectations.Check(*map));
463
464 expectations.SetDataField(0, NONE, Representation::None(), none_type);
465
466 CHECK(!new_map->is_deprecated());
467 CHECK(new_map->is_stable());
468 CHECK(expectations.Check(*new_map));
469
470 Handle<Map> new_map2 = Map::ReconfigureProperty(
471 map, 0, kData, NONE, Representation::None(), none_type, FORCE_FIELD);
472 CHECK_EQ(*new_map, *new_map2);
473
474 Handle<Object> value(Smi::FromInt(0), isolate);
475 Handle<Map> prepared_map = Map::PrepareForDataProperty(new_map, 0, value);
476 // None to Smi generalization is trivial, map does not change.
477 CHECK_EQ(*new_map, *prepared_map);
478
479 expectations.SetDataField(0, NONE, Representation::Smi(), any_type);
480 CHECK(prepared_map->is_stable());
481 CHECK(expectations.Check(*prepared_map));
482
483 // Now create an object with |map|, migrate it to |prepared_map| and ensure
484 // that the data property is uninitialized.
485 Factory* factory = isolate->factory();
486 Handle<JSObject> obj = factory->NewJSObjectFromMap(map);
487 JSObject::MigrateToMap(obj, prepared_map);
488 FieldIndex index = FieldIndex::ForDescriptor(*prepared_map, 0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100489 CHECK(obj->RawFastPropertyAt(index)->IsUninitialized(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490#ifdef VERIFY_HEAP
491 obj->ObjectVerify();
492#endif
493}
494
495
496// This test checks that the LookupIterator machinery involved in
497// JSObject::SetOwnPropertyIgnoreAttributes() does not try to migrate object
498// to a map with a property with None representation.
499TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {
500 CcTest::InitializeVM();
501 Isolate* isolate = CcTest::i_isolate();
502 Factory* factory = isolate->factory();
503 v8::HandleScope scope(CcTest::isolate());
504
505 CompileRun(
506 "function getter() { return 1; };"
507 "function setter() {};"
508 "var o = {};"
509 "Object.defineProperty(o, 'foo', "
510 " { get: getter, set: setter, "
511 " configurable: true, enumerable: true});");
512
513 Handle<String> foo_str = factory->InternalizeUtf8String("foo");
514 Handle<String> obj_name = factory->InternalizeUtf8String("o");
515
516 Handle<Object> obj_value =
517 Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
518 CHECK(obj_value->IsJSObject());
519 Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
520
521 CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
522 CHECK(obj->map()->instance_descriptors()->GetValue(0)->IsAccessorPair());
523
524 Handle<Object> value(Smi::FromInt(42), isolate);
525 JSObject::SetOwnPropertyIgnoreAttributes(obj, foo_str, value, NONE).Check();
526
527 // Check that the property contains |value|.
528 CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
529 FieldIndex index = FieldIndex::ForDescriptor(obj->map(), 0);
530 Object* the_value = obj->RawFastPropertyAt(index);
531 CHECK(the_value->IsSmi());
532 CHECK_EQ(42, Smi::cast(the_value)->value());
533}
534
535
536////////////////////////////////////////////////////////////////////////////////
537// A set of tests for representation generalization case.
538//
539
540// This test ensures that representation/field type generalization at
541// |property_index| is done correctly independently of the fact that the |map|
542// is detached from transition tree or not.
543//
544// {} - p0 - p1 - p2: |detach_point_map|
545// |
546// X - detached at |detach_property_at_index|
547// |
548// + - p3 - p4: |map|
549//
550// Detaching does not happen if |detach_property_at_index| is -1.
551//
552static void TestGeneralizeRepresentation(
553 int detach_property_at_index, int property_index,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100554 Representation from_representation, Handle<FieldType> from_type,
555 Representation to_representation, Handle<FieldType> to_type,
556 Representation expected_representation, Handle<FieldType> expected_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 bool expected_deprecation, bool expected_field_type_dependency) {
558 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100559 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560
561 CHECK(detach_property_at_index >= -1 &&
562 detach_property_at_index < kPropCount);
563 CHECK(property_index < kPropCount);
564 CHECK_NE(detach_property_at_index, property_index);
565
566 const bool is_detached_map = detach_property_at_index >= 0;
567
568 Expectations expectations(isolate);
569
570 // Create a map, add required properties to it and initialize expectations.
571 Handle<Map> initial_map = Map::Create(isolate, 0);
572 Handle<Map> map = initial_map;
573 Handle<Map> detach_point_map;
574 for (int i = 0; i < kPropCount; i++) {
575 if (i == property_index) {
576 map =
577 expectations.AddDataField(map, NONE, from_representation, from_type);
578 } else {
579 map =
580 expectations.AddDataField(map, NONE, Representation::Smi(), any_type);
581 if (i == detach_property_at_index) {
582 detach_point_map = map;
583 }
584 }
585 }
586 CHECK(!map->is_deprecated());
587 CHECK(map->is_stable());
588 CHECK(expectations.Check(*map));
589
Ben Murdochda12d292016-06-02 14:46:10 +0100590 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000591
592 if (is_detached_map) {
593 detach_point_map = Map::ReconfigureProperty(
594 detach_point_map, detach_property_at_index, kData, NONE,
595 Representation::Tagged(), any_type, FORCE_FIELD);
596 expectations.SetDataField(detach_property_at_index,
597 Representation::Tagged(), any_type);
598 CHECK(map->is_deprecated());
599 CHECK(expectations.Check(*detach_point_map,
600 detach_point_map->NumberOfOwnDescriptors()));
601 }
602
603 // Create new maps by generalizing representation of propX field.
604 Handle<Map> field_owner(map->FindFieldOwner(property_index), isolate);
Ben Murdochc5610432016-08-08 18:44:38 +0100605 CompilationInfo info(ArrayVector("testing"), isolate, &zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000606 CHECK(!info.dependencies()->HasAborted());
607
608 info.dependencies()->AssumeFieldType(field_owner);
609
610 Handle<Map> new_map =
611 Map::ReconfigureProperty(map, property_index, kData, NONE,
612 to_representation, to_type, FORCE_FIELD);
613
614 expectations.SetDataField(property_index, expected_representation,
615 expected_type);
616
617 CHECK(!new_map->is_deprecated());
618 CHECK(expectations.Check(*new_map));
619
620 if (is_detached_map) {
621 CHECK(!map->is_stable());
622 CHECK(map->is_deprecated());
623 CHECK_NE(*map, *new_map);
624 CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
625 info.dependencies()->HasAborted());
626
627 } else if (expected_deprecation) {
628 CHECK(!map->is_stable());
629 CHECK(map->is_deprecated());
630 CHECK(field_owner->is_deprecated());
631 CHECK_NE(*map, *new_map);
632 CHECK(!info.dependencies()->HasAborted());
633
634 } else {
635 CHECK(!field_owner->is_deprecated());
636 CHECK(map->is_stable()); // Map did not change, must be left stable.
637 CHECK_EQ(*map, *new_map);
638
639 CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
640 }
641
642 {
643 // Check that all previous maps are not stable.
644 Map* tmp = *new_map;
645 while (true) {
646 Object* back = tmp->GetBackPointer();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100647 if (back->IsUndefined(isolate)) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000648 tmp = Map::cast(back);
649 CHECK(!tmp->is_stable());
650 }
651 }
652
653 info.dependencies()->Rollback(); // Properly cleanup compilation info.
654
655 // Update all deprecated maps and check that they are now the same.
656 Handle<Map> updated_map = Map::Update(map);
657 CHECK_EQ(*new_map, *updated_map);
658}
659
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000660static void TestGeneralizeRepresentation(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100661 Representation from_representation, Handle<FieldType> from_type,
662 Representation to_representation, Handle<FieldType> to_type,
663 Representation expected_representation, Handle<FieldType> expected_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 bool expected_deprecation, bool expected_field_type_dependency) {
665 // Check the cases when the map being reconfigured is a part of the
666 // transition tree.
667 STATIC_ASSERT(kPropCount > 4);
668 int indices[] = {0, 2, kPropCount - 1};
669 for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
670 TestGeneralizeRepresentation(
671 -1, indices[i], from_representation, from_type, to_representation,
672 to_type, expected_representation, expected_type, expected_deprecation,
673 expected_field_type_dependency);
674 }
675
676 if (!from_representation.IsNone()) {
677 // Check the cases when the map being reconfigured is NOT a part of the
678 // transition tree. "None -> anything" representation changes make sense
679 // only for "attached" maps.
680 int indices[] = {0, kPropCount - 1};
681 for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
682 TestGeneralizeRepresentation(
683 indices[i], 2, from_representation, from_type, to_representation,
684 to_type, expected_representation, expected_type, expected_deprecation,
685 expected_field_type_dependency);
686 }
687
688 // Check that reconfiguration to the very same field works correctly.
689 Representation representation = from_representation;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100690 Handle<FieldType> type = from_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 TestGeneralizeRepresentation(-1, 2, representation, type, representation,
692 type, representation, type, false, false);
693 }
694}
695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696static void TestGeneralizeRepresentation(Representation from_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100697 Handle<FieldType> from_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 Representation to_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100699 Handle<FieldType> to_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 Representation expected_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100701 Handle<FieldType> expected_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000702 const bool expected_deprecation = true;
703 const bool expected_field_type_dependency = false;
704
705 TestGeneralizeRepresentation(
706 from_representation, from_type, to_representation, to_type,
707 expected_representation, expected_type, expected_deprecation,
708 expected_field_type_dependency);
709}
710
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000711static void TestGeneralizeRepresentationTrivial(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100712 Representation from_representation, Handle<FieldType> from_type,
713 Representation to_representation, Handle<FieldType> to_type,
714 Representation expected_representation, Handle<FieldType> expected_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 bool expected_field_type_dependency = true) {
716 const bool expected_deprecation = false;
717
718 TestGeneralizeRepresentation(
719 from_representation, from_type, to_representation, to_type,
720 expected_representation, expected_type, expected_deprecation,
721 expected_field_type_dependency);
722}
723
724
725TEST(GeneralizeRepresentationSmiToDouble) {
726 CcTest::InitializeVM();
727 v8::HandleScope scope(CcTest::isolate());
728 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100729 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730
731 TestGeneralizeRepresentation(Representation::Smi(), any_type,
732 Representation::Double(), any_type,
733 Representation::Double(), any_type);
734}
735
736
737TEST(GeneralizeRepresentationSmiToTagged) {
738 CcTest::InitializeVM();
739 v8::HandleScope scope(CcTest::isolate());
740 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100741 Handle<FieldType> any_type = FieldType::Any(isolate);
742 Handle<FieldType> value_type =
743 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744
745 TestGeneralizeRepresentation(Representation::Smi(), any_type,
746 Representation::HeapObject(), value_type,
747 Representation::Tagged(), any_type);
748}
749
750
751TEST(GeneralizeRepresentationDoubleToTagged) {
752 CcTest::InitializeVM();
753 v8::HandleScope scope(CcTest::isolate());
754 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100755 Handle<FieldType> any_type = FieldType::Any(isolate);
756 Handle<FieldType> value_type =
757 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758
759 TestGeneralizeRepresentation(Representation::Double(), any_type,
760 Representation::HeapObject(), value_type,
761 Representation::Tagged(), any_type);
762}
763
764
765TEST(GeneralizeRepresentationHeapObjectToTagged) {
766 CcTest::InitializeVM();
767 v8::HandleScope scope(CcTest::isolate());
768 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100769 Handle<FieldType> any_type = FieldType::Any(isolate);
770 Handle<FieldType> value_type =
771 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772
773 TestGeneralizeRepresentation(Representation::HeapObject(), value_type,
774 Representation::Smi(), any_type,
775 Representation::Tagged(), any_type);
776}
777
778
779TEST(GeneralizeRepresentationHeapObjectToHeapObject) {
780 CcTest::InitializeVM();
781 v8::HandleScope scope(CcTest::isolate());
782 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100783 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784
Ben Murdoch097c5b22016-05-18 11:27:45 +0100785 Handle<FieldType> current_type =
786 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000787
Ben Murdoch097c5b22016-05-18 11:27:45 +0100788 Handle<FieldType> new_type =
789 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790
Ben Murdoch097c5b22016-05-18 11:27:45 +0100791 Handle<FieldType> expected_type = any_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000792
793 TestGeneralizeRepresentationTrivial(
794 Representation::HeapObject(), current_type,
795 Representation::HeapObject(), new_type, Representation::HeapObject(),
796 expected_type);
797 current_type = expected_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798
Ben Murdoch097c5b22016-05-18 11:27:45 +0100799 new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800
801 TestGeneralizeRepresentationTrivial(
802 Representation::HeapObject(), any_type, Representation::HeapObject(),
803 new_type, Representation::HeapObject(), any_type, false);
804}
805
806
807TEST(GeneralizeRepresentationNoneToSmi) {
808 CcTest::InitializeVM();
809 v8::HandleScope scope(CcTest::isolate());
810 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100811 Handle<FieldType> none_type = FieldType::None(isolate);
812 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813
814 // None -> Smi representation change is trivial.
815 TestGeneralizeRepresentationTrivial(Representation::None(), none_type,
816 Representation::Smi(), any_type,
817 Representation::Smi(), any_type);
818}
819
820
821TEST(GeneralizeRepresentationNoneToDouble) {
822 CcTest::InitializeVM();
823 v8::HandleScope scope(CcTest::isolate());
824 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100825 Handle<FieldType> none_type = FieldType::None(isolate);
826 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000827
828 // None -> Double representation change is NOT trivial.
829 TestGeneralizeRepresentation(Representation::None(), none_type,
830 Representation::Double(), any_type,
831 Representation::Double(), any_type);
832}
833
834
835TEST(GeneralizeRepresentationNoneToHeapObject) {
836 CcTest::InitializeVM();
837 v8::HandleScope scope(CcTest::isolate());
838 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100839 Handle<FieldType> none_type = FieldType::None(isolate);
840 Handle<FieldType> value_type =
841 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000842
843 // None -> HeapObject representation change is trivial.
844 TestGeneralizeRepresentationTrivial(Representation::None(), none_type,
845 Representation::HeapObject(), value_type,
846 Representation::HeapObject(), value_type);
847}
848
849
850TEST(GeneralizeRepresentationNoneToTagged) {
851 CcTest::InitializeVM();
852 v8::HandleScope scope(CcTest::isolate());
853 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100854 Handle<FieldType> none_type = FieldType::None(isolate);
855 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000856
857 // None -> HeapObject representation change is trivial.
858 TestGeneralizeRepresentationTrivial(Representation::None(), none_type,
859 Representation::Tagged(), any_type,
860 Representation::Tagged(), any_type);
861}
862
863
864////////////////////////////////////////////////////////////////////////////////
865// A set of tests for representation generalization case with kAccessor
866// properties.
867//
868
869TEST(GeneralizeRepresentationWithAccessorProperties) {
870 CcTest::InitializeVM();
871 v8::HandleScope scope(CcTest::isolate());
872 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100873 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000874 Handle<AccessorPair> pair = CreateAccessorPair(true, true);
875
876 const int kAccessorProp = kPropCount / 2;
877 Expectations expectations(isolate);
878
879 // Create a map, add required properties to it and initialize expectations.
880 Handle<Map> initial_map = Map::Create(isolate, 0);
881 Handle<Map> map = initial_map;
882 for (int i = 0; i < kPropCount; i++) {
883 if (i == kAccessorProp) {
884 map = expectations.AddAccessorConstant(map, NONE, pair);
885 } else {
886 map =
887 expectations.AddDataField(map, NONE, Representation::Smi(), any_type);
888 }
889 }
890 CHECK(!map->is_deprecated());
891 CHECK(map->is_stable());
892 CHECK(expectations.Check(*map));
893
894 // Create new maps by generalizing representation of propX field.
895 Handle<Map> maps[kPropCount];
896 for (int i = 0; i < kPropCount; i++) {
897 if (i == kAccessorProp) {
898 // Skip accessor property reconfiguration.
899 maps[i] = maps[i - 1];
900 continue;
901 }
902 Handle<Map> new_map = Map::ReconfigureProperty(
903 map, i, kData, NONE, Representation::Double(), any_type, FORCE_FIELD);
904 maps[i] = new_map;
905
906 expectations.SetDataField(i, Representation::Double(), any_type);
907
908 CHECK(!map->is_stable());
909 CHECK(map->is_deprecated());
910 CHECK_NE(*map, *new_map);
911 CHECK(i == 0 || maps[i - 1]->is_deprecated());
912
913 CHECK(!new_map->is_deprecated());
914 CHECK(expectations.Check(*new_map));
915 }
916
917 Handle<Map> active_map = maps[kPropCount - 1];
918 CHECK(!active_map->is_deprecated());
919
920 // Update all deprecated maps and check that they are now the same.
921 Handle<Map> updated_map = Map::Update(map);
922 CHECK_EQ(*active_map, *updated_map);
923 for (int i = 0; i < kPropCount; i++) {
924 updated_map = Map::Update(maps[i]);
925 CHECK_EQ(*active_map, *updated_map);
926 }
927}
928
929
930////////////////////////////////////////////////////////////////////////////////
931// A set of tests for attribute reconfiguration case.
932//
933
934// This test ensures that representation/field type generalization is correctly
935// propagated from one branch of transition tree (|map2|) to another (|map|).
936//
937// + - p2B - p3 - p4: |map2|
938// |
939// {} - p0 - p1 - p2A - p3 - p4: |map|
940//
941// where "p2A" and "p2B" differ only in the attributes.
942//
943static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100944 Representation from_representation, Handle<FieldType> from_type,
945 Representation to_representation, Handle<FieldType> to_type,
946 Representation expected_representation, Handle<FieldType> expected_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 Isolate* isolate = CcTest::i_isolate();
948
949 Expectations expectations(isolate);
950
951 // Create a map, add required properties to it and initialize expectations.
952 Handle<Map> initial_map = Map::Create(isolate, 0);
953 Handle<Map> map = initial_map;
954 for (int i = 0; i < kPropCount; i++) {
955 map = expectations.AddDataField(map, NONE, from_representation, from_type);
956 }
957 CHECK(!map->is_deprecated());
958 CHECK(map->is_stable());
959 CHECK(expectations.Check(*map));
960
961
962 // Create another branch in transition tree (property at index |kSplitProp|
963 // has different attributes), initialize expectations.
964 const int kSplitProp = kPropCount / 2;
965 Expectations expectations2(isolate);
966
967 Handle<Map> map2 = initial_map;
968 for (int i = 0; i < kSplitProp; i++) {
969 map2 = expectations2.FollowDataTransition(map2, NONE, from_representation,
970 from_type);
971 }
972 map2 =
973 expectations2.AddDataField(map2, READ_ONLY, to_representation, to_type);
974
975 for (int i = kSplitProp + 1; i < kPropCount; i++) {
976 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
977 }
978 CHECK(!map2->is_deprecated());
979 CHECK(map2->is_stable());
980 CHECK(expectations2.Check(*map2));
981
Ben Murdochda12d292016-06-02 14:46:10 +0100982 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000983 Handle<Map> field_owner(map->FindFieldOwner(kSplitProp), isolate);
Ben Murdochc5610432016-08-08 18:44:38 +0100984 CompilationInfo info(ArrayVector("testing"), isolate, &zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 CHECK(!info.dependencies()->HasAborted());
986 info.dependencies()->AssumeFieldType(field_owner);
987
988 // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
989 // should generalize representations in |map1|.
990 Handle<Map> new_map =
991 Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE);
992
993 // |map2| should be left unchanged but marked unstable.
994 CHECK(!map2->is_stable());
995 CHECK(!map2->is_deprecated());
996 CHECK_NE(*map2, *new_map);
997 CHECK(expectations2.Check(*map2));
998
999 // |map| should be deprecated and |new_map| 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(!info.dependencies()->HasAborted());
1005 info.dependencies()->Rollback(); // Properly cleanup compilation info.
1006 CHECK_NE(*map, *new_map);
1007
1008 CHECK(!new_map->is_deprecated());
1009 CHECK(expectations.Check(*new_map));
1010
1011 // Update deprecated |map|, it should become |new_map|.
1012 Handle<Map> updated_map = Map::Update(map);
1013 CHECK_EQ(*new_map, *updated_map);
1014}
1015
1016
1017// This test ensures that trivial representation/field type generalization
1018// (from HeapObject to HeapObject) is correctly propagated from one branch of
1019// transition tree (|map2|) to another (|map|).
1020//
1021// + - p2B - p3 - p4: |map2|
1022// |
1023// {} - p0 - p1 - p2A - p3 - p4: |map|
1024//
1025// where "p2A" and "p2B" differ only in the attributes.
1026//
1027static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001028 Representation from_representation, Handle<FieldType> from_type,
1029 Representation to_representation, Handle<FieldType> to_type,
1030 Representation expected_representation, Handle<FieldType> expected_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001031 bool expected_field_type_dependency = true) {
1032 Isolate* isolate = CcTest::i_isolate();
1033
1034 Expectations expectations(isolate);
1035
1036 // Create a map, add required properties to it and initialize expectations.
1037 Handle<Map> initial_map = Map::Create(isolate, 0);
1038 Handle<Map> map = initial_map;
1039 for (int i = 0; i < kPropCount; i++) {
1040 map = expectations.AddDataField(map, NONE, from_representation, from_type);
1041 }
1042 CHECK(!map->is_deprecated());
1043 CHECK(map->is_stable());
1044 CHECK(expectations.Check(*map));
1045
1046
1047 // Create another branch in transition tree (property at index |kSplitProp|
1048 // has different attributes), initialize expectations.
1049 const int kSplitProp = kPropCount / 2;
1050 Expectations expectations2(isolate);
1051
1052 Handle<Map> map2 = initial_map;
1053 for (int i = 0; i < kSplitProp; i++) {
1054 map2 = expectations2.FollowDataTransition(map2, NONE, from_representation,
1055 from_type);
1056 }
1057 map2 =
1058 expectations2.AddDataField(map2, READ_ONLY, to_representation, to_type);
1059
1060 for (int i = kSplitProp + 1; i < kPropCount; i++) {
1061 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
1062 }
1063 CHECK(!map2->is_deprecated());
1064 CHECK(map2->is_stable());
1065 CHECK(expectations2.Check(*map2));
1066
Ben Murdochda12d292016-06-02 14:46:10 +01001067 Zone zone(isolate->allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068 Handle<Map> field_owner(map->FindFieldOwner(kSplitProp), isolate);
Ben Murdochc5610432016-08-08 18:44:38 +01001069 CompilationInfo info(ArrayVector("testing"), isolate, &zone);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070 CHECK(!info.dependencies()->HasAborted());
1071 info.dependencies()->AssumeFieldType(field_owner);
1072
1073 // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
1074 // should generalize representations in |map1|.
1075 Handle<Map> new_map =
1076 Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE);
1077
1078 // |map2| should be left unchanged but marked unstable.
1079 CHECK(!map2->is_stable());
1080 CHECK(!map2->is_deprecated());
1081 CHECK_NE(*map2, *new_map);
1082 CHECK(expectations2.Check(*map2));
1083
1084 // In trivial case |map| should be returned as a result of the property
1085 // reconfiguration, respective field types should be generalized and
1086 // respective code dependencies should be invalidated. |map| should be NOT
1087 // deprecated and it should match new expectations.
1088 for (int i = kSplitProp; i < kPropCount; i++) {
1089 expectations.SetDataField(i, expected_representation, expected_type);
1090 }
1091 CHECK(!map->is_deprecated());
1092 CHECK_EQ(*map, *new_map);
1093 CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
1094 info.dependencies()->Rollback(); // Properly cleanup compilation info.
1095
1096 CHECK(!new_map->is_deprecated());
1097 CHECK(expectations.Check(*new_map));
1098
1099 Handle<Map> updated_map = Map::Update(map);
1100 CHECK_EQ(*new_map, *updated_map);
1101}
1102
1103
1104TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToDouble) {
1105 CcTest::InitializeVM();
1106 v8::HandleScope scope(CcTest::isolate());
1107 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001108 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001109
1110 TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
1111 Representation::Smi(), any_type, Representation::Double(), any_type,
1112 Representation::Double(), any_type);
1113}
1114
1115
1116TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToTagged) {
1117 CcTest::InitializeVM();
1118 v8::HandleScope scope(CcTest::isolate());
1119 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001120 Handle<FieldType> any_type = FieldType::Any(isolate);
1121 Handle<FieldType> value_type =
1122 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001123
1124 TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
1125 Representation::Smi(), any_type, Representation::HeapObject(), value_type,
1126 Representation::Tagged(), any_type);
1127}
1128
1129
1130TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationDoubleToTagged) {
1131 CcTest::InitializeVM();
1132 v8::HandleScope scope(CcTest::isolate());
1133 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001134 Handle<FieldType> any_type = FieldType::Any(isolate);
1135 Handle<FieldType> value_type =
1136 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001137
1138 TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
1139 Representation::Double(), any_type, Representation::HeapObject(),
1140 value_type, Representation::Tagged(), any_type);
1141}
1142
1143
1144TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjToHeapObj) {
1145 CcTest::InitializeVM();
1146 v8::HandleScope scope(CcTest::isolate());
1147 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001148 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149
Ben Murdoch097c5b22016-05-18 11:27:45 +01001150 Handle<FieldType> current_type =
1151 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001152
Ben Murdoch097c5b22016-05-18 11:27:45 +01001153 Handle<FieldType> new_type =
1154 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155
Ben Murdoch097c5b22016-05-18 11:27:45 +01001156 Handle<FieldType> expected_type = any_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157
Ben Murdoch097c5b22016-05-18 11:27:45 +01001158 TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial(
1159 Representation::HeapObject(), current_type, Representation::HeapObject(),
1160 new_type, Representation::HeapObject(), expected_type);
1161 current_type = expected_type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162
Ben Murdoch097c5b22016-05-18 11:27:45 +01001163 new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001164
1165 TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial(
1166 Representation::HeapObject(), any_type, Representation::HeapObject(),
1167 new_type, Representation::HeapObject(), any_type, false);
1168}
1169
1170
1171TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjectToTagged) {
1172 CcTest::InitializeVM();
1173 v8::HandleScope scope(CcTest::isolate());
1174 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001175 Handle<FieldType> any_type = FieldType::Any(isolate);
1176 Handle<FieldType> value_type =
1177 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178
1179 TestReconfigureDataFieldAttribute_GeneralizeRepresentation(
1180 Representation::HeapObject(), value_type, Representation::Smi(), any_type,
1181 Representation::Tagged(), any_type);
1182}
1183
1184
1185// Checks that given |map| is deprecated and that it updates to given |new_map|
1186// which in turn should match expectations.
1187struct CheckDeprecated {
1188 void Check(Handle<Map> map, Handle<Map> new_map,
1189 const Expectations& expectations) {
1190 CHECK(map->is_deprecated());
1191 CHECK_NE(*map, *new_map);
1192
1193 CHECK(!new_map->is_deprecated());
1194 CHECK(expectations.Check(*new_map));
1195
1196 // Update deprecated |map|, it should become |new_map|.
1197 Handle<Map> updated_map = Map::Update(map);
1198 CHECK_EQ(*new_map, *updated_map);
1199 }
1200};
1201
1202
1203// Checks that given |map| is NOT deprecated, equals to given |new_map| and
1204// matches expectations.
1205struct CheckSameMap {
1206 void Check(Handle<Map> map, Handle<Map> new_map,
1207 const Expectations& expectations) {
1208 // |map| was not reconfigured, therefore it should stay stable.
1209 CHECK(map->is_stable());
1210 CHECK(!map->is_deprecated());
1211 CHECK_EQ(*map, *new_map);
1212
1213 CHECK(!new_map->is_deprecated());
1214 CHECK(expectations.Check(*new_map));
1215
1216 // Update deprecated |map|, it should become |new_map|.
1217 Handle<Map> updated_map = Map::Update(map);
1218 CHECK_EQ(*new_map, *updated_map);
1219 }
1220};
1221
1222
1223// Checks that given |map| is NOT deprecated and matches expectations.
1224// |new_map| is unrelated to |map|.
1225struct CheckUnrelated {
1226 void Check(Handle<Map> map, Handle<Map> new_map,
1227 const Expectations& expectations) {
1228 CHECK(!map->is_deprecated());
1229 CHECK_NE(*map, *new_map);
1230 CHECK(expectations.Check(*map));
1231
1232 CHECK(new_map->is_stable());
1233 CHECK(!new_map->is_deprecated());
1234 }
1235};
1236
1237
1238// Checks that given |map| is NOT deprecated, and |new_map| is a result of
1239// copy-generalize-all-representations.
1240struct CheckCopyGeneralizeAllRepresentations {
1241 void Check(Handle<Map> map, Handle<Map> new_map, Expectations& expectations) {
1242 CHECK(!map->is_deprecated());
1243 CHECK_NE(*map, *new_map);
1244
Ben Murdoch61f157c2016-09-16 13:49:30 +01001245 CHECK(new_map->GetBackPointer()->IsUndefined(map->GetIsolate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 for (int i = 0; i < kPropCount; i++) {
1247 expectations.GeneralizeRepresentation(i);
1248 }
1249
1250 CHECK(!new_map->is_deprecated());
1251 CHECK(expectations.Check(*new_map));
1252 }
1253};
1254
1255
1256// This test ensures that representation/field type generalization is correctly
1257// propagated from one branch of transition tree (|map2|) to another (|map1|).
1258//
1259// + - p2B - p3 - p4: |map2|
1260// |
1261// {} - p0 - p1: |map|
1262// |
1263// + - p2A - p3 - p4: |map1|
1264// |
1265// + - the property customized by the TestConfig provided
1266//
1267// where "p2A" and "p2B" differ only in the attributes.
1268//
1269template <typename TestConfig, typename Checker>
1270static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
1271 TestConfig& config, Checker& checker) {
1272 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001273 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001274
1275 const int kCustomPropIndex = kPropCount - 2;
1276 Expectations expectations(isolate);
1277
1278 const int kSplitProp = 2;
1279 CHECK(kSplitProp < kCustomPropIndex);
1280
1281 const Representation representation = Representation::Smi();
1282
1283 // Create common part of transition tree.
1284 Handle<Map> initial_map = Map::Create(isolate, 0);
1285 Handle<Map> map = initial_map;
1286 for (int i = 0; i < kSplitProp; i++) {
1287 map = expectations.AddDataField(map, NONE, representation, any_type);
1288 }
1289 CHECK(!map->is_deprecated());
1290 CHECK(map->is_stable());
1291 CHECK(expectations.Check(*map));
1292
1293
1294 // Create branch to |map1|.
1295 Handle<Map> map1 = map;
1296 Expectations expectations1 = expectations;
1297 for (int i = kSplitProp; i < kCustomPropIndex; i++) {
1298 map1 = expectations1.AddDataField(map1, NONE, representation, any_type);
1299 }
1300 map1 = config.AddPropertyAtBranch(1, expectations1, map1);
1301 for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
1302 map1 = expectations1.AddDataField(map1, NONE, representation, any_type);
1303 }
1304 CHECK(!map1->is_deprecated());
1305 CHECK(map1->is_stable());
1306 CHECK(expectations1.Check(*map1));
1307
1308
1309 // Create another branch in transition tree (property at index |kSplitProp|
1310 // has different attributes), initialize expectations.
1311 Handle<Map> map2 = map;
1312 Expectations expectations2 = expectations;
1313 map2 = expectations2.AddDataField(map2, READ_ONLY, representation, any_type);
1314 for (int i = kSplitProp + 1; i < kCustomPropIndex; i++) {
1315 map2 = expectations2.AddDataField(map2, NONE, representation, any_type);
1316 }
1317 map2 = config.AddPropertyAtBranch(2, expectations2, map2);
1318 for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
1319 map2 = expectations2.AddDataField(map2, NONE, representation, any_type);
1320 }
1321 CHECK(!map2->is_deprecated());
1322 CHECK(map2->is_stable());
1323 CHECK(expectations2.Check(*map2));
1324
1325
1326 // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
1327 // should generalize representations in |map1|.
1328 Handle<Map> new_map =
1329 Map::ReconfigureExistingProperty(map2, kSplitProp, kData, NONE);
1330
1331 // |map2| should be left unchanged but marked unstable.
1332 CHECK(!map2->is_stable());
1333 CHECK(!map2->is_deprecated());
1334 CHECK_NE(*map2, *new_map);
1335 CHECK(expectations2.Check(*map2));
1336
1337 config.UpdateExpectations(kCustomPropIndex, expectations1);
1338 checker.Check(map1, new_map, expectations1);
1339}
1340
1341
1342TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) {
1343 CcTest::InitializeVM();
1344 v8::HandleScope scope(CcTest::isolate());
1345
1346 struct TestConfig {
1347 Handle<JSFunction> js_func_;
1348 TestConfig() {
1349 Isolate* isolate = CcTest::i_isolate();
1350 Factory* factory = isolate->factory();
1351 js_func_ = factory->NewFunction(factory->empty_string());
1352 }
1353
1354 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1355 Handle<Map> map) {
1356 CHECK(branch_id == 1 || branch_id == 2);
1357 // Add the same data constant property at both transition tree branches.
1358 return expectations.AddDataConstant(map, NONE, js_func_);
1359 }
1360
1361 void UpdateExpectations(int property_index, Expectations& expectations) {
1362 // Expectations stay the same.
1363 }
1364 };
1365
1366 TestConfig config;
1367 // Two branches are "compatible" so the |map1| should NOT be deprecated.
1368 CheckSameMap checker;
1369 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1370}
1371
1372
1373TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
1374 CcTest::InitializeVM();
1375 v8::HandleScope scope(CcTest::isolate());
1376
1377 struct TestConfig {
1378 Handle<JSFunction> js_func1_;
1379 Handle<JSFunction> js_func2_;
1380 TestConfig() {
1381 Isolate* isolate = CcTest::i_isolate();
1382 Factory* factory = isolate->factory();
1383 js_func1_ = factory->NewFunction(factory->empty_string());
1384 js_func2_ = factory->NewFunction(factory->empty_string());
1385 }
1386
1387 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1388 Handle<Map> map) {
1389 CHECK(branch_id == 1 || branch_id == 2);
1390 Handle<JSFunction> js_func = branch_id == 1 ? js_func1_ : js_func2_;
1391 return expectations.AddDataConstant(map, NONE, js_func);
1392 }
1393
1394 void UpdateExpectations(int property_index, Expectations& expectations) {
1395 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001396 Handle<FieldType> function_type =
1397 FieldType::Class(isolate->sloppy_function_map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001398 expectations.SetDataField(property_index, Representation::HeapObject(),
1399 function_type);
1400 }
1401 };
1402
1403 TestConfig config;
1404 // Two branches are "incompatible" so the |map1| should be deprecated.
1405 CheckDeprecated checker;
1406 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1407}
1408
1409
1410TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {
1411 CcTest::InitializeVM();
1412 v8::HandleScope scope(CcTest::isolate());
1413
1414 struct TestConfig {
1415 Handle<JSFunction> js_func_;
1416 Handle<AccessorPair> pair_;
1417 TestConfig() {
1418 Isolate* isolate = CcTest::i_isolate();
1419 Factory* factory = isolate->factory();
1420 js_func_ = factory->NewFunction(factory->empty_string());
1421 pair_ = CreateAccessorPair(true, true);
1422 }
1423
1424 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1425 Handle<Map> map) {
1426 CHECK(branch_id == 1 || branch_id == 2);
1427 if (branch_id == 1) {
1428 return expectations.AddDataConstant(map, NONE, js_func_);
1429 } else {
1430 return expectations.AddAccessorConstant(map, NONE, pair_);
1431 }
1432 }
1433
1434 void UpdateExpectations(int property_index, Expectations& expectations) {}
1435 };
1436
1437 TestConfig config;
1438 // These are completely separate branches in transition tree.
1439 CheckUnrelated checker;
1440 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1441}
1442
1443
1444TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
1445 CcTest::InitializeVM();
1446 v8::HandleScope scope(CcTest::isolate());
1447
1448 struct TestConfig {
1449 Handle<AccessorPair> pair_;
1450 TestConfig() { pair_ = CreateAccessorPair(true, true); }
1451
1452 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1453 Handle<Map> map) {
1454 CHECK(branch_id == 1 || branch_id == 2);
1455 // Add the same accessor constant property at both transition tree
1456 // branches.
1457 return expectations.AddAccessorConstant(map, NONE, pair_);
1458 }
1459
1460 void UpdateExpectations(int property_index, Expectations& expectations) {
1461 // Two branches are "compatible" so the |map1| should NOT be deprecated.
1462 }
1463 };
1464
1465 TestConfig config;
1466 CheckSameMap checker;
1467 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1468}
1469
1470
1471TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
1472 CcTest::InitializeVM();
1473 v8::HandleScope scope(CcTest::isolate());
1474
1475 struct TestConfig {
1476 Handle<AccessorPair> pair1_;
1477 Handle<AccessorPair> pair2_;
1478 TestConfig() {
1479 pair1_ = CreateAccessorPair(true, true);
1480 pair2_ = CreateAccessorPair(true, true);
1481 }
1482
1483 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1484 Handle<Map> map) {
1485 CHECK(branch_id == 1 || branch_id == 2);
1486 Handle<AccessorPair> pair = branch_id == 1 ? pair1_ : pair2_;
1487 return expectations.AddAccessorConstant(map, NONE, pair);
1488 }
1489
1490 void UpdateExpectations(int property_index, Expectations& expectations) {
1491 if (IS_ACCESSOR_FIELD_SUPPORTED) {
1492 expectations.SetAccessorField(property_index);
1493 } else {
1494 // Currently we have a copy-generalize-all-representations case and
1495 // ACCESSOR property becomes ACCESSOR_CONSTANT.
1496 expectations.SetAccessorConstant(property_index, pair2_);
1497 }
1498 }
1499 };
1500
1501 TestConfig config;
1502 if (IS_ACCESSOR_FIELD_SUPPORTED) {
1503 CheckCopyGeneralizeAllRepresentations checker;
1504 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1505 } else {
1506 // Currently we have a copy-generalize-all-representations case.
1507 CheckCopyGeneralizeAllRepresentations checker;
1508 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1509 }
1510}
1511
1512
1513TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {
1514 CcTest::InitializeVM();
1515 v8::HandleScope scope(CcTest::isolate());
1516
1517 struct TestConfig {
1518 Handle<AccessorPair> pair_;
1519 TestConfig() { pair_ = CreateAccessorPair(true, true); }
1520
1521 Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1522 Handle<Map> map) {
1523 CHECK(branch_id == 1 || branch_id == 2);
1524 if (branch_id == 1) {
1525 return expectations.AddAccessorConstant(map, NONE, pair_);
1526 } else {
1527 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001528 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 return expectations.AddDataField(map, NONE, Representation::Smi(),
1530 any_type);
1531 }
1532 }
1533
1534 void UpdateExpectations(int property_index, Expectations& expectations) {}
1535 };
1536
1537 TestConfig config;
1538 // These are completely separate branches in transition tree.
1539 CheckUnrelated checker;
1540 TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1541}
1542
1543
1544////////////////////////////////////////////////////////////////////////////////
Ben Murdochc5610432016-08-08 18:44:38 +01001545// A set of tests for elements kind reconfiguration case.
1546//
1547
1548// This test ensures that representation/field type generalization is correctly
1549// propagated from one branch of transition tree (|map2) to another (|map|).
1550//
1551// + - p0 - p1 - p2A - p3 - p4: |map|
1552// |
1553// ek
1554// |
1555// {} - p0 - p1 - p2B - p3 - p4: |map2|
1556//
1557// where "p2A" and "p2B" differ only in the representation/field type.
1558//
1559static void TestReconfigureElementsKind_GeneralizeRepresentation(
1560 Representation from_representation, Handle<FieldType> from_type,
1561 Representation to_representation, Handle<FieldType> to_type,
1562 Representation expected_representation, Handle<FieldType> expected_type) {
1563 Isolate* isolate = CcTest::i_isolate();
1564
1565 Expectations expectations(isolate, FAST_SMI_ELEMENTS);
1566
1567 // Create a map, add required properties to it and initialize expectations.
1568 Handle<Map> initial_map = Map::Create(isolate, 0);
1569 initial_map->set_elements_kind(FAST_SMI_ELEMENTS);
1570
1571 Handle<Map> map = initial_map;
1572 map = expectations.AsElementsKind(map, FAST_ELEMENTS);
1573 for (int i = 0; i < kPropCount; i++) {
1574 map = expectations.AddDataField(map, NONE, from_representation, from_type);
1575 }
1576 CHECK(!map->is_deprecated());
1577 CHECK(map->is_stable());
1578 CHECK(expectations.Check(*map));
1579
1580 // Create another branch in transition tree (property at index |kDiffProp|
1581 // has different representatio/field type), initialize expectations.
1582 const int kDiffProp = kPropCount / 2;
1583 Expectations expectations2(isolate, FAST_SMI_ELEMENTS);
1584
1585 Handle<Map> map2 = initial_map;
1586 for (int i = 0; i < kPropCount; i++) {
1587 if (i == kDiffProp) {
1588 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
1589 } else {
1590 map2 = expectations2.AddDataField(map2, NONE, from_representation,
1591 from_type);
1592 }
1593 }
1594 CHECK(!map2->is_deprecated());
1595 CHECK(map2->is_stable());
1596 CHECK(expectations2.Check(*map2));
1597
1598 Zone zone(isolate->allocator());
1599 Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate);
1600 CompilationInfo info(ArrayVector("testing"), isolate, &zone);
1601 CHECK(!info.dependencies()->HasAborted());
1602 info.dependencies()->AssumeFieldType(field_owner);
1603
1604 // Reconfigure elements kinds of |map2|, which should generalize
1605 // representations in |map|.
1606 Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS);
1607
1608 // |map2| should be left unchanged but marked unstable.
1609 CHECK(!map2->is_stable());
1610 CHECK(!map2->is_deprecated());
1611 CHECK_NE(*map2, *new_map);
1612 CHECK(expectations2.Check(*map2));
1613
1614 // |map| should be deprecated and |new_map| should match new expectations.
1615 expectations.SetDataField(kDiffProp, expected_representation, expected_type);
1616
1617 CHECK(map->is_deprecated());
1618 CHECK(!info.dependencies()->HasAborted());
1619 info.dependencies()->Rollback(); // Properly cleanup compilation info.
1620 CHECK_NE(*map, *new_map);
1621
1622 CHECK(!new_map->is_deprecated());
1623 CHECK(expectations.Check(*new_map));
1624
1625 // Update deprecated |map|, it should become |new_map|.
1626 Handle<Map> updated_map = Map::Update(map);
1627 CHECK_EQ(*new_map, *updated_map);
1628
1629 // Ensure Map::FindElementsKindTransitionedMap() is able to find the
1630 // transitioned map.
1631 {
1632 MapHandleList map_list;
1633 map_list.Add(updated_map);
1634 Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
1635 CHECK_EQ(*updated_map, transitioned_map);
1636 }
1637}
1638
1639// This test ensures that trivial representation/field type generalization
1640// (from HeapObject to HeapObject) is correctly propagated from one branch of
1641// transition tree (|map2|) to another (|map|).
1642//
1643// + - p0 - p1 - p2A - p3 - p4: |map|
1644// |
1645// ek
1646// |
1647// {} - p0 - p1 - p2B - p3 - p4: |map2|
1648//
1649// where "p2A" and "p2B" differ only in the representation/field type.
1650//
1651static void TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
1652 Representation from_representation, Handle<FieldType> from_type,
1653 Representation to_representation, Handle<FieldType> to_type,
1654 Representation expected_representation, Handle<FieldType> expected_type,
1655 bool expected_field_type_dependency = true) {
1656 Isolate* isolate = CcTest::i_isolate();
1657
1658 Expectations expectations(isolate, FAST_SMI_ELEMENTS);
1659
1660 // Create a map, add required properties to it and initialize expectations.
1661 Handle<Map> initial_map = Map::Create(isolate, 0);
1662 initial_map->set_elements_kind(FAST_SMI_ELEMENTS);
1663
1664 Handle<Map> map = initial_map;
1665 map = expectations.AsElementsKind(map, FAST_ELEMENTS);
1666 for (int i = 0; i < kPropCount; i++) {
1667 map = expectations.AddDataField(map, NONE, from_representation, from_type);
1668 }
1669 CHECK(!map->is_deprecated());
1670 CHECK(map->is_stable());
1671 CHECK(expectations.Check(*map));
1672
1673 // Create another branch in transition tree (property at index |kDiffProp|
1674 // has different attributes), initialize expectations.
1675 const int kDiffProp = kPropCount / 2;
1676 Expectations expectations2(isolate, FAST_SMI_ELEMENTS);
1677
1678 Handle<Map> map2 = initial_map;
1679 for (int i = 0; i < kPropCount; i++) {
1680 if (i == kDiffProp) {
1681 map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type);
1682 } else {
1683 map2 = expectations2.AddDataField(map2, NONE, from_representation,
1684 from_type);
1685 }
1686 }
1687 CHECK(!map2->is_deprecated());
1688 CHECK(map2->is_stable());
1689 CHECK(expectations2.Check(*map2));
1690
1691 Zone zone(isolate->allocator());
1692 Handle<Map> field_owner(map->FindFieldOwner(kDiffProp), isolate);
1693 CompilationInfo info(ArrayVector("testing"), isolate, &zone);
1694 CHECK(!info.dependencies()->HasAborted());
1695 info.dependencies()->AssumeFieldType(field_owner);
1696
1697 // Reconfigure elements kinds of |map2|, which should generalize
1698 // representations in |map|.
1699 Handle<Map> new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS);
1700
1701 // |map2| should be left unchanged but marked unstable.
1702 CHECK(!map2->is_stable());
1703 CHECK(!map2->is_deprecated());
1704 CHECK_NE(*map2, *new_map);
1705 CHECK(expectations2.Check(*map2));
1706
1707 // In trivial case |map| should be returned as a result of the elements
1708 // kind reconfiguration, respective field types should be generalized and
1709 // respective code dependencies should be invalidated. |map| should be NOT
1710 // deprecated and it should match new expectations.
1711 expectations.SetDataField(kDiffProp, expected_representation, expected_type);
1712 CHECK(!map->is_deprecated());
1713 CHECK_EQ(*map, *new_map);
1714 CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted());
1715 info.dependencies()->Rollback(); // Properly cleanup compilation info.
1716
1717 CHECK(!new_map->is_deprecated());
1718 CHECK(expectations.Check(*new_map));
1719
1720 Handle<Map> updated_map = Map::Update(map);
1721 CHECK_EQ(*new_map, *updated_map);
1722
1723 // Ensure Map::FindElementsKindTransitionedMap() is able to find the
1724 // transitioned map.
1725 {
1726 MapHandleList map_list;
1727 map_list.Add(updated_map);
1728 Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list);
1729 CHECK_EQ(*updated_map, transitioned_map);
1730 }
1731}
1732
1733TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToDouble) {
1734 CcTest::InitializeVM();
1735 v8::HandleScope scope(CcTest::isolate());
1736 Isolate* isolate = CcTest::i_isolate();
1737 Handle<FieldType> any_type = FieldType::Any(isolate);
1738
1739 TestReconfigureElementsKind_GeneralizeRepresentation(
1740 Representation::Smi(), any_type, Representation::Double(), any_type,
1741 Representation::Double(), any_type);
1742}
1743
1744TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToTagged) {
1745 CcTest::InitializeVM();
1746 v8::HandleScope scope(CcTest::isolate());
1747 Isolate* isolate = CcTest::i_isolate();
1748 Handle<FieldType> any_type = FieldType::Any(isolate);
1749 Handle<FieldType> value_type =
1750 FieldType::Class(Map::Create(isolate, 0), isolate);
1751
1752 TestReconfigureElementsKind_GeneralizeRepresentation(
1753 Representation::Smi(), any_type, Representation::HeapObject(), value_type,
1754 Representation::Tagged(), any_type);
1755}
1756
1757TEST(ReconfigureElementsKind_GeneralizeRepresentationDoubleToTagged) {
1758 CcTest::InitializeVM();
1759 v8::HandleScope scope(CcTest::isolate());
1760 Isolate* isolate = CcTest::i_isolate();
1761 Handle<FieldType> any_type = FieldType::Any(isolate);
1762 Handle<FieldType> value_type =
1763 FieldType::Class(Map::Create(isolate, 0), isolate);
1764
1765 TestReconfigureElementsKind_GeneralizeRepresentation(
1766 Representation::Double(), any_type, Representation::HeapObject(),
1767 value_type, Representation::Tagged(), any_type);
1768}
1769
1770TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjToHeapObj) {
1771 CcTest::InitializeVM();
1772 v8::HandleScope scope(CcTest::isolate());
1773 Isolate* isolate = CcTest::i_isolate();
1774 Handle<FieldType> any_type = FieldType::Any(isolate);
1775
1776 Handle<FieldType> current_type =
1777 FieldType::Class(Map::Create(isolate, 0), isolate);
1778
1779 Handle<FieldType> new_type =
1780 FieldType::Class(Map::Create(isolate, 0), isolate);
1781
1782 Handle<FieldType> expected_type = any_type;
1783
1784 TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
1785 Representation::HeapObject(), current_type, Representation::HeapObject(),
1786 new_type, Representation::HeapObject(), expected_type);
1787 current_type = expected_type;
1788
1789 new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
1790
1791 TestReconfigureElementsKind_GeneralizeRepresentationTrivial(
1792 Representation::HeapObject(), any_type, Representation::HeapObject(),
1793 new_type, Representation::HeapObject(), any_type, false);
1794}
1795
1796TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjectToTagged) {
1797 CcTest::InitializeVM();
1798 v8::HandleScope scope(CcTest::isolate());
1799 Isolate* isolate = CcTest::i_isolate();
1800 Handle<FieldType> any_type = FieldType::Any(isolate);
1801 Handle<FieldType> value_type =
1802 FieldType::Class(Map::Create(isolate, 0), isolate);
1803
1804 TestReconfigureElementsKind_GeneralizeRepresentation(
1805 Representation::HeapObject(), value_type, Representation::Smi(), any_type,
1806 Representation::Tagged(), any_type);
1807}
1808
1809////////////////////////////////////////////////////////////////////////////////
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001810// A set of tests checking split map deprecation.
1811//
1812
1813TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
1814 CcTest::InitializeVM();
1815 v8::HandleScope scope(CcTest::isolate());
1816 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001817 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818
1819 Expectations expectations(isolate);
1820
1821 // Create a map, add required properties to it and initialize expectations.
1822 Handle<Map> initial_map = Map::Create(isolate, 0);
1823 Handle<Map> map = initial_map;
1824 for (int i = 0; i < kPropCount; i++) {
1825 map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type);
1826 }
1827 CHECK(!map->is_deprecated());
1828 CHECK(map->is_stable());
1829
1830 // Generalize representation of property at index |kSplitProp|.
1831 const int kSplitProp = kPropCount / 2;
1832 Handle<Map> split_map;
1833 Handle<Map> map2 = initial_map;
1834 {
1835 for (int i = 0; i < kSplitProp + 1; i++) {
1836 if (i == kSplitProp) {
1837 split_map = map2;
1838 }
1839
1840 Handle<String> name = MakeName("prop", i);
1841 Map* target =
1842 TransitionArray::SearchTransition(*map2, kData, *name, NONE);
1843 CHECK(target != NULL);
1844 map2 = handle(target);
1845 }
1846
1847 map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE,
1848 Representation::Double(), any_type,
1849 FORCE_FIELD);
1850 expectations.SetDataField(kSplitProp, Representation::Double(), any_type);
1851
1852 CHECK(expectations.Check(*split_map, kSplitProp));
1853 CHECK(expectations.Check(*map2, kSplitProp + 1));
1854 }
1855
1856 // At this point |map| should be deprecated and disconnected from the
1857 // transition tree.
1858 CHECK(map->is_deprecated());
1859 CHECK(!split_map->is_deprecated());
1860 CHECK(map2->is_stable());
1861 CHECK(!map2->is_deprecated());
1862
1863 // Fill in transition tree of |map2| so that it can't have more transitions.
1864 for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) {
1865 CHECK(TransitionArray::CanHaveMoreTransitions(map2));
1866 Handle<String> name = MakeName("foo", i);
1867 Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(),
1868 INSERT_TRANSITION)
1869 .ToHandleChecked();
1870 }
1871 CHECK(!TransitionArray::CanHaveMoreTransitions(map2));
1872
1873 // Try to update |map|, since there is no place for propX transition at |map2|
1874 // |map| should become "copy-generalized".
1875 Handle<Map> updated_map = Map::Update(map);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001876 CHECK(updated_map->GetBackPointer()->IsUndefined(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001877
1878 for (int i = 0; i < kPropCount; i++) {
1879 expectations.SetDataField(i, Representation::Tagged(), any_type);
1880 }
1881 CHECK(expectations.Check(*updated_map));
1882}
1883
1884
1885////////////////////////////////////////////////////////////////////////////////
1886// A set of tests involving special transitions (such as elements kind
1887// transition, observed transition or prototype transition).
1888//
1889
1890// This test ensures that representation/field type generalization is correctly
1891// propagated from one branch of transition tree (|map2|) to another (|map|).
1892//
1893// p4B: |map2|
1894// |
1895// * - special transition
1896// |
1897// {} - p0 - p1 - p2A - p3 - p4A: |map|
1898//
1899// where "p4A" and "p4B" are exactly the same properties.
1900//
1901// TODO(ishell): unify this test template with
1902// TestReconfigureDataFieldAttribute_GeneralizeRepresentation once
1903// IS_PROTO_TRANS_ISSUE_FIXED and IS_NON_EQUIVALENT_TRANSITION_SUPPORTED are
1904// fixed.
1905template <typename TestConfig>
1906static void TestGeneralizeRepresentationWithSpecialTransition(
1907 TestConfig& config, Representation from_representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001908 Handle<FieldType> from_type, Representation to_representation,
1909 Handle<FieldType> to_type, Representation expected_representation,
1910 Handle<FieldType> expected_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001911 Isolate* isolate = CcTest::i_isolate();
1912
1913 Expectations expectations(isolate);
1914
1915 // Create a map, add required properties to it and initialize expectations.
1916 Handle<Map> initial_map = Map::Create(isolate, 0);
1917 Handle<Map> map = initial_map;
1918 for (int i = 0; i < kPropCount; i++) {
1919 map = expectations.AddDataField(map, NONE, from_representation, from_type);
1920 }
1921 CHECK(!map->is_deprecated());
1922 CHECK(map->is_stable());
1923 CHECK(expectations.Check(*map));
1924
Ben Murdochc5610432016-08-08 18:44:38 +01001925 Expectations expectations2 = expectations;
1926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001927 // Apply some special transition to |map|.
1928 CHECK(map->owns_descriptors());
Ben Murdochc5610432016-08-08 18:44:38 +01001929 Handle<Map> map2 = config.Transition(map, expectations2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001930
1931 // |map| should still match expectations.
1932 CHECK(!map->is_deprecated());
1933 CHECK(expectations.Check(*map));
1934
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001935 if (config.generalizes_representations()) {
1936 for (int i = 0; i < kPropCount; i++) {
1937 expectations2.GeneralizeRepresentation(i);
1938 }
1939 }
1940
1941 CHECK(!map2->is_deprecated());
1942 CHECK(map2->is_stable());
1943 CHECK(expectations2.Check(*map2));
1944
1945 // Create new maps by generalizing representation of propX field.
1946 Handle<Map> maps[kPropCount];
1947 for (int i = 0; i < kPropCount; i++) {
1948 Handle<Map> new_map = Map::ReconfigureProperty(
1949 map, i, kData, NONE, to_representation, to_type, FORCE_FIELD);
1950 maps[i] = new_map;
1951
1952 expectations.SetDataField(i, expected_representation, expected_type);
1953
1954 CHECK(map->is_deprecated());
1955 CHECK_NE(*map, *new_map);
1956 CHECK(i == 0 || maps[i - 1]->is_deprecated());
1957 CHECK(expectations.Check(*new_map));
1958
1959 Handle<Map> new_map2 = Map::Update(map2);
1960 CHECK(!new_map2->is_deprecated());
1961 CHECK(!new_map2->is_dictionary_map());
1962
1963 Handle<Map> tmp_map;
1964 if (Map::TryUpdate(map2).ToHandle(&tmp_map)) {
1965 // If Map::TryUpdate() manages to succeed the result must match the result
1966 // of Map::Update().
1967 CHECK_EQ(*new_map2, *tmp_map);
1968 }
1969
1970 if (config.is_non_equevalent_transition()) {
1971 // In case of non-equivalent transition currently we generalize all
1972 // representations.
1973 for (int i = 0; i < kPropCount; i++) {
1974 expectations2.GeneralizeRepresentation(i);
1975 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001976 CHECK(new_map2->GetBackPointer()->IsUndefined(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001977 CHECK(expectations2.Check(*new_map2));
1978 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001979 CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001980 CHECK(expectations2.Check(*new_map2));
1981 }
1982 }
1983
1984 Handle<Map> active_map = maps[kPropCount - 1];
1985 CHECK(!active_map->is_deprecated());
1986
1987 // Update all deprecated maps and check that they are now the same.
1988 Handle<Map> updated_map = Map::Update(map);
1989 CHECK_EQ(*active_map, *updated_map);
1990 for (int i = 0; i < kPropCount; i++) {
1991 updated_map = Map::Update(maps[i]);
1992 CHECK_EQ(*active_map, *updated_map);
1993 }
1994}
1995
1996
1997TEST(ElementsKindTransitionFromMapOwningDescriptor) {
1998 CcTest::InitializeVM();
1999 v8::HandleScope scope(CcTest::isolate());
2000 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002001 Handle<FieldType> any_type = FieldType::Any(isolate);
2002 Handle<FieldType> value_type =
2003 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002004
2005 struct TestConfig {
Ben Murdochc5610432016-08-08 18:44:38 +01002006 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2007 Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol());
2008 expectations.SetElementsKind(DICTIONARY_ELEMENTS);
2009 return Map::CopyForPreventExtensions(map, NONE, frozen_symbol,
2010 "CopyForPreventExtensions");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002011 }
2012 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2013 bool generalizes_representations() const { return false; }
Ben Murdochc5610432016-08-08 18:44:38 +01002014 bool is_non_equevalent_transition() const { return true; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002015 };
2016 TestConfig config;
2017 TestGeneralizeRepresentationWithSpecialTransition(
2018 config, Representation::Smi(), any_type, Representation::HeapObject(),
2019 value_type, Representation::Tagged(), any_type);
2020}
2021
2022
2023TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
2024 CcTest::InitializeVM();
2025 v8::HandleScope scope(CcTest::isolate());
2026 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002027 Handle<FieldType> any_type = FieldType::Any(isolate);
2028 Handle<FieldType> value_type =
2029 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002030
2031 struct TestConfig {
Ben Murdochc5610432016-08-08 18:44:38 +01002032 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002033 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002034 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002035
2036 // Add one more transition to |map| in order to prevent descriptors
2037 // ownership.
2038 CHECK(map->owns_descriptors());
2039 Map::CopyWithField(map, MakeString("foo"), any_type, NONE,
2040 Representation::Smi(), INSERT_TRANSITION)
2041 .ToHandleChecked();
2042 CHECK(!map->owns_descriptors());
2043
Ben Murdochc5610432016-08-08 18:44:38 +01002044 Handle<Symbol> frozen_symbol(map->GetHeap()->frozen_symbol());
2045 expectations.SetElementsKind(DICTIONARY_ELEMENTS);
2046 return Map::CopyForPreventExtensions(map, NONE, frozen_symbol,
2047 "CopyForPreventExtensions");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002048 }
2049 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2050 bool generalizes_representations() const { return false; }
2051 bool is_non_equevalent_transition() const { return true; }
2052 };
2053 TestConfig config;
2054 TestGeneralizeRepresentationWithSpecialTransition(
2055 config, Representation::Smi(), any_type, Representation::HeapObject(),
2056 value_type, Representation::Tagged(), any_type);
2057}
2058
2059
2060TEST(PrototypeTransitionFromMapOwningDescriptor) {
2061 CcTest::InitializeVM();
2062 v8::HandleScope scope(CcTest::isolate());
2063 Isolate* isolate = CcTest::i_isolate();
2064
Ben Murdoch097c5b22016-05-18 11:27:45 +01002065 Handle<FieldType> any_type = FieldType::Any(isolate);
2066 Handle<FieldType> value_type =
2067 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002068
2069 struct TestConfig {
2070 Handle<JSObject> prototype_;
2071
2072 TestConfig() {
2073 Isolate* isolate = CcTest::i_isolate();
2074 Factory* factory = isolate->factory();
2075 prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
2076 }
2077
Ben Murdochc5610432016-08-08 18:44:38 +01002078 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002079 return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE);
2080 }
2081 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2082 bool generalizes_representations() const {
2083 return !IS_PROTO_TRANS_ISSUE_FIXED;
2084 }
2085 bool is_non_equevalent_transition() const { return true; }
2086 };
2087 TestConfig config;
2088 TestGeneralizeRepresentationWithSpecialTransition(
2089 config, Representation::Smi(), any_type, Representation::HeapObject(),
2090 value_type, Representation::Tagged(), any_type);
2091}
2092
2093
2094TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
2095 CcTest::InitializeVM();
2096 v8::HandleScope scope(CcTest::isolate());
2097 Isolate* isolate = CcTest::i_isolate();
2098
Ben Murdoch097c5b22016-05-18 11:27:45 +01002099 Handle<FieldType> any_type = FieldType::Any(isolate);
2100 Handle<FieldType> value_type =
2101 FieldType::Class(Map::Create(isolate, 0), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002102
2103 struct TestConfig {
2104 Handle<JSObject> prototype_;
2105
2106 TestConfig() {
2107 Isolate* isolate = CcTest::i_isolate();
2108 Factory* factory = isolate->factory();
2109 prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
2110 }
2111
Ben Murdochc5610432016-08-08 18:44:38 +01002112 Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002113 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002114 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002115
2116 // Add one more transition to |map| in order to prevent descriptors
2117 // ownership.
2118 CHECK(map->owns_descriptors());
2119 Map::CopyWithField(map, MakeString("foo"), any_type, NONE,
2120 Representation::Smi(), INSERT_TRANSITION)
2121 .ToHandleChecked();
2122 CHECK(!map->owns_descriptors());
2123
2124 return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE);
2125 }
2126 // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2127 bool generalizes_representations() const {
2128 return !IS_PROTO_TRANS_ISSUE_FIXED;
2129 }
2130 bool is_non_equevalent_transition() const { return true; }
2131 };
2132 TestConfig config;
2133 TestGeneralizeRepresentationWithSpecialTransition(
2134 config, Representation::Smi(), any_type, Representation::HeapObject(),
2135 value_type, Representation::Tagged(), any_type);
2136}
2137
2138
2139////////////////////////////////////////////////////////////////////////////////
2140// A set of tests for higher level transitioning mechanics.
2141//
2142
2143struct TransitionToDataFieldOperator {
2144 Representation representation_;
2145 PropertyAttributes attributes_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002146 Handle<FieldType> heap_type_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002147 Handle<Object> value_;
2148
2149 TransitionToDataFieldOperator(Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002150 Handle<FieldType> heap_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002151 Handle<Object> value,
2152 PropertyAttributes attributes = NONE)
2153 : representation_(representation),
2154 attributes_(attributes),
2155 heap_type_(heap_type),
2156 value_(value) {}
2157
2158 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2159 return expectations.TransitionToDataField(map, attributes_, representation_,
2160 heap_type_, value_);
2161 }
2162};
2163
2164
2165struct TransitionToDataConstantOperator {
2166 PropertyAttributes attributes_;
2167 Handle<JSFunction> value_;
2168
2169 TransitionToDataConstantOperator(Handle<JSFunction> value,
2170 PropertyAttributes attributes = NONE)
2171 : attributes_(attributes), value_(value) {}
2172
2173 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2174 return expectations.TransitionToDataConstant(map, attributes_, value_);
2175 }
2176};
2177
2178
2179struct TransitionToAccessorConstantOperator {
2180 PropertyAttributes attributes_;
2181 Handle<AccessorPair> pair_;
2182
2183 TransitionToAccessorConstantOperator(Handle<AccessorPair> pair,
2184 PropertyAttributes attributes = NONE)
2185 : attributes_(attributes), pair_(pair) {}
2186
2187 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2188 return expectations.TransitionToAccessorConstant(map, attributes_, pair_);
2189 }
2190};
2191
2192
2193struct ReconfigureAsDataPropertyOperator {
2194 int descriptor_;
2195 Representation representation_;
2196 PropertyAttributes attributes_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002197 Handle<FieldType> heap_type_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002198
2199 ReconfigureAsDataPropertyOperator(int descriptor,
2200 Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002201 Handle<FieldType> heap_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002202 PropertyAttributes attributes = NONE)
2203 : descriptor_(descriptor),
2204 representation_(representation),
2205 attributes_(attributes),
2206 heap_type_(heap_type) {}
2207
2208 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2209 expectations.SetDataField(descriptor_, representation_, heap_type_);
2210 return Map::ReconfigureExistingProperty(map, descriptor_, kData,
2211 attributes_);
2212 }
2213};
2214
2215
2216struct ReconfigureAsAccessorPropertyOperator {
2217 int descriptor_;
2218 PropertyAttributes attributes_;
2219
2220 ReconfigureAsAccessorPropertyOperator(int descriptor,
2221 PropertyAttributes attributes = NONE)
2222 : descriptor_(descriptor), attributes_(attributes) {}
2223
2224 Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2225 expectations.SetAccessorField(descriptor_);
2226 return Map::ReconfigureExistingProperty(map, descriptor_, kAccessor,
2227 attributes_);
2228 }
2229};
2230
2231
2232// Checks that representation/field type generalization happened.
2233struct FieldGeneralizationChecker {
2234 int descriptor_;
2235 Representation representation_;
2236 PropertyAttributes attributes_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002237 Handle<FieldType> heap_type_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002238
2239 FieldGeneralizationChecker(int descriptor, Representation representation,
Ben Murdoch097c5b22016-05-18 11:27:45 +01002240 Handle<FieldType> heap_type,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002241 PropertyAttributes attributes = NONE)
2242 : descriptor_(descriptor),
2243 representation_(representation),
2244 attributes_(attributes),
2245 heap_type_(heap_type) {}
2246
2247 void Check(Expectations& expectations2, Handle<Map> map1, Handle<Map> map2) {
2248 CHECK(!map2->is_deprecated());
2249
2250 CHECK(map1->is_deprecated());
2251 CHECK_NE(*map1, *map2);
2252 Handle<Map> updated_map = Map::Update(map1);
2253 CHECK_EQ(*map2, *updated_map);
2254
2255 expectations2.SetDataField(descriptor_, attributes_, representation_,
2256 heap_type_);
2257 CHECK(expectations2.Check(*map2));
2258 }
2259};
2260
2261
2262// Checks that existing transition was taken as is.
2263struct SameMapChecker {
2264 void Check(Expectations& expectations, Handle<Map> map1, Handle<Map> map2) {
2265 CHECK(!map2->is_deprecated());
2266 CHECK_EQ(*map1, *map2);
2267 CHECK(expectations.Check(*map2));
2268 }
2269};
2270
2271
2272// Checks that both |map1| and |map2| should stays non-deprecated, this is
2273// the case when property kind is change.
2274struct PropertyKindReconfigurationChecker {
2275 void Check(Expectations& expectations, Handle<Map> map1, Handle<Map> map2) {
2276 CHECK(!map1->is_deprecated());
2277 CHECK(!map2->is_deprecated());
2278 CHECK_NE(*map1, *map2);
2279 CHECK(expectations.Check(*map2));
2280 }
2281};
2282
2283
2284// This test transitions to various property types under different
2285// circumstances.
2286// Plan:
2287// 1) create a |map| with p0..p3 properties.
2288// 2) create |map1| by adding "p4" to |map0|.
2289// 3) create |map2| by transition to "p4" from |map0|.
2290//
2291// + - p4B: |map2|
2292// |
2293// {} - p0 - p1 - pA - p3: |map|
2294// |
2295// + - p4A: |map1|
2296//
2297// where "p4A" and "p4B" differ only in the attributes.
2298//
2299template <typename TransitionOp1, typename TransitionOp2, typename Checker>
2300static void TestTransitionTo(TransitionOp1& transition_op1,
2301 TransitionOp2& transition_op2, Checker& checker) {
2302 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002303 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002304
2305 Expectations expectations(isolate);
2306
2307 // Create a map, add required properties to it and initialize expectations.
2308 Handle<Map> initial_map = Map::Create(isolate, 0);
2309 Handle<Map> map = initial_map;
2310 for (int i = 0; i < kPropCount - 1; i++) {
2311 map = expectations.AddDataField(map, NONE, Representation::Smi(), any_type);
2312 }
2313 CHECK(expectations.Check(*map));
2314
2315 Expectations expectations1 = expectations;
2316 Handle<Map> map1 = transition_op1.DoTransition(expectations1, map);
2317 CHECK(expectations1.Check(*map1));
2318
2319 Expectations expectations2 = expectations;
2320 Handle<Map> map2 = transition_op2.DoTransition(expectations2, map);
2321
2322 // Let the test customization do the check.
2323 checker.Check(expectations2, map1, map2);
2324}
2325
2326
2327TEST(TransitionDataFieldToDataField) {
2328 CcTest::InitializeVM();
2329 v8::HandleScope scope(CcTest::isolate());
2330 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002331 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002332
2333 Handle<Object> value1 = handle(Smi::FromInt(0), isolate);
2334 TransitionToDataFieldOperator transition_op1(Representation::Smi(), any_type,
2335 value1);
2336
2337 Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
2338 TransitionToDataFieldOperator transition_op2(Representation::Double(),
2339 any_type, value2);
2340
2341 FieldGeneralizationChecker checker(kPropCount - 1, Representation::Double(),
2342 any_type);
2343 TestTransitionTo(transition_op1, transition_op2, checker);
2344}
2345
2346
2347TEST(TransitionDataConstantToSameDataConstant) {
2348 CcTest::InitializeVM();
2349 v8::HandleScope scope(CcTest::isolate());
2350 Isolate* isolate = CcTest::i_isolate();
2351 Factory* factory = isolate->factory();
2352
2353 Handle<JSFunction> js_func = factory->NewFunction(factory->empty_string());
2354 TransitionToDataConstantOperator transition_op(js_func);
2355
2356 SameMapChecker checker;
2357 TestTransitionTo(transition_op, transition_op, checker);
2358}
2359
2360
2361TEST(TransitionDataConstantToAnotherDataConstant) {
2362 CcTest::InitializeVM();
2363 v8::HandleScope scope(CcTest::isolate());
2364 Isolate* isolate = CcTest::i_isolate();
2365 Factory* factory = isolate->factory();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002366 Handle<FieldType> function_type =
2367 FieldType::Class(isolate->sloppy_function_map(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002368
2369 Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string());
2370 TransitionToDataConstantOperator transition_op1(js_func1);
2371
2372 Handle<JSFunction> js_func2 = factory->NewFunction(factory->empty_string());
2373 TransitionToDataConstantOperator transition_op2(js_func2);
2374
2375 FieldGeneralizationChecker checker(
2376 kPropCount - 1, Representation::HeapObject(), function_type);
2377 TestTransitionTo(transition_op1, transition_op2, checker);
2378}
2379
2380
2381TEST(TransitionDataConstantToDataField) {
2382 CcTest::InitializeVM();
2383 v8::HandleScope scope(CcTest::isolate());
2384 Isolate* isolate = CcTest::i_isolate();
2385 Factory* factory = isolate->factory();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002386 Handle<FieldType> any_type = FieldType::Any(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002387
2388 Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string());
2389 TransitionToDataConstantOperator transition_op1(js_func1);
2390
2391 Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
2392 TransitionToDataFieldOperator transition_op2(Representation::Double(),
2393 any_type, value2);
2394
2395 FieldGeneralizationChecker checker(kPropCount - 1, Representation::Tagged(),
2396 any_type);
2397 TestTransitionTo(transition_op1, transition_op2, checker);
2398}
2399
2400
2401TEST(TransitionAccessorConstantToSameAccessorConstant) {
2402 CcTest::InitializeVM();
2403 v8::HandleScope scope(CcTest::isolate());
2404
2405 Handle<AccessorPair> pair = CreateAccessorPair(true, true);
2406 TransitionToAccessorConstantOperator transition_op(pair);
2407
2408 SameMapChecker checker;
2409 TestTransitionTo(transition_op, transition_op, checker);
2410}
2411
2412
2413// TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported.
2414// TEST(TransitionAccessorConstantToAnotherAccessorConstant)