Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <stdlib.h>
6 : #include <utility>
7 :
8 : #include "test/cctest/test-api.h"
9 :
10 : #include "src/v8.h"
11 :
12 : #include "src/compilation-cache.h"
13 : #include "src/compiler/compilation-dependencies.h"
14 : #include "src/compiler/js-heap-broker.h"
15 : #include "src/execution.h"
16 : #include "src/field-type.h"
17 : #include "src/global-handles.h"
18 : #include "src/heap/factory.h"
19 : #include "src/ic/stub-cache.h"
20 : #include "src/macro-assembler.h"
21 : #include "src/objects-inl.h"
22 : #include "src/objects/heap-number-inl.h"
23 : #include "src/objects/struct-inl.h"
24 : #include "src/optimized-compilation-info.h"
25 : #include "src/ostreams.h"
26 : #include "src/property.h"
27 : #include "src/transitions.h"
28 :
29 : namespace v8 {
30 : namespace internal {
31 : namespace compiler {
32 : namespace test_field_type_tracking {
33 :
34 : // TODO(ishell): fix this once TransitionToPrototype stops generalizing
35 : // all field representations (similar to crbug/448711 where elements kind
36 : // and observed transitions caused generalization of all fields).
37 : const bool IS_PROTO_TRANS_ISSUE_FIXED = false;
38 :
39 :
40 : // TODO(ishell): fix this once TransitionToAccessorProperty is able to always
41 : // keep map in fast mode.
42 : const bool IS_ACCESSOR_FIELD_SUPPORTED = false;
43 :
44 :
45 : // Number of properties used in the tests.
46 : const int kPropCount = 7;
47 :
48 :
49 : //
50 : // Helper functions.
51 : //
52 :
53 : static Handle<String> MakeString(const char* str) {
54 : Isolate* isolate = CcTest::i_isolate();
55 : Factory* factory = isolate->factory();
56 13465 : return factory->InternalizeUtf8String(str);
57 : }
58 :
59 :
60 13445 : static Handle<String> MakeName(const char* str, int suffix) {
61 : EmbeddedVector<char, 128> buffer;
62 13445 : SNPrintF(buffer, "%s%d", str, suffix);
63 26890 : return MakeString(buffer.start());
64 : }
65 :
66 :
67 40 : static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
68 : bool with_setter) {
69 : Isolate* isolate = CcTest::i_isolate();
70 : Factory* factory = isolate->factory();
71 40 : Handle<AccessorPair> pair = factory->NewAccessorPair();
72 40 : Handle<String> empty_string = factory->empty_string();
73 40 : if (with_getter) {
74 40 : Handle<JSFunction> func = factory->NewFunctionForTest(empty_string);
75 80 : pair->set_getter(*func);
76 : }
77 40 : if (with_setter) {
78 40 : Handle<JSFunction> func = factory->NewFunctionForTest(empty_string);
79 80 : pair->set_setter(*func);
80 : }
81 40 : return pair;
82 : }
83 :
84 : // Check cached migration target map after Map::Update() and Map::TryUpdate()
85 755 : static void CheckMigrationTarget(Isolate* isolate, Map old_map, Map new_map) {
86 : Map target = TransitionsAccessor(isolate, handle(old_map, isolate))
87 755 : .GetMigrationTarget();
88 1510 : if (target.is_null()) return;
89 0 : CHECK_EQ(new_map, target);
90 0 : CHECK_EQ(Map::TryUpdateSlow(isolate, old_map), target);
91 : }
92 :
93 : class Expectations {
94 : static const int MAX_PROPERTIES = 10;
95 : Isolate* isolate_;
96 : ElementsKind elements_kind_;
97 : PropertyKind kinds_[MAX_PROPERTIES];
98 : PropertyLocation locations_[MAX_PROPERTIES];
99 : PropertyConstness constnesses_[MAX_PROPERTIES];
100 : PropertyAttributes attributes_[MAX_PROPERTIES];
101 : Representation representations_[MAX_PROPERTIES];
102 : // FieldType for kField, value for DATA_CONSTANT and getter for
103 : // ACCESSOR_CONSTANT.
104 : Handle<Object> values_[MAX_PROPERTIES];
105 : // Setter for ACCESSOR_CONSTANT.
106 : Handle<Object> setter_values_[MAX_PROPERTIES];
107 : int number_of_properties_;
108 :
109 : public:
110 800 : explicit Expectations(Isolate* isolate, ElementsKind elements_kind)
111 : : isolate_(isolate),
112 : elements_kind_(elements_kind),
113 24800 : number_of_properties_(0) {}
114 :
115 560 : explicit Expectations(Isolate* isolate)
116 : : Expectations(
117 : isolate,
118 1680 : isolate->object_function()->initial_map()->elements_kind()) {}
119 :
120 7175 : void Init(int index, PropertyKind kind, PropertyAttributes attributes,
121 : PropertyConstness constness, PropertyLocation location,
122 : Representation representation, Handle<Object> value) {
123 7175 : CHECK(index < MAX_PROPERTIES);
124 7175 : kinds_[index] = kind;
125 7175 : locations_[index] = location;
126 14295 : if (kind == kData && location == kField &&
127 7120 : IsTransitionableFastElementsKind(elements_kind_)) {
128 : // Maps with transitionable elements kinds must have the most general
129 : // field type.
130 1800 : value = FieldType::Any(isolate_);
131 : }
132 7175 : constnesses_[index] = constness;
133 7175 : attributes_[index] = attributes;
134 7175 : representations_[index] = representation;
135 7175 : values_[index] = value;
136 7175 : }
137 :
138 0 : void Print() const {
139 0 : StdoutStream os;
140 0 : os << "Expectations: #" << number_of_properties_ << "\n";
141 0 : for (int i = 0; i < number_of_properties_; i++) {
142 0 : os << " " << i << ": ";
143 0 : os << "Descriptor @ ";
144 :
145 0 : if (kinds_[i] == kData) {
146 0 : os << Brief(*values_[i]);
147 : } else {
148 : // kAccessor
149 0 : os << "(get: " << Brief(*values_[i])
150 0 : << ", set: " << Brief(*setter_values_[i]) << ") ";
151 : }
152 :
153 0 : os << " (";
154 0 : if (constnesses_[i] == PropertyConstness::kConst) os << "const ";
155 0 : os << (kinds_[i] == kData ? "data " : "accessor ");
156 0 : if (locations_[i] == kField) {
157 0 : os << "field"
158 0 : << ": " << representations_[i].Mnemonic();
159 : } else {
160 0 : os << "descriptor";
161 : }
162 0 : os << ", attrs: " << attributes_[i] << ")\n";
163 : }
164 0 : os << "\n";
165 0 : }
166 :
167 : void SetElementsKind(ElementsKind elements_kind) {
168 30 : elements_kind_ = elements_kind;
169 : }
170 :
171 : Handle<FieldType> GetFieldType(int index) {
172 : CHECK(index < MAX_PROPERTIES);
173 : CHECK_EQ(kField, locations_[index]);
174 : return Handle<FieldType>::cast(values_[index]);
175 : }
176 :
177 : void SetDataField(int index, PropertyAttributes attrs,
178 : PropertyConstness constness, Representation representation,
179 : Handle<FieldType> field_type) {
180 7070 : Init(index, kData, attrs, constness, kField, representation, field_type);
181 : }
182 :
183 1405 : void SetDataField(int index, PropertyConstness constness,
184 : Representation representation,
185 : Handle<FieldType> field_type) {
186 : SetDataField(index, attributes_[index], constness, representation,
187 1405 : field_type);
188 1405 : }
189 :
190 : void SetAccessorField(int index, PropertyAttributes attrs) {
191 : Init(index, kAccessor, attrs, PropertyConstness::kConst, kDescriptor,
192 : Representation::Tagged(), FieldType::Any(isolate_));
193 : }
194 :
195 : void SetAccessorField(int index) {
196 : SetAccessorField(index, attributes_[index]);
197 : }
198 :
199 50 : void SetDataConstant(int index, PropertyAttributes attrs,
200 : Handle<JSFunction> value) {
201 : if (FLAG_track_constant_fields) {
202 100 : Handle<FieldType> field_type(FieldType::Class(value->map()), isolate_);
203 : Init(index, kData, attrs, PropertyConstness::kConst, kField,
204 50 : Representation::HeapObject(), field_type);
205 :
206 : } else {
207 : Init(index, kData, attrs, PropertyConstness::kConst, kDescriptor,
208 : Representation::HeapObject(), value);
209 : }
210 50 : }
211 :
212 : void SetDataConstant(int index, Handle<JSFunction> value) {
213 : SetDataConstant(index, attributes_[index], value);
214 : }
215 :
216 : void SetAccessorConstant(int index, PropertyAttributes attrs,
217 : Handle<Object> getter, Handle<Object> setter) {
218 : Init(index, kAccessor, attrs, PropertyConstness::kConst, kDescriptor,
219 55 : Representation::Tagged(), getter);
220 55 : setter_values_[index] = setter;
221 : }
222 :
223 : void SetAccessorConstantComponent(int index, PropertyAttributes attrs,
224 : AccessorComponent component,
225 : Handle<Object> accessor) {
226 : CHECK_EQ(kAccessor, kinds_[index]);
227 : CHECK_EQ(kDescriptor, locations_[index]);
228 : CHECK(index < number_of_properties_);
229 : if (component == ACCESSOR_GETTER) {
230 : values_[index] = accessor;
231 : } else {
232 : setter_values_[index] = accessor;
233 : }
234 : }
235 :
236 50 : void SetAccessorConstant(int index, PropertyAttributes attrs,
237 : Handle<AccessorPair> pair) {
238 50 : Handle<Object> getter = handle(pair->getter(), isolate_);
239 50 : Handle<Object> setter = handle(pair->setter(), isolate_);
240 : SetAccessorConstant(index, attrs, getter, setter);
241 50 : }
242 :
243 5 : void SetAccessorConstant(int index, Handle<Object> getter,
244 : Handle<Object> setter) {
245 5 : SetAccessorConstant(index, attributes_[index], getter, setter);
246 5 : }
247 :
248 5 : void SetAccessorConstant(int index, Handle<AccessorPair> pair) {
249 10 : Handle<Object> getter = handle(pair->getter(), isolate_);
250 10 : Handle<Object> setter = handle(pair->setter(), isolate_);
251 5 : SetAccessorConstant(index, getter, setter);
252 5 : }
253 :
254 595 : void GeneralizeField(int index) {
255 595 : CHECK(index < number_of_properties_);
256 595 : representations_[index] = Representation::Tagged();
257 595 : if (locations_[index] == kField) {
258 590 : values_[index] = FieldType::Any(isolate_);
259 : }
260 595 : }
261 :
262 16395 : bool Check(DescriptorArray descriptors, int descriptor) const {
263 16395 : PropertyDetails details = descriptors->GetDetails(descriptor);
264 :
265 16395 : if (details.kind() != kinds_[descriptor]) return false;
266 16395 : if (details.location() != locations_[descriptor]) return false;
267 16395 : if (details.constness() != constnesses_[descriptor]) return false;
268 :
269 16395 : PropertyAttributes expected_attributes = attributes_[descriptor];
270 16395 : if (details.attributes() != expected_attributes) return false;
271 :
272 16395 : Representation expected_representation = representations_[descriptor];
273 :
274 16395 : if (!details.representation().Equals(expected_representation)) return false;
275 :
276 16395 : Object expected_value = *values_[descriptor];
277 16395 : if (details.location() == kField) {
278 16280 : if (details.kind() == kData) {
279 16280 : FieldType type = descriptors->GetFieldType(descriptor);
280 32560 : return FieldType::cast(expected_value) == type;
281 : } else {
282 : // kAccessor
283 0 : UNREACHABLE();
284 : }
285 : } else {
286 115 : Object value = descriptors->GetStrongValue(descriptor);
287 : // kDescriptor
288 115 : if (details.kind() == kData) {
289 0 : CHECK(!FLAG_track_constant_fields);
290 : return value == expected_value;
291 : } else {
292 : // kAccessor
293 115 : if (value == expected_value) return true;
294 115 : if (!value->IsAccessorPair()) return false;
295 : AccessorPair pair = AccessorPair::cast(value);
296 230 : return pair->Equals(expected_value, *setter_values_[descriptor]);
297 : }
298 : }
299 : UNREACHABLE();
300 : }
301 :
302 2415 : bool Check(Map map, int expected_nof) const {
303 2415 : CHECK_EQ(elements_kind_, map->elements_kind());
304 2415 : CHECK(number_of_properties_ <= MAX_PROPERTIES);
305 2415 : CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors());
306 2415 : CHECK(!map->is_dictionary_map());
307 :
308 2415 : DescriptorArray descriptors = map->instance_descriptors();
309 2415 : CHECK(expected_nof <= number_of_properties_);
310 16395 : for (int i = 0; i < expected_nof; i++) {
311 16395 : if (!Check(descriptors, i)) {
312 0 : Print();
313 : #ifdef OBJECT_PRINT
314 : descriptors->Print();
315 : #endif
316 0 : Check(descriptors, i);
317 0 : return false;
318 : }
319 : }
320 : return true;
321 : }
322 :
323 2345 : bool Check(Map map) const { return Check(map, number_of_properties_); }
324 :
325 : //
326 : // Helper methods for initializing expectations and adding properties to
327 : // given |map|.
328 : //
329 :
330 120 : Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) {
331 120 : elements_kind_ = elements_kind;
332 120 : map = Map::AsElementsKind(isolate_, map, elements_kind);
333 120 : CHECK_EQ(elements_kind_, map->elements_kind());
334 120 : return map;
335 : }
336 :
337 : void ChangeAttributesForAllProperties(PropertyAttributes attributes) {
338 210 : for (int i = 0; i < number_of_properties_; i++) {
339 210 : attributes_[i] = attributes;
340 : }
341 : }
342 :
343 5315 : Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
344 : PropertyConstness constness,
345 : Representation representation,
346 : Handle<FieldType> field_type) {
347 5315 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
348 5315 : int property_index = number_of_properties_++;
349 : SetDataField(property_index, attributes, constness, representation,
350 : field_type);
351 :
352 5315 : Handle<String> name = MakeName("prop", property_index);
353 : return Map::CopyWithField(isolate_, map, name, field_type, attributes,
354 10630 : constness, representation, INSERT_TRANSITION)
355 15945 : .ToHandleChecked();
356 : }
357 :
358 25 : Handle<Map> AddDataConstant(Handle<Map> map, PropertyAttributes attributes,
359 : Handle<JSFunction> value) {
360 25 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
361 25 : int property_index = number_of_properties_++;
362 25 : SetDataConstant(property_index, attributes, value);
363 :
364 25 : Handle<String> name = MakeName("prop", property_index);
365 : return Map::CopyWithConstant(isolate_, map, name, value, attributes,
366 50 : INSERT_TRANSITION)
367 75 : .ToHandleChecked();
368 : }
369 :
370 15 : Handle<Map> TransitionToDataField(Handle<Map> map,
371 : PropertyAttributes attributes,
372 : PropertyConstness constness,
373 : Representation representation,
374 : Handle<FieldType> heap_type,
375 : Handle<Object> value) {
376 15 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
377 15 : int property_index = number_of_properties_++;
378 : SetDataField(property_index, attributes, constness, representation,
379 : heap_type);
380 :
381 15 : Handle<String> name = MakeName("prop", property_index);
382 : return Map::TransitionToDataProperty(isolate_, map, name, value, attributes,
383 15 : constness, StoreOrigin::kNamed);
384 : }
385 :
386 25 : Handle<Map> TransitionToDataConstant(Handle<Map> map,
387 : PropertyAttributes attributes,
388 : Handle<JSFunction> value) {
389 25 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
390 25 : int property_index = number_of_properties_++;
391 25 : SetDataConstant(property_index, attributes, value);
392 :
393 25 : Handle<String> name = MakeName("prop", property_index);
394 : return Map::TransitionToDataProperty(isolate_, map, name, value, attributes,
395 : PropertyConstness::kConst,
396 25 : StoreOrigin::kNamed);
397 : }
398 :
399 315 : Handle<Map> FollowDataTransition(Handle<Map> map,
400 : PropertyAttributes attributes,
401 : PropertyConstness constness,
402 : Representation representation,
403 : Handle<FieldType> heap_type) {
404 315 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
405 315 : int property_index = number_of_properties_++;
406 : SetDataField(property_index, attributes, constness, representation,
407 : heap_type);
408 :
409 315 : Handle<String> name = MakeName("prop", property_index);
410 : Map target = TransitionsAccessor(isolate_, map)
411 315 : .SearchTransition(*name, kData, attributes);
412 315 : CHECK(!target.is_null());
413 630 : return handle(target, isolate_);
414 : }
415 :
416 40 : Handle<Map> AddAccessorConstant(Handle<Map> map,
417 : PropertyAttributes attributes,
418 : Handle<AccessorPair> pair) {
419 40 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
420 40 : int property_index = number_of_properties_++;
421 40 : SetAccessorConstant(property_index, attributes, pair);
422 :
423 40 : Handle<String> name = MakeName("prop", property_index);
424 :
425 40 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
426 40 : return Map::CopyInsertDescriptor(isolate_, map, &d, INSERT_TRANSITION);
427 : }
428 :
429 : Handle<Map> AddAccessorConstant(Handle<Map> map,
430 : PropertyAttributes attributes,
431 : Handle<Object> getter,
432 : Handle<Object> setter) {
433 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
434 : int property_index = number_of_properties_++;
435 : SetAccessorConstant(property_index, attributes, getter, setter);
436 :
437 : Handle<String> name = MakeName("prop", property_index);
438 :
439 : CHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
440 : Factory* factory = isolate_->factory();
441 :
442 : if (!getter->IsNull(isolate_)) {
443 : Handle<AccessorPair> pair = factory->NewAccessorPair();
444 : pair->SetComponents(*getter, *factory->null_value());
445 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
446 : map = Map::CopyInsertDescriptor(isolate_, map, &d, INSERT_TRANSITION);
447 : }
448 : if (!setter->IsNull(isolate_)) {
449 : Handle<AccessorPair> pair = factory->NewAccessorPair();
450 : pair->SetComponents(*getter, *setter);
451 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
452 : map = Map::CopyInsertDescriptor(isolate_, map, &d, INSERT_TRANSITION);
453 : }
454 : return map;
455 : }
456 :
457 10 : Handle<Map> TransitionToAccessorConstant(Handle<Map> map,
458 : PropertyAttributes attributes,
459 : Handle<AccessorPair> pair) {
460 10 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
461 10 : int property_index = number_of_properties_++;
462 10 : SetAccessorConstant(property_index, attributes, pair);
463 :
464 10 : Handle<String> name = MakeName("prop", property_index);
465 :
466 : Isolate* isolate = CcTest::i_isolate();
467 : Handle<Object> getter(pair->getter(), isolate);
468 : Handle<Object> setter(pair->setter(), isolate);
469 :
470 : int descriptor =
471 20 : map->instance_descriptors()->SearchWithCache(isolate, *name, *map);
472 : map = Map::TransitionToAccessorProperty(isolate, map, name, descriptor,
473 10 : getter, setter, attributes);
474 10 : CHECK(!map->is_deprecated());
475 10 : CHECK(!map->is_dictionary_map());
476 10 : return map;
477 : }
478 : };
479 :
480 :
481 : ////////////////////////////////////////////////////////////////////////////////
482 : // A set of tests for property reconfiguration that makes new transition tree
483 : // branch.
484 : //
485 :
486 25880 : TEST(ReconfigureAccessorToNonExistingDataField) {
487 5 : CcTest::InitializeVM();
488 5 : v8::HandleScope scope(CcTest::isolate());
489 : Isolate* isolate = CcTest::i_isolate();
490 :
491 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
492 5 : Handle<FieldType> none_type = FieldType::None(isolate);
493 5 : Handle<AccessorPair> pair = CreateAccessorPair(true, true);
494 :
495 5 : Expectations expectations(isolate);
496 :
497 : // Create a map, add required properties to it and initialize expectations.
498 5 : Handle<Map> initial_map = Map::Create(isolate, 0);
499 5 : Handle<Map> map = initial_map;
500 5 : map = expectations.AddAccessorConstant(map, NONE, pair);
501 :
502 5 : CHECK(!map->is_deprecated());
503 5 : CHECK(map->is_stable());
504 5 : CHECK(expectations.Check(*map));
505 :
506 : Handle<Map> new_map = Map::ReconfigureProperty(
507 5 : isolate, map, 0, kData, NONE, Representation::None(), none_type);
508 : // |map| did not change except marked unstable.
509 5 : CHECK(!map->is_deprecated());
510 5 : CHECK(!map->is_stable());
511 5 : CHECK(expectations.Check(*map));
512 :
513 : // Property kind reconfiguration always makes the field mutable.
514 : expectations.SetDataField(0, NONE, PropertyConstness::kMutable,
515 : Representation::None(), none_type);
516 :
517 5 : CHECK(!new_map->is_deprecated());
518 5 : CHECK(new_map->is_stable());
519 5 : CHECK(expectations.Check(*new_map));
520 :
521 : Handle<Map> new_map2 = Map::ReconfigureProperty(
522 5 : isolate, map, 0, kData, NONE, Representation::None(), none_type);
523 15 : CHECK_EQ(*new_map, *new_map2);
524 :
525 : Handle<Object> value(Smi::kZero, isolate);
526 : Handle<Map> prepared_map = Map::PrepareForDataProperty(
527 5 : isolate, new_map, 0, PropertyConstness::kConst, value);
528 : // None to Smi generalization is trivial, map does not change.
529 15 : CHECK_EQ(*new_map, *prepared_map);
530 :
531 : expectations.SetDataField(0, NONE, PropertyConstness::kMutable,
532 : Representation::Smi(), any_type);
533 5 : CHECK(prepared_map->is_stable());
534 5 : CHECK(expectations.Check(*prepared_map));
535 :
536 : // Now create an object with |map|, migrate it to |prepared_map| and ensure
537 : // that the data property is uninitialized.
538 : Factory* factory = isolate->factory();
539 5 : Handle<JSObject> obj = factory->NewJSObjectFromMap(map);
540 5 : JSObject::MigrateToMap(obj, prepared_map);
541 5 : FieldIndex index = FieldIndex::ForDescriptor(*prepared_map, 0);
542 10 : CHECK(obj->RawFastPropertyAt(index)->IsUninitialized(isolate));
543 : #ifdef VERIFY_HEAP
544 : obj->ObjectVerify(isolate);
545 : #endif
546 5 : }
547 :
548 :
549 : // This test checks that the LookupIterator machinery involved in
550 : // JSObject::SetOwnPropertyIgnoreAttributes() does not try to migrate object
551 : // to a map with a property with None representation.
552 25880 : TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {
553 5 : CcTest::InitializeVM();
554 5 : v8::HandleScope scope(CcTest::isolate());
555 : Isolate* isolate = CcTest::i_isolate();
556 : Factory* factory = isolate->factory();
557 :
558 : CompileRun(
559 : "function getter() { return 1; };"
560 : "function setter() {};"
561 : "var o = {};"
562 : "Object.defineProperty(o, 'foo', "
563 : " { get: getter, set: setter, "
564 : " configurable: true, enumerable: true});");
565 :
566 5 : Handle<String> foo_str = factory->InternalizeUtf8String("foo");
567 5 : Handle<String> obj_name = factory->InternalizeUtf8String("o");
568 :
569 : Handle<Object> obj_value =
570 10 : Object::GetProperty(isolate, isolate->global_object(), obj_name)
571 10 : .ToHandleChecked();
572 10 : CHECK(obj_value->IsJSObject());
573 5 : Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
574 :
575 5 : CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
576 15 : CHECK(
577 : obj->map()->instance_descriptors()->GetStrongValue(0)->IsAccessorPair());
578 :
579 : Handle<Object> value(Smi::FromInt(42), isolate);
580 10 : JSObject::SetOwnPropertyIgnoreAttributes(obj, foo_str, value, NONE).Check();
581 :
582 : // Check that the property contains |value|.
583 5 : CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
584 5 : FieldIndex index = FieldIndex::ForDescriptor(obj->map(), 0);
585 5 : Object the_value = obj->RawFastPropertyAt(index);
586 5 : CHECK(the_value->IsSmi());
587 5 : CHECK_EQ(42, Smi::ToInt(the_value));
588 5 : }
589 :
590 :
591 : ////////////////////////////////////////////////////////////////////////////////
592 : // A set of tests for field generalization case.
593 : //
594 :
595 : // <Constness, Representation, FieldType> data.
596 : struct CRFTData {
597 : PropertyConstness constness;
598 : Representation representation;
599 : Handle<FieldType> type;
600 : };
601 :
602 : // This test ensures that field generalization at |property_index| is done
603 : // correctly independently of the fact that the |map| is detached from
604 : // transition tree or not.
605 : //
606 : // {} - p0 - p1 - p2: |detach_point_map|
607 : // |
608 : // X - detached at |detach_property_at_index|
609 : // |
610 : // + - p3 - p4: |map|
611 : //
612 : // Detaching does not happen if |detach_property_at_index| is -1.
613 : //
614 240 : static void TestGeneralizeField(int detach_property_at_index,
615 : int property_index, const CRFTData& from,
616 : const CRFTData& to, const CRFTData& expected,
617 : bool expected_deprecation,
618 : bool expected_field_type_dependency) {
619 240 : Isolate* isolate = CcTest::i_isolate();
620 240 : Handle<FieldType> any_type = FieldType::Any(isolate);
621 :
622 240 : CHECK(detach_property_at_index >= -1 &&
623 : detach_property_at_index < kPropCount);
624 240 : CHECK_LT(property_index, kPropCount);
625 240 : CHECK_NE(detach_property_at_index, property_index);
626 :
627 240 : const bool is_detached_map = detach_property_at_index >= 0;
628 :
629 240 : Expectations expectations(isolate);
630 :
631 : // Create a map, add required properties to it and initialize expectations.
632 240 : Handle<Map> initial_map = Map::Create(isolate, 0);
633 240 : Handle<Map> map = initial_map;
634 : Handle<Map> detach_point_map;
635 1920 : for (int i = 0; i < kPropCount; i++) {
636 1680 : if (i == property_index) {
637 : map = expectations.AddDataField(map, NONE, from.constness,
638 240 : from.representation, from.type);
639 : } else {
640 : map = expectations.AddDataField(map, NONE, kDefaultFieldConstness,
641 1440 : Representation::Smi(), any_type);
642 1440 : if (i == detach_property_at_index) {
643 : detach_point_map = map;
644 : }
645 : }
646 : }
647 240 : CHECK(!map->is_deprecated());
648 240 : CHECK(map->is_stable());
649 240 : CHECK(expectations.Check(*map));
650 :
651 240 : Zone zone(isolate->allocator(), ZONE_NAME);
652 :
653 240 : if (is_detached_map) {
654 : detach_point_map = Map::ReconfigureProperty(
655 : isolate, detach_point_map, detach_property_at_index, kData, NONE,
656 60 : Representation::Tagged(), any_type);
657 : expectations.SetDataField(detach_property_at_index, kDefaultFieldConstness,
658 60 : Representation::Tagged(), any_type);
659 60 : CHECK(map->is_deprecated());
660 60 : CHECK(expectations.Check(*detach_point_map,
661 : detach_point_map->NumberOfOwnDescriptors()));
662 : }
663 :
664 : // Create new maps by generalizing representation of propX field.
665 480 : CanonicalHandleScope canonical(isolate);
666 240 : JSHeapBroker broker(isolate, &zone);
667 240 : CompilationDependencies dependencies(isolate, &zone);
668 : MapRef map_ref(&broker, map);
669 240 : map_ref.SerializeOwnDescriptors();
670 240 : dependencies.DependOnFieldType(map_ref, property_index);
671 :
672 : Handle<Map> field_owner(map->FindFieldOwner(isolate, property_index),
673 480 : isolate);
674 : Handle<Map> new_map = Map::ReconfigureProperty(
675 240 : isolate, map, property_index, kData, NONE, to.representation, to.type);
676 :
677 : expectations.SetDataField(property_index, expected.constness,
678 240 : expected.representation, expected.type);
679 :
680 240 : CHECK(!new_map->is_deprecated());
681 240 : CHECK(expectations.Check(*new_map));
682 :
683 240 : if (is_detached_map) {
684 60 : CHECK(!map->is_stable());
685 60 : CHECK(map->is_deprecated());
686 180 : CHECK_NE(*map, *new_map);
687 70 : CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
688 : !dependencies.AreValid());
689 :
690 180 : } else if (expected_deprecation) {
691 75 : CHECK(!map->is_stable());
692 75 : CHECK(map->is_deprecated());
693 75 : CHECK(field_owner->is_deprecated());
694 225 : CHECK_NE(*map, *new_map);
695 75 : CHECK(dependencies.AreValid());
696 :
697 : } else {
698 105 : CHECK(!field_owner->is_deprecated());
699 105 : CHECK(map->is_stable()); // Map did not change, must be left stable.
700 315 : CHECK_EQ(*map, *new_map);
701 :
702 105 : CHECK_EQ(expected_field_type_dependency, !dependencies.AreValid());
703 : }
704 :
705 : {
706 : // Check that all previous maps are not stable.
707 240 : Map tmp = *new_map;
708 : while (true) {
709 1920 : Object back = tmp->GetBackPointer();
710 1920 : if (back->IsUndefined(isolate)) break;
711 1680 : tmp = Map::cast(back);
712 1680 : CHECK(!tmp->is_stable());
713 1680 : }
714 : }
715 :
716 : // Update all deprecated maps and check that they are now the same.
717 240 : Handle<Map> updated_map = Map::Update(isolate, map);
718 720 : CHECK_EQ(*new_map, *updated_map);
719 480 : CheckMigrationTarget(isolate, *map, *updated_map);
720 240 : }
721 :
722 50 : static void TestGeneralizeField(const CRFTData& from, const CRFTData& to,
723 : const CRFTData& expected,
724 : bool expected_deprecation,
725 : bool expected_field_type_dependency) {
726 : // Check the cases when the map being reconfigured is a part of the
727 : // transition tree.
728 : STATIC_ASSERT(kPropCount > 4);
729 50 : int indices[] = {0, 2, kPropCount - 1};
730 200 : for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
731 : TestGeneralizeField(-1, indices[i], from, to, expected,
732 150 : expected_deprecation, expected_field_type_dependency);
733 : }
734 :
735 50 : if (!from.representation.IsNone()) {
736 : // Check the cases when the map being reconfigured is NOT a part of the
737 : // transition tree. "None -> anything" representation changes make sense
738 : // only for "attached" maps.
739 30 : int indices[] = {0, kPropCount - 1};
740 90 : for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
741 : TestGeneralizeField(indices[i], 2, from, to, expected,
742 60 : expected_deprecation, expected_field_type_dependency);
743 : }
744 :
745 : // Check that reconfiguration to the very same field works correctly.
746 30 : CRFTData data = from;
747 30 : TestGeneralizeField(-1, 2, data, data, data, false, false);
748 : }
749 50 : }
750 :
751 : static void TestGeneralizeField(const CRFTData& from, const CRFTData& to,
752 : const CRFTData& expected) {
753 : const bool expected_deprecation = true;
754 : const bool expected_field_type_dependency = false;
755 :
756 : TestGeneralizeField(from, to, expected, expected_deprecation,
757 25 : expected_field_type_dependency);
758 : }
759 :
760 : static void TestGeneralizeFieldTrivial(
761 : const CRFTData& from, const CRFTData& to, const CRFTData& expected,
762 : bool expected_field_type_dependency = true) {
763 : const bool expected_deprecation = false;
764 :
765 : TestGeneralizeField(from, to, expected, expected_deprecation,
766 25 : expected_field_type_dependency);
767 : }
768 :
769 25880 : TEST(GeneralizeSmiFieldToDouble) {
770 5 : CcTest::InitializeVM();
771 5 : v8::HandleScope scope(CcTest::isolate());
772 : Isolate* isolate = CcTest::i_isolate();
773 :
774 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
775 :
776 : TestGeneralizeField(
777 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
778 : {PropertyConstness::kMutable, Representation::Double(), any_type},
779 10 : {PropertyConstness::kMutable, Representation::Double(), any_type});
780 5 : }
781 :
782 25880 : TEST(GeneralizeSmiFieldToTagged) {
783 5 : CcTest::InitializeVM();
784 5 : v8::HandleScope scope(CcTest::isolate());
785 : Isolate* isolate = CcTest::i_isolate();
786 :
787 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
788 : Handle<FieldType> value_type =
789 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
790 :
791 : TestGeneralizeField(
792 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
793 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
794 10 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
795 5 : }
796 :
797 25880 : TEST(GeneralizeDoubleFieldToTagged) {
798 5 : CcTest::InitializeVM();
799 5 : v8::HandleScope scope(CcTest::isolate());
800 : Isolate* isolate = CcTest::i_isolate();
801 :
802 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
803 : Handle<FieldType> value_type =
804 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
805 :
806 : TestGeneralizeField(
807 : {PropertyConstness::kMutable, Representation::Double(), any_type},
808 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
809 10 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
810 5 : }
811 :
812 25880 : TEST(GeneralizeHeapObjectFieldToTagged) {
813 5 : CcTest::InitializeVM();
814 5 : v8::HandleScope scope(CcTest::isolate());
815 : Isolate* isolate = CcTest::i_isolate();
816 :
817 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
818 : Handle<FieldType> value_type =
819 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
820 :
821 : TestGeneralizeField(
822 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
823 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
824 10 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
825 5 : }
826 :
827 25880 : TEST(GeneralizeHeapObjectFieldToHeapObject) {
828 5 : CcTest::InitializeVM();
829 5 : v8::HandleScope scope(CcTest::isolate());
830 : Isolate* isolate = CcTest::i_isolate();
831 :
832 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
833 :
834 : Handle<FieldType> current_type =
835 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
836 :
837 : Handle<FieldType> new_type =
838 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
839 :
840 5 : Handle<FieldType> expected_type = any_type;
841 :
842 : TestGeneralizeFieldTrivial(
843 : {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
844 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
845 : {PropertyConstness::kMutable, Representation::HeapObject(),
846 10 : expected_type});
847 : current_type = expected_type;
848 :
849 5 : new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
850 :
851 : TestGeneralizeFieldTrivial(
852 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
853 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
854 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
855 10 : false);
856 5 : }
857 :
858 25880 : TEST(GeneralizeNoneFieldToSmi) {
859 5 : CcTest::InitializeVM();
860 5 : v8::HandleScope scope(CcTest::isolate());
861 : Isolate* isolate = CcTest::i_isolate();
862 :
863 5 : Handle<FieldType> none_type = FieldType::None(isolate);
864 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
865 :
866 : // None -> Smi representation change is trivial.
867 : TestGeneralizeFieldTrivial(
868 : {PropertyConstness::kMutable, Representation::None(), none_type},
869 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
870 10 : {PropertyConstness::kMutable, Representation::Smi(), any_type});
871 5 : }
872 :
873 25880 : TEST(GeneralizeNoneFieldToDouble) {
874 5 : CcTest::InitializeVM();
875 5 : v8::HandleScope scope(CcTest::isolate());
876 : Isolate* isolate = CcTest::i_isolate();
877 :
878 5 : Handle<FieldType> none_type = FieldType::None(isolate);
879 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
880 :
881 : // None -> Double representation change is NOT trivial.
882 : TestGeneralizeField(
883 : {PropertyConstness::kMutable, Representation::None(), none_type},
884 : {PropertyConstness::kMutable, Representation::Double(), any_type},
885 10 : {PropertyConstness::kMutable, Representation::Double(), any_type});
886 5 : }
887 :
888 25880 : TEST(GeneralizeNoneFieldToHeapObject) {
889 5 : CcTest::InitializeVM();
890 5 : v8::HandleScope scope(CcTest::isolate());
891 : Isolate* isolate = CcTest::i_isolate();
892 :
893 5 : Handle<FieldType> none_type = FieldType::None(isolate);
894 : Handle<FieldType> value_type =
895 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
896 :
897 : // None -> HeapObject representation change is trivial.
898 : TestGeneralizeFieldTrivial(
899 : {PropertyConstness::kMutable, Representation::None(), none_type},
900 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
901 10 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type});
902 5 : }
903 :
904 25880 : TEST(GeneralizeNoneFieldToTagged) {
905 5 : CcTest::InitializeVM();
906 5 : v8::HandleScope scope(CcTest::isolate());
907 : Isolate* isolate = CcTest::i_isolate();
908 :
909 5 : Handle<FieldType> none_type = FieldType::None(isolate);
910 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
911 :
912 : // None -> HeapObject representation change is trivial.
913 : TestGeneralizeFieldTrivial(
914 : {PropertyConstness::kMutable, Representation::None(), none_type},
915 : {PropertyConstness::kMutable, Representation::Tagged(), any_type},
916 10 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
917 5 : }
918 :
919 :
920 : ////////////////////////////////////////////////////////////////////////////////
921 : // A set of tests for field generalization case with kAccessor properties.
922 : //
923 :
924 25880 : TEST(GeneralizeFieldWithAccessorProperties) {
925 5 : CcTest::InitializeVM();
926 5 : v8::HandleScope scope(CcTest::isolate());
927 : Isolate* isolate = CcTest::i_isolate();
928 :
929 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
930 5 : Handle<AccessorPair> pair = CreateAccessorPair(true, true);
931 :
932 : const int kAccessorProp = kPropCount / 2;
933 5 : Expectations expectations(isolate);
934 :
935 : // Create a map, add required properties to it and initialize expectations.
936 5 : Handle<Map> initial_map = Map::Create(isolate, 0);
937 5 : Handle<Map> map = initial_map;
938 40 : for (int i = 0; i < kPropCount; i++) {
939 35 : if (i == kAccessorProp) {
940 5 : map = expectations.AddAccessorConstant(map, NONE, pair);
941 : } else {
942 : map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
943 30 : Representation::Smi(), any_type);
944 : }
945 : }
946 5 : CHECK(!map->is_deprecated());
947 5 : CHECK(map->is_stable());
948 5 : CHECK(expectations.Check(*map));
949 :
950 : // Create new maps by generalizing representation of propX field.
951 35 : Handle<Map> maps[kPropCount];
952 35 : for (int i = 0; i < kPropCount; i++) {
953 35 : if (i == kAccessorProp) {
954 : // Skip accessor property reconfiguration.
955 5 : maps[i] = maps[i - 1];
956 : continue;
957 : }
958 : Handle<Map> new_map = Map::ReconfigureProperty(
959 30 : isolate, map, i, kData, NONE, Representation::Double(), any_type);
960 30 : maps[i] = new_map;
961 :
962 : expectations.SetDataField(i, PropertyConstness::kMutable,
963 30 : Representation::Double(), any_type);
964 :
965 30 : CHECK(!map->is_stable());
966 30 : CHECK(map->is_deprecated());
967 90 : CHECK_NE(*map, *new_map);
968 55 : CHECK(i == 0 || maps[i - 1]->is_deprecated());
969 :
970 30 : CHECK(!new_map->is_deprecated());
971 30 : CHECK(expectations.Check(*new_map));
972 : }
973 :
974 5 : Handle<Map> active_map = maps[kPropCount - 1];
975 5 : CHECK(!active_map->is_deprecated());
976 :
977 : // Update all deprecated maps and check that they are now the same.
978 5 : Handle<Map> updated_map = Map::Update(isolate, map);
979 15 : CHECK_EQ(*active_map, *updated_map);
980 5 : CheckMigrationTarget(isolate, *map, *updated_map);
981 40 : for (int i = 0; i < kPropCount; i++) {
982 35 : updated_map = Map::Update(isolate, maps[i]);
983 105 : CHECK_EQ(*active_map, *updated_map);
984 70 : CheckMigrationTarget(isolate, *maps[i], *updated_map);
985 5 : }
986 5 : }
987 :
988 :
989 : ////////////////////////////////////////////////////////////////////////////////
990 : // A set of tests for attribute reconfiguration case.
991 : //
992 :
993 : // This test ensures that field generalization is correctly propagated from one
994 : // branch of transition tree (|map2|) to another (|map|).
995 : //
996 : // + - p2B - p3 - p4: |map2|
997 : // |
998 : // {} - p0 - p1 - p2A - p3 - p4: |map|
999 : //
1000 : // where "p2A" and "p2B" differ only in the attributes.
1001 : //
1002 65 : static void TestReconfigureDataFieldAttribute_GeneralizeField(
1003 : const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
1004 65 : Isolate* isolate = CcTest::i_isolate();
1005 :
1006 65 : Expectations expectations(isolate);
1007 :
1008 : // Create a map, add required properties to it and initialize expectations.
1009 65 : Handle<Map> initial_map = Map::Create(isolate, 0);
1010 65 : Handle<Map> map = initial_map;
1011 520 : for (int i = 0; i < kPropCount; i++) {
1012 : map = expectations.AddDataField(map, NONE, from.constness,
1013 455 : from.representation, from.type);
1014 : }
1015 65 : CHECK(!map->is_deprecated());
1016 65 : CHECK(map->is_stable());
1017 65 : CHECK(expectations.Check(*map));
1018 :
1019 :
1020 : // Create another branch in transition tree (property at index |kSplitProp|
1021 : // has different attributes), initialize expectations.
1022 : const int kSplitProp = kPropCount / 2;
1023 65 : Expectations expectations2(isolate);
1024 :
1025 : Handle<Map> map2 = initial_map;
1026 260 : for (int i = 0; i < kSplitProp; i++) {
1027 : map2 = expectations2.FollowDataTransition(map2, NONE, from.constness,
1028 195 : from.representation, from.type);
1029 : }
1030 : map2 = expectations2.AddDataField(map2, READ_ONLY, to.constness,
1031 65 : to.representation, to.type);
1032 :
1033 260 : for (int i = kSplitProp + 1; i < kPropCount; i++) {
1034 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1035 195 : to.representation, to.type);
1036 : }
1037 65 : CHECK(!map2->is_deprecated());
1038 65 : CHECK(map2->is_stable());
1039 65 : CHECK(expectations2.Check(*map2));
1040 :
1041 65 : Zone zone(isolate->allocator(), ZONE_NAME);
1042 130 : CanonicalHandleScope canonical(isolate);
1043 65 : JSHeapBroker broker(isolate, &zone);
1044 65 : CompilationDependencies dependencies(isolate, &zone);
1045 : MapRef map_ref(&broker, map);
1046 65 : map_ref.SerializeOwnDescriptors();
1047 65 : dependencies.DependOnFieldType(map_ref, kSplitProp);
1048 :
1049 : // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
1050 : // should generalize representations in |map1|.
1051 : Handle<Map> new_map =
1052 65 : Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
1053 :
1054 : // |map2| should be left unchanged but marked unstable.
1055 65 : CHECK(!map2->is_stable());
1056 65 : CHECK(!map2->is_deprecated());
1057 195 : CHECK_NE(*map2, *new_map);
1058 65 : CHECK(expectations2.Check(*map2));
1059 :
1060 : // |map| should be deprecated and |new_map| should match new expectations.
1061 260 : for (int i = kSplitProp; i < kPropCount; i++) {
1062 : expectations.SetDataField(i, expected.constness, expected.representation,
1063 260 : expected.type);
1064 : }
1065 65 : CHECK(map->is_deprecated());
1066 65 : CHECK(dependencies.AreValid());
1067 195 : CHECK_NE(*map, *new_map);
1068 :
1069 65 : CHECK(!new_map->is_deprecated());
1070 65 : CHECK(expectations.Check(*new_map));
1071 :
1072 : // Update deprecated |map|, it should become |new_map|.
1073 65 : Handle<Map> updated_map = Map::Update(isolate, map);
1074 195 : CHECK_EQ(*new_map, *updated_map);
1075 130 : CheckMigrationTarget(isolate, *map, *updated_map);
1076 65 : }
1077 :
1078 : // This test ensures that trivial field generalization (from HeapObject to
1079 : // HeapObject) is correctly propagated from one branch of transition tree
1080 : // (|map2|) to another (|map|).
1081 : //
1082 : // + - p2B - p3 - p4: |map2|
1083 : // |
1084 : // {} - p0 - p1 - p2A - p3 - p4: |map|
1085 : //
1086 : // where "p2A" and "p2B" differ only in the attributes.
1087 : //
1088 40 : static void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1089 : const CRFTData& from, const CRFTData& to, const CRFTData& expected,
1090 : bool expected_field_type_dependency = true) {
1091 40 : Isolate* isolate = CcTest::i_isolate();
1092 :
1093 40 : Expectations expectations(isolate);
1094 :
1095 : // Create a map, add required properties to it and initialize expectations.
1096 40 : Handle<Map> initial_map = Map::Create(isolate, 0);
1097 40 : Handle<Map> map = initial_map;
1098 320 : for (int i = 0; i < kPropCount; i++) {
1099 : map = expectations.AddDataField(map, NONE, from.constness,
1100 280 : from.representation, from.type);
1101 : }
1102 40 : CHECK(!map->is_deprecated());
1103 40 : CHECK(map->is_stable());
1104 40 : CHECK(expectations.Check(*map));
1105 :
1106 :
1107 : // Create another branch in transition tree (property at index |kSplitProp|
1108 : // has different attributes), initialize expectations.
1109 : const int kSplitProp = kPropCount / 2;
1110 40 : Expectations expectations2(isolate);
1111 :
1112 : Handle<Map> map2 = initial_map;
1113 160 : for (int i = 0; i < kSplitProp; i++) {
1114 : map2 = expectations2.FollowDataTransition(map2, NONE, from.constness,
1115 120 : from.representation, from.type);
1116 : }
1117 : map2 = expectations2.AddDataField(map2, READ_ONLY, to.constness,
1118 40 : to.representation, to.type);
1119 :
1120 160 : for (int i = kSplitProp + 1; i < kPropCount; i++) {
1121 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1122 120 : to.representation, to.type);
1123 : }
1124 40 : CHECK(!map2->is_deprecated());
1125 40 : CHECK(map2->is_stable());
1126 40 : CHECK(expectations2.Check(*map2));
1127 :
1128 40 : Zone zone(isolate->allocator(), ZONE_NAME);
1129 80 : CanonicalHandleScope canonical(isolate);
1130 40 : JSHeapBroker broker(isolate, &zone);
1131 40 : CompilationDependencies dependencies(isolate, &zone);
1132 : MapRef map_ref(&broker, map);
1133 40 : map_ref.SerializeOwnDescriptors();
1134 40 : dependencies.DependOnFieldType(map_ref, kSplitProp);
1135 40 : dependencies.DependOnFieldConstness(map_ref, kSplitProp);
1136 :
1137 : // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
1138 : // should generalize representations in |map1|.
1139 : Handle<Map> new_map =
1140 40 : Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
1141 :
1142 : // |map2| should be left unchanged but marked unstable.
1143 40 : CHECK(!map2->is_stable());
1144 40 : CHECK(!map2->is_deprecated());
1145 120 : CHECK_NE(*map2, *new_map);
1146 40 : CHECK(expectations2.Check(*map2));
1147 :
1148 : // In trivial case |map| should be returned as a result of the property
1149 : // reconfiguration, respective field types should be generalized and
1150 : // respective code dependencies should be invalidated. |map| should be NOT
1151 : // deprecated and it should match new expectations.
1152 160 : for (int i = kSplitProp; i < kPropCount; i++) {
1153 : expectations.SetDataField(i, expected.constness, expected.representation,
1154 160 : expected.type);
1155 : }
1156 40 : CHECK(!map->is_deprecated());
1157 120 : CHECK_EQ(*map, *new_map);
1158 40 : CHECK_EQ(expected_field_type_dependency, !dependencies.AreValid());
1159 :
1160 40 : CHECK(!new_map->is_deprecated());
1161 40 : CHECK(expectations.Check(*new_map));
1162 :
1163 40 : Handle<Map> updated_map = Map::Update(isolate, map);
1164 160 : CHECK_EQ(*new_map, *updated_map);
1165 40 : }
1166 :
1167 25880 : TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToDouble) {
1168 5 : CcTest::InitializeVM();
1169 5 : v8::HandleScope scope(CcTest::isolate());
1170 : Isolate* isolate = CcTest::i_isolate();
1171 :
1172 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1173 :
1174 : if (FLAG_track_constant_fields) {
1175 : TestReconfigureDataFieldAttribute_GeneralizeField(
1176 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1177 : {PropertyConstness::kConst, Representation::Double(), any_type},
1178 5 : {PropertyConstness::kConst, Representation::Double(), any_type});
1179 :
1180 : TestReconfigureDataFieldAttribute_GeneralizeField(
1181 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1182 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1183 5 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1184 :
1185 : TestReconfigureDataFieldAttribute_GeneralizeField(
1186 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1187 : {PropertyConstness::kConst, Representation::Double(), any_type},
1188 5 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1189 : }
1190 :
1191 : TestReconfigureDataFieldAttribute_GeneralizeField(
1192 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1193 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1194 5 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1195 5 : }
1196 :
1197 25880 : TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) {
1198 5 : CcTest::InitializeVM();
1199 5 : v8::HandleScope scope(CcTest::isolate());
1200 : Isolate* isolate = CcTest::i_isolate();
1201 :
1202 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1203 : Handle<FieldType> value_type =
1204 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
1205 :
1206 : if (FLAG_track_constant_fields) {
1207 : TestReconfigureDataFieldAttribute_GeneralizeField(
1208 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1209 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1210 5 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
1211 :
1212 : TestReconfigureDataFieldAttribute_GeneralizeField(
1213 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1214 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1215 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1216 :
1217 : TestReconfigureDataFieldAttribute_GeneralizeField(
1218 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1219 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1220 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1221 : }
1222 :
1223 : TestReconfigureDataFieldAttribute_GeneralizeField(
1224 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1225 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1226 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1227 5 : }
1228 :
1229 25880 : TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) {
1230 5 : CcTest::InitializeVM();
1231 5 : v8::HandleScope scope(CcTest::isolate());
1232 : Isolate* isolate = CcTest::i_isolate();
1233 :
1234 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1235 : Handle<FieldType> value_type =
1236 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
1237 :
1238 : if (FLAG_track_constant_fields) {
1239 : TestReconfigureDataFieldAttribute_GeneralizeField(
1240 : {PropertyConstness::kConst, Representation::Double(), any_type},
1241 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1242 5 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
1243 :
1244 : TestReconfigureDataFieldAttribute_GeneralizeField(
1245 : {PropertyConstness::kConst, Representation::Double(), any_type},
1246 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1247 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1248 :
1249 : TestReconfigureDataFieldAttribute_GeneralizeField(
1250 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1251 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1252 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1253 : }
1254 :
1255 : TestReconfigureDataFieldAttribute_GeneralizeField(
1256 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1257 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1258 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1259 5 : }
1260 :
1261 25880 : TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
1262 5 : CcTest::InitializeVM();
1263 5 : v8::HandleScope scope(CcTest::isolate());
1264 : Isolate* isolate = CcTest::i_isolate();
1265 :
1266 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1267 :
1268 : Handle<FieldType> current_type =
1269 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
1270 :
1271 : Handle<FieldType> new_type =
1272 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
1273 :
1274 5 : Handle<FieldType> expected_type = any_type;
1275 :
1276 : // Check generalizations that trigger deopts.
1277 : if (FLAG_track_constant_fields) {
1278 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1279 : {PropertyConstness::kConst, Representation::HeapObject(), current_type},
1280 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1281 : {PropertyConstness::kConst, Representation::HeapObject(),
1282 5 : expected_type});
1283 :
1284 : if (FLAG_modify_map_inplace) {
1285 : // PropertyConstness::kConst to PropertyConstness::kMutable migration does
1286 : // not create a new map, therefore trivial generalization.
1287 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1288 : {PropertyConstness::kConst, Representation::HeapObject(),
1289 : current_type},
1290 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1291 : {PropertyConstness::kMutable, Representation::HeapObject(),
1292 5 : expected_type});
1293 : } else {
1294 : // PropertyConstness::kConst to PropertyConstness::kMutable migration
1295 : // causes map change, therefore non-trivial generalization.
1296 : TestReconfigureDataFieldAttribute_GeneralizeField(
1297 : {PropertyConstness::kConst, Representation::HeapObject(),
1298 : current_type},
1299 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1300 : {PropertyConstness::kMutable, Representation::HeapObject(),
1301 : expected_type});
1302 : }
1303 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1304 : {PropertyConstness::kMutable, Representation::HeapObject(),
1305 : current_type},
1306 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1307 : {PropertyConstness::kMutable, Representation::HeapObject(),
1308 5 : expected_type});
1309 : }
1310 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1311 : {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
1312 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1313 : {PropertyConstness::kMutable, Representation::HeapObject(),
1314 5 : expected_type});
1315 : current_type = expected_type;
1316 :
1317 : // Check generalizations that do not trigger deopts.
1318 5 : new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
1319 :
1320 : if (FLAG_track_constant_fields) {
1321 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1322 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1323 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1324 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1325 5 : false);
1326 :
1327 : if (FLAG_modify_map_inplace) {
1328 : // PropertyConstness::kConst to PropertyConstness::kMutable migration does
1329 : // not create a new map, therefore trivial generalization.
1330 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1331 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1332 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1333 : {PropertyConstness::kMutable, Representation::HeapObject(),
1334 5 : any_type});
1335 : } else {
1336 : // PropertyConstness::kConst to PropertyConstness::kMutable migration
1337 : // causes map change, therefore non-trivial generalization.
1338 : TestReconfigureDataFieldAttribute_GeneralizeField(
1339 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1340 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1341 : {PropertyConstness::kMutable, Representation::HeapObject(),
1342 : any_type});
1343 : }
1344 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1345 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1346 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1347 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1348 5 : false);
1349 : }
1350 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1351 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1352 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1353 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1354 5 : false);
1355 5 : }
1356 :
1357 25880 : TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) {
1358 5 : CcTest::InitializeVM();
1359 5 : v8::HandleScope scope(CcTest::isolate());
1360 : Isolate* isolate = CcTest::i_isolate();
1361 :
1362 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1363 : Handle<FieldType> value_type =
1364 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
1365 :
1366 : TestReconfigureDataFieldAttribute_GeneralizeField(
1367 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1368 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1369 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1370 5 : }
1371 :
1372 :
1373 : // Checks that given |map| is deprecated and that it updates to given |new_map|
1374 : // which in turn should match expectations.
1375 : struct CheckDeprecated {
1376 : void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
1377 : const Expectations& expectations) {
1378 : CHECK(map->is_deprecated());
1379 : CHECK_NE(*map, *new_map);
1380 :
1381 : CHECK(!new_map->is_deprecated());
1382 : CHECK(expectations.Check(*new_map));
1383 :
1384 : // Update deprecated |map|, it should become |new_map|.
1385 : Handle<Map> updated_map = Map::Update(isolate, map);
1386 : CHECK_EQ(*new_map, *updated_map);
1387 : CheckMigrationTarget(isolate, *map, *updated_map);
1388 : }
1389 : };
1390 :
1391 :
1392 : // Checks that given |map| is NOT deprecated, equals to given |new_map| and
1393 : // matches expectations.
1394 : struct CheckSameMap {
1395 15 : void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
1396 : const Expectations& expectations) {
1397 : // |map| was not reconfigured, therefore it should stay stable.
1398 15 : CHECK(map->is_stable());
1399 15 : CHECK(!map->is_deprecated());
1400 45 : CHECK_EQ(*map, *new_map);
1401 :
1402 15 : CHECK(!new_map->is_deprecated());
1403 15 : CHECK(expectations.Check(*new_map));
1404 :
1405 : // Update deprecated |map|, it should become |new_map|.
1406 15 : Handle<Map> updated_map = Map::Update(isolate, map);
1407 45 : CHECK_EQ(*new_map, *updated_map);
1408 15 : }
1409 : };
1410 :
1411 :
1412 : // Checks that given |map| is NOT deprecated and matches expectations.
1413 : // |new_map| is unrelated to |map|.
1414 : struct CheckUnrelated {
1415 10 : void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
1416 : const Expectations& expectations) {
1417 10 : CHECK(!map->is_deprecated());
1418 30 : CHECK_NE(*map, *new_map);
1419 10 : CHECK(expectations.Check(*map));
1420 :
1421 10 : CHECK(new_map->is_stable());
1422 10 : CHECK(!new_map->is_deprecated());
1423 10 : }
1424 : };
1425 :
1426 :
1427 : // Checks that given |map| is NOT deprecated, and |new_map| is a result of
1428 : // copy-generalize-all-representations.
1429 : struct CheckCopyGeneralizeAllFields {
1430 5 : void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
1431 : Expectations& expectations) {
1432 5 : CHECK(!map->is_deprecated());
1433 15 : CHECK_NE(*map, *new_map);
1434 :
1435 10 : CHECK(new_map->GetBackPointer()->IsUndefined(isolate));
1436 35 : for (int i = 0; i < kPropCount; i++) {
1437 35 : expectations.GeneralizeField(i);
1438 : }
1439 :
1440 5 : CHECK(!new_map->is_deprecated());
1441 5 : CHECK(expectations.Check(*new_map));
1442 5 : }
1443 : };
1444 :
1445 : // This test ensures that field generalization is correctly propagated from one
1446 : // branch of transition tree (|map2|) to another (|map1|).
1447 : //
1448 : // + - p2B - p3 - p4: |map2|
1449 : // |
1450 : // {} - p0 - p1: |map|
1451 : // |
1452 : // + - p2A - p3 - p4: |map1|
1453 : // |
1454 : // + - the property customized by the TestConfig provided
1455 : //
1456 : // where "p2A" and "p2B" differ only in the attributes.
1457 : //
1458 : template <typename TestConfig, typename Checker>
1459 30 : static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
1460 : TestConfig& config, Checker& checker) {
1461 : Isolate* isolate = CcTest::i_isolate();
1462 30 : Handle<FieldType> any_type = FieldType::Any(isolate);
1463 :
1464 : const int kCustomPropIndex = kPropCount - 2;
1465 30 : Expectations expectations(isolate);
1466 :
1467 : const int kSplitProp = 2;
1468 : CHECK_LT(kSplitProp, kCustomPropIndex);
1469 :
1470 : const PropertyConstness constness = PropertyConstness::kMutable;
1471 30 : const Representation representation = Representation::Smi();
1472 :
1473 : // Create common part of transition tree.
1474 30 : Handle<Map> initial_map = Map::Create(isolate, 0);
1475 30 : Handle<Map> map = initial_map;
1476 90 : for (int i = 0; i < kSplitProp; i++) {
1477 60 : map = expectations.AddDataField(map, NONE, constness, representation,
1478 : any_type);
1479 : }
1480 30 : CHECK(!map->is_deprecated());
1481 30 : CHECK(map->is_stable());
1482 30 : CHECK(expectations.Check(*map));
1483 :
1484 :
1485 : // Create branch to |map1|.
1486 : Handle<Map> map1 = map;
1487 30 : Expectations expectations1 = expectations;
1488 120 : for (int i = kSplitProp; i < kCustomPropIndex; i++) {
1489 90 : map1 = expectations1.AddDataField(map1, NONE, constness, representation,
1490 : any_type);
1491 : }
1492 30 : map1 = config.AddPropertyAtBranch(1, expectations1, map1);
1493 60 : for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
1494 30 : map1 = expectations1.AddDataField(map1, NONE, constness, representation,
1495 : any_type);
1496 : }
1497 30 : CHECK(!map1->is_deprecated());
1498 30 : CHECK(map1->is_stable());
1499 30 : CHECK(expectations1.Check(*map1));
1500 :
1501 :
1502 : // Create another branch in transition tree (property at index |kSplitProp|
1503 : // has different attributes), initialize expectations.
1504 : Handle<Map> map2 = map;
1505 30 : Expectations expectations2 = expectations;
1506 30 : map2 = expectations2.AddDataField(map2, READ_ONLY, constness, representation,
1507 : any_type);
1508 90 : for (int i = kSplitProp + 1; i < kCustomPropIndex; i++) {
1509 60 : map2 = expectations2.AddDataField(map2, NONE, constness, representation,
1510 : any_type);
1511 : }
1512 30 : map2 = config.AddPropertyAtBranch(2, expectations2, map2);
1513 60 : for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
1514 30 : map2 = expectations2.AddDataField(map2, NONE, constness, representation,
1515 : any_type);
1516 : }
1517 30 : CHECK(!map2->is_deprecated());
1518 30 : CHECK(map2->is_stable());
1519 30 : CHECK(expectations2.Check(*map2));
1520 :
1521 :
1522 : // Reconfigure attributes of property |kSplitProp| of |map2| to NONE, which
1523 : // should generalize representations in |map1|.
1524 : Handle<Map> new_map =
1525 30 : Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
1526 :
1527 : // |map2| should be left unchanged but marked unstable.
1528 30 : CHECK(!map2->is_stable());
1529 30 : CHECK(!map2->is_deprecated());
1530 90 : CHECK_NE(*map2, *new_map);
1531 30 : CHECK(expectations2.Check(*map2));
1532 :
1533 : config.UpdateExpectations(kCustomPropIndex, expectations1);
1534 30 : checker.Check(isolate, map1, new_map, expectations1);
1535 30 : }
1536 :
1537 :
1538 25880 : TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) {
1539 5 : CcTest::InitializeVM();
1540 5 : v8::HandleScope scope(CcTest::isolate());
1541 :
1542 : struct TestConfig {
1543 : Handle<JSFunction> js_func_;
1544 5 : TestConfig() {
1545 : Isolate* isolate = CcTest::i_isolate();
1546 : Factory* factory = isolate->factory();
1547 5 : js_func_ = factory->NewFunctionForTest(factory->empty_string());
1548 5 : }
1549 :
1550 10 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1551 : Handle<Map> map) {
1552 10 : CHECK(branch_id == 1 || branch_id == 2);
1553 : // Add the same data constant property at both transition tree branches.
1554 10 : return expectations.AddDataConstant(map, NONE, js_func_);
1555 : }
1556 :
1557 : void UpdateExpectations(int property_index, Expectations& expectations) {
1558 : // Expectations stay the same.
1559 : }
1560 : };
1561 :
1562 5 : TestConfig config;
1563 : // Two branches are "compatible" so the |map1| should NOT be deprecated.
1564 : CheckSameMap checker;
1565 5 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1566 5 : }
1567 :
1568 :
1569 25880 : TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
1570 5 : CcTest::InitializeVM();
1571 5 : v8::HandleScope scope(CcTest::isolate());
1572 :
1573 : struct TestConfig {
1574 : Handle<JSFunction> js_func1_;
1575 : Handle<JSFunction> js_func2_;
1576 : Handle<FieldType> function_type_;
1577 5 : TestConfig() {
1578 : Isolate* isolate = CcTest::i_isolate();
1579 : Factory* factory = isolate->factory();
1580 : Handle<String> name = factory->empty_string();
1581 : Handle<Map> sloppy_map =
1582 5 : Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
1583 : Handle<SharedFunctionInfo> info =
1584 5 : factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
1585 5 : function_type_ = FieldType::Class(sloppy_map, isolate);
1586 5 : CHECK(sloppy_map->is_stable());
1587 :
1588 : js_func1_ =
1589 10 : factory->NewFunction(sloppy_map, info, isolate->native_context());
1590 :
1591 : js_func2_ =
1592 10 : factory->NewFunction(sloppy_map, info, isolate->native_context());
1593 5 : }
1594 :
1595 10 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1596 : Handle<Map> map) {
1597 10 : CHECK(branch_id == 1 || branch_id == 2);
1598 10 : Handle<JSFunction> js_func = branch_id == 1 ? js_func1_ : js_func2_;
1599 10 : return expectations.AddDataConstant(map, NONE, js_func);
1600 : }
1601 :
1602 : void UpdateExpectations(int property_index, Expectations& expectations) {
1603 : PropertyConstness expected_constness = FLAG_track_constant_fields
1604 : ? PropertyConstness::kConst
1605 : : PropertyConstness::kMutable;
1606 : expectations.SetDataField(property_index, expected_constness,
1607 5 : Representation::HeapObject(), function_type_);
1608 : }
1609 : };
1610 :
1611 5 : TestConfig config;
1612 : if (FLAG_track_constant_fields) {
1613 : CheckSameMap checker;
1614 5 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1615 :
1616 : } else {
1617 : // Two branches are "incompatible" so the |map1| should be deprecated.
1618 : CheckDeprecated checker;
1619 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1620 5 : }
1621 5 : }
1622 :
1623 :
1624 25880 : TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {
1625 5 : CcTest::InitializeVM();
1626 5 : v8::HandleScope scope(CcTest::isolate());
1627 :
1628 : struct TestConfig {
1629 : Handle<JSFunction> js_func_;
1630 : Handle<AccessorPair> pair_;
1631 5 : TestConfig() {
1632 : Isolate* isolate = CcTest::i_isolate();
1633 : Factory* factory = isolate->factory();
1634 5 : js_func_ = factory->NewFunctionForTest(factory->empty_string());
1635 5 : pair_ = CreateAccessorPair(true, true);
1636 5 : }
1637 :
1638 10 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1639 : Handle<Map> map) {
1640 10 : CHECK(branch_id == 1 || branch_id == 2);
1641 10 : if (branch_id == 1) {
1642 5 : return expectations.AddDataConstant(map, NONE, js_func_);
1643 : } else {
1644 5 : return expectations.AddAccessorConstant(map, NONE, pair_);
1645 : }
1646 : }
1647 :
1648 : void UpdateExpectations(int property_index, Expectations& expectations) {}
1649 : };
1650 :
1651 5 : TestConfig config;
1652 : // These are completely separate branches in transition tree.
1653 : CheckUnrelated checker;
1654 5 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1655 5 : }
1656 :
1657 :
1658 25880 : TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
1659 5 : CcTest::InitializeVM();
1660 5 : v8::HandleScope scope(CcTest::isolate());
1661 :
1662 : struct TestConfig {
1663 : Handle<AccessorPair> pair_;
1664 5 : TestConfig() { pair_ = CreateAccessorPair(true, true); }
1665 :
1666 10 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1667 : Handle<Map> map) {
1668 10 : CHECK(branch_id == 1 || branch_id == 2);
1669 : // Add the same accessor constant property at both transition tree
1670 : // branches.
1671 10 : return expectations.AddAccessorConstant(map, NONE, pair_);
1672 : }
1673 :
1674 : void UpdateExpectations(int property_index, Expectations& expectations) {
1675 : // Two branches are "compatible" so the |map1| should NOT be deprecated.
1676 : }
1677 : };
1678 :
1679 : TestConfig config;
1680 : CheckSameMap checker;
1681 5 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1682 5 : }
1683 :
1684 :
1685 25880 : TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
1686 5 : CcTest::InitializeVM();
1687 5 : v8::HandleScope scope(CcTest::isolate());
1688 :
1689 : struct TestConfig {
1690 : Handle<AccessorPair> pair1_;
1691 : Handle<AccessorPair> pair2_;
1692 5 : TestConfig() {
1693 5 : pair1_ = CreateAccessorPair(true, true);
1694 5 : pair2_ = CreateAccessorPair(true, true);
1695 5 : }
1696 :
1697 10 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1698 : Handle<Map> map) {
1699 10 : CHECK(branch_id == 1 || branch_id == 2);
1700 10 : Handle<AccessorPair> pair = branch_id == 1 ? pair1_ : pair2_;
1701 10 : return expectations.AddAccessorConstant(map, NONE, pair);
1702 : }
1703 :
1704 : void UpdateExpectations(int property_index, Expectations& expectations) {
1705 : if (IS_ACCESSOR_FIELD_SUPPORTED) {
1706 : expectations.SetAccessorField(property_index);
1707 : } else {
1708 : // Currently we have a copy-generalize-all-representations case and
1709 : // ACCESSOR property becomes ACCESSOR_CONSTANT.
1710 5 : expectations.SetAccessorConstant(property_index, pair2_);
1711 : }
1712 : }
1713 : };
1714 :
1715 5 : TestConfig config;
1716 : if (IS_ACCESSOR_FIELD_SUPPORTED) {
1717 : CheckCopyGeneralizeAllFields checker;
1718 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1719 : } else {
1720 : // Currently we have a copy-generalize-all-representations case.
1721 : CheckCopyGeneralizeAllFields checker;
1722 5 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1723 5 : }
1724 5 : }
1725 :
1726 :
1727 25880 : TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {
1728 5 : CcTest::InitializeVM();
1729 5 : v8::HandleScope scope(CcTest::isolate());
1730 :
1731 : struct TestConfig {
1732 : Handle<AccessorPair> pair_;
1733 5 : TestConfig() { pair_ = CreateAccessorPair(true, true); }
1734 :
1735 10 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1736 : Handle<Map> map) {
1737 10 : CHECK(branch_id == 1 || branch_id == 2);
1738 10 : if (branch_id == 1) {
1739 5 : return expectations.AddAccessorConstant(map, NONE, pair_);
1740 : } else {
1741 : Isolate* isolate = CcTest::i_isolate();
1742 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1743 : return expectations.AddDataField(map, NONE, kDefaultFieldConstness,
1744 5 : Representation::Smi(), any_type);
1745 : }
1746 : }
1747 :
1748 : void UpdateExpectations(int property_index, Expectations& expectations) {}
1749 : };
1750 :
1751 : TestConfig config;
1752 : // These are completely separate branches in transition tree.
1753 : CheckUnrelated checker;
1754 5 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1755 5 : }
1756 :
1757 :
1758 : ////////////////////////////////////////////////////////////////////////////////
1759 : // A set of tests for elements kind reconfiguration case.
1760 : //
1761 :
1762 : // This test ensures that field generalization is correctly propagated from one
1763 : // branch of transition tree (|map2) to another (|map|).
1764 : //
1765 : // + - p0 - p1 - p2A - p3 - p4: |map|
1766 : // |
1767 : // ek
1768 : // |
1769 : // {} - p0 - p1 - p2B - p3 - p4: |map2|
1770 : //
1771 : // where "p2A" and "p2B" differ only in the representation/field type.
1772 : //
1773 80 : static void TestReconfigureElementsKind_GeneralizeField(
1774 : const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
1775 80 : Isolate* isolate = CcTest::i_isolate();
1776 :
1777 80 : Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
1778 :
1779 : // Create a map, add required properties to it and initialize expectations.
1780 80 : Handle<Map> initial_map = Map::Create(isolate, 0);
1781 : initial_map->set_instance_type(JS_ARRAY_TYPE);
1782 80 : initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
1783 :
1784 : Handle<Map> map = initial_map;
1785 80 : map = expectations.AsElementsKind(map, PACKED_ELEMENTS);
1786 640 : for (int i = 0; i < kPropCount; i++) {
1787 : map = expectations.AddDataField(map, NONE, from.constness,
1788 560 : from.representation, from.type);
1789 : }
1790 80 : CHECK(!map->is_deprecated());
1791 80 : CHECK(map->is_stable());
1792 80 : CHECK(expectations.Check(*map));
1793 :
1794 : // Create another branch in transition tree (property at index |kDiffProp|
1795 : // has different representatio/field type), initialize expectations.
1796 : const int kDiffProp = kPropCount / 2;
1797 80 : Expectations expectations2(isolate, PACKED_SMI_ELEMENTS);
1798 :
1799 : Handle<Map> map2 = initial_map;
1800 640 : for (int i = 0; i < kPropCount; i++) {
1801 560 : if (i == kDiffProp) {
1802 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1803 80 : to.representation, to.type);
1804 : } else {
1805 : map2 = expectations2.AddDataField(map2, NONE, from.constness,
1806 480 : from.representation, from.type);
1807 : }
1808 : }
1809 80 : CHECK(!map2->is_deprecated());
1810 80 : CHECK(map2->is_stable());
1811 80 : CHECK(expectations2.Check(*map2));
1812 :
1813 80 : Zone zone(isolate->allocator(), ZONE_NAME);
1814 160 : CanonicalHandleScope canonical(isolate);
1815 80 : JSHeapBroker broker(isolate, &zone);
1816 80 : CompilationDependencies dependencies(isolate, &zone);
1817 : MapRef map_ref(&broker, map);
1818 80 : map_ref.SerializeOwnDescriptors();
1819 80 : dependencies.DependOnFieldType(map_ref, kDiffProp);
1820 :
1821 : // Reconfigure elements kinds of |map2|, which should generalize
1822 : // representations in |map|.
1823 : Handle<Map> new_map =
1824 80 : Map::ReconfigureElementsKind(isolate, map2, PACKED_ELEMENTS);
1825 :
1826 : // |map2| should be left unchanged but marked unstable.
1827 80 : CHECK(!map2->is_stable());
1828 80 : CHECK(!map2->is_deprecated());
1829 240 : CHECK_NE(*map2, *new_map);
1830 80 : CHECK(expectations2.Check(*map2));
1831 :
1832 : // |map| should be deprecated and |new_map| should match new expectations.
1833 : expectations.SetDataField(kDiffProp, expected.constness,
1834 80 : expected.representation, expected.type);
1835 :
1836 80 : CHECK(map->is_deprecated());
1837 80 : CHECK(dependencies.AreValid());
1838 240 : CHECK_NE(*map, *new_map);
1839 :
1840 80 : CHECK(!new_map->is_deprecated());
1841 80 : CHECK(expectations.Check(*new_map));
1842 :
1843 : // Update deprecated |map|, it should become |new_map|.
1844 80 : Handle<Map> updated_map = Map::Update(isolate, map);
1845 240 : CHECK_EQ(*new_map, *updated_map);
1846 80 : CheckMigrationTarget(isolate, *map, *updated_map);
1847 :
1848 : // Ensure Map::FindElementsKindTransitionedMap() is able to find the
1849 : // transitioned map.
1850 : {
1851 : MapHandles map_list;
1852 80 : map_list.push_back(updated_map);
1853 : Map transitioned_map =
1854 80 : map2->FindElementsKindTransitionedMap(isolate, map_list);
1855 160 : CHECK_EQ(*updated_map, transitioned_map);
1856 80 : }
1857 80 : }
1858 :
1859 : // This test ensures that trivial field generalization (from HeapObject to
1860 : // HeapObject) is correctly propagated from one branch of transition tree
1861 : // (|map2|) to another (|map|).
1862 : //
1863 : // + - p0 - p1 - p2A - p3 - p4: |map|
1864 : // |
1865 : // ek
1866 : // |
1867 : // {} - p0 - p1 - p2B - p3 - p4: |map2|
1868 : //
1869 : // where "p2A" and "p2B" differ only in the representation/field type.
1870 : //
1871 40 : static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
1872 : const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
1873 40 : Isolate* isolate = CcTest::i_isolate();
1874 :
1875 40 : Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
1876 :
1877 : // Create a map, add required properties to it and initialize expectations.
1878 40 : Handle<Map> initial_map = Map::Create(isolate, 0);
1879 : initial_map->set_instance_type(JS_ARRAY_TYPE);
1880 40 : initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
1881 :
1882 : Handle<Map> map = initial_map;
1883 40 : map = expectations.AsElementsKind(map, PACKED_ELEMENTS);
1884 320 : for (int i = 0; i < kPropCount; i++) {
1885 : map = expectations.AddDataField(map, NONE, from.constness,
1886 280 : from.representation, from.type);
1887 : }
1888 40 : CHECK(!map->is_deprecated());
1889 40 : CHECK(map->is_stable());
1890 40 : CHECK(expectations.Check(*map));
1891 :
1892 : // Create another branch in transition tree (property at index |kDiffProp|
1893 : // has different attributes), initialize expectations.
1894 : const int kDiffProp = kPropCount / 2;
1895 40 : Expectations expectations2(isolate, PACKED_SMI_ELEMENTS);
1896 :
1897 : Handle<Map> map2 = initial_map;
1898 320 : for (int i = 0; i < kPropCount; i++) {
1899 280 : if (i == kDiffProp) {
1900 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1901 40 : to.representation, to.type);
1902 : } else {
1903 : map2 = expectations2.AddDataField(map2, NONE, from.constness,
1904 240 : from.representation, from.type);
1905 : }
1906 : }
1907 40 : CHECK(!map2->is_deprecated());
1908 40 : CHECK(map2->is_stable());
1909 40 : CHECK(expectations2.Check(*map2));
1910 :
1911 40 : Zone zone(isolate->allocator(), ZONE_NAME);
1912 80 : CanonicalHandleScope canonical(isolate);
1913 40 : JSHeapBroker broker(isolate, &zone);
1914 40 : CompilationDependencies dependencies(isolate, &zone);
1915 : MapRef map_ref(&broker, map);
1916 40 : map_ref.SerializeOwnDescriptors();
1917 :
1918 40 : dependencies.DependOnFieldType(map_ref, kDiffProp);
1919 40 : dependencies.DependOnFieldConstness(map_ref, kDiffProp);
1920 :
1921 : // Reconfigure elements kinds of |map2|, which should generalize
1922 : // representations in |map|.
1923 : Handle<Map> new_map =
1924 40 : Map::ReconfigureElementsKind(isolate, map2, PACKED_ELEMENTS);
1925 :
1926 : // |map2| should be left unchanged but marked unstable.
1927 40 : CHECK(!map2->is_stable());
1928 40 : CHECK(!map2->is_deprecated());
1929 120 : CHECK_NE(*map2, *new_map);
1930 40 : CHECK(expectations2.Check(*map2));
1931 :
1932 : // In trivial case |map| should be returned as a result of the elements
1933 : // kind reconfiguration, respective field types should be generalized and
1934 : // respective code dependencies should be invalidated. |map| should be NOT
1935 : // deprecated and it should match new expectations.
1936 : expectations.SetDataField(kDiffProp, expected.constness,
1937 40 : expected.representation, expected.type);
1938 40 : CHECK(!map->is_deprecated());
1939 120 : CHECK_EQ(*map, *new_map);
1940 80 : CHECK_EQ(IsGeneralizableTo(to.constness, from.constness),
1941 : dependencies.AreValid());
1942 :
1943 40 : CHECK(!new_map->is_deprecated());
1944 40 : CHECK(expectations.Check(*new_map));
1945 :
1946 40 : Handle<Map> updated_map = Map::Update(isolate, map);
1947 120 : CHECK_EQ(*new_map, *updated_map);
1948 :
1949 : // Ensure Map::FindElementsKindTransitionedMap() is able to find the
1950 : // transitioned map.
1951 : {
1952 : MapHandles map_list;
1953 40 : map_list.push_back(updated_map);
1954 : Map transitioned_map =
1955 40 : map2->FindElementsKindTransitionedMap(isolate, map_list);
1956 80 : CHECK_EQ(*updated_map, transitioned_map);
1957 40 : }
1958 40 : }
1959 :
1960 25880 : TEST(ReconfigureElementsKind_GeneralizeSmiFieldToDouble) {
1961 5 : CcTest::InitializeVM();
1962 5 : v8::HandleScope scope(CcTest::isolate());
1963 : Isolate* isolate = CcTest::i_isolate();
1964 :
1965 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1966 :
1967 : if (FLAG_track_constant_fields) {
1968 : TestReconfigureElementsKind_GeneralizeField(
1969 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1970 : {PropertyConstness::kConst, Representation::Double(), any_type},
1971 5 : {PropertyConstness::kConst, Representation::Double(), any_type});
1972 :
1973 : TestReconfigureElementsKind_GeneralizeField(
1974 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1975 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1976 5 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1977 :
1978 : TestReconfigureElementsKind_GeneralizeField(
1979 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1980 : {PropertyConstness::kConst, Representation::Double(), any_type},
1981 5 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1982 : }
1983 : TestReconfigureElementsKind_GeneralizeField(
1984 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1985 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1986 5 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1987 5 : }
1988 :
1989 25880 : TEST(ReconfigureElementsKind_GeneralizeSmiFieldToTagged) {
1990 5 : CcTest::InitializeVM();
1991 5 : v8::HandleScope scope(CcTest::isolate());
1992 : Isolate* isolate = CcTest::i_isolate();
1993 :
1994 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
1995 : Handle<FieldType> value_type =
1996 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
1997 :
1998 : if (FLAG_track_constant_fields) {
1999 : TestReconfigureElementsKind_GeneralizeField(
2000 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2001 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2002 5 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
2003 :
2004 : TestReconfigureElementsKind_GeneralizeField(
2005 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2006 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2007 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2008 :
2009 : TestReconfigureElementsKind_GeneralizeField(
2010 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2011 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2012 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2013 : }
2014 : TestReconfigureElementsKind_GeneralizeField(
2015 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2016 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2017 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2018 5 : }
2019 :
2020 25880 : TEST(ReconfigureElementsKind_GeneralizeDoubleFieldToTagged) {
2021 5 : CcTest::InitializeVM();
2022 5 : v8::HandleScope scope(CcTest::isolate());
2023 : Isolate* isolate = CcTest::i_isolate();
2024 :
2025 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2026 : Handle<FieldType> value_type =
2027 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2028 :
2029 : if (FLAG_track_constant_fields) {
2030 : TestReconfigureElementsKind_GeneralizeField(
2031 : {PropertyConstness::kConst, Representation::Double(), any_type},
2032 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2033 5 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
2034 :
2035 : TestReconfigureElementsKind_GeneralizeField(
2036 : {PropertyConstness::kConst, Representation::Double(), any_type},
2037 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2038 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2039 :
2040 : TestReconfigureElementsKind_GeneralizeField(
2041 : {PropertyConstness::kMutable, Representation::Double(), any_type},
2042 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2043 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2044 : }
2045 : TestReconfigureElementsKind_GeneralizeField(
2046 : {PropertyConstness::kMutable, Representation::Double(), any_type},
2047 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2048 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2049 5 : }
2050 :
2051 25880 : TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
2052 5 : CcTest::InitializeVM();
2053 5 : v8::HandleScope scope(CcTest::isolate());
2054 : Isolate* isolate = CcTest::i_isolate();
2055 :
2056 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2057 :
2058 : Handle<FieldType> current_type =
2059 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2060 :
2061 : Handle<FieldType> new_type =
2062 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2063 :
2064 5 : Handle<FieldType> expected_type = any_type;
2065 :
2066 : // Check generalizations that trigger deopts.
2067 : if (FLAG_track_constant_fields) {
2068 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2069 : {PropertyConstness::kConst, Representation::HeapObject(), current_type},
2070 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2071 : {PropertyConstness::kConst, Representation::HeapObject(),
2072 5 : expected_type});
2073 : if (FLAG_modify_map_inplace) {
2074 : // PropertyConstness::kConst to PropertyConstness::kMutable migration does
2075 : // not create a new map, therefore trivial generalization.
2076 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2077 : {PropertyConstness::kConst, Representation::HeapObject(),
2078 : current_type},
2079 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2080 : {PropertyConstness::kMutable, Representation::HeapObject(),
2081 5 : expected_type});
2082 : } else {
2083 : // PropertyConstness::kConst to PropertyConstness::kMutable migration
2084 : // causes map change, therefore non-trivial generalization.
2085 : TestReconfigureElementsKind_GeneralizeField(
2086 : {PropertyConstness::kConst, Representation::HeapObject(),
2087 : current_type},
2088 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2089 : {PropertyConstness::kMutable, Representation::HeapObject(),
2090 : expected_type});
2091 : }
2092 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2093 : {PropertyConstness::kMutable, Representation::HeapObject(),
2094 : current_type},
2095 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2096 : {PropertyConstness::kMutable, Representation::HeapObject(),
2097 5 : expected_type});
2098 : }
2099 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2100 : {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
2101 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2102 : {PropertyConstness::kMutable, Representation::HeapObject(),
2103 5 : expected_type});
2104 : current_type = expected_type;
2105 :
2106 : // Check generalizations that do not trigger deopts.
2107 5 : new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
2108 :
2109 : if (FLAG_track_constant_fields) {
2110 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2111 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
2112 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2113 5 : {PropertyConstness::kConst, Representation::HeapObject(), any_type});
2114 :
2115 : if (FLAG_modify_map_inplace) {
2116 : // PropertyConstness::kConst to PropertyConstness::kMutable migration does
2117 : // not create a new map, therefore trivial generalization.
2118 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2119 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
2120 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2121 : {PropertyConstness::kMutable, Representation::HeapObject(),
2122 5 : any_type});
2123 : } else {
2124 : // PropertyConstness::kConst to PropertyConstness::kMutable migration
2125 : // causes map change, therefore non-trivial generalization.
2126 : TestReconfigureElementsKind_GeneralizeField(
2127 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
2128 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2129 : {PropertyConstness::kMutable, Representation::HeapObject(),
2130 : any_type});
2131 : }
2132 :
2133 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2134 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
2135 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2136 5 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type});
2137 : }
2138 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2139 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
2140 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2141 5 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type});
2142 5 : }
2143 :
2144 25880 : TEST(ReconfigureElementsKind_GeneralizeHeapObjectFieldToTagged) {
2145 5 : CcTest::InitializeVM();
2146 5 : v8::HandleScope scope(CcTest::isolate());
2147 : Isolate* isolate = CcTest::i_isolate();
2148 :
2149 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2150 : Handle<FieldType> value_type =
2151 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2152 :
2153 : if (FLAG_track_constant_fields) {
2154 : TestReconfigureElementsKind_GeneralizeField(
2155 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2156 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2157 5 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
2158 :
2159 : TestReconfigureElementsKind_GeneralizeField(
2160 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2161 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2162 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2163 :
2164 : TestReconfigureElementsKind_GeneralizeField(
2165 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2166 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2167 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2168 : }
2169 : TestReconfigureElementsKind_GeneralizeField(
2170 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2171 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2172 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2173 5 : }
2174 :
2175 : ////////////////////////////////////////////////////////////////////////////////
2176 : // A set of tests checking split map deprecation.
2177 : //
2178 :
2179 25880 : TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
2180 5 : CcTest::InitializeVM();
2181 5 : v8::HandleScope scope(CcTest::isolate());
2182 : Isolate* isolate = CcTest::i_isolate();
2183 :
2184 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2185 :
2186 5 : Expectations expectations(isolate);
2187 :
2188 : // Create a map, add required properties to it and initialize expectations.
2189 5 : Handle<Map> initial_map = Map::Create(isolate, 0);
2190 5 : Handle<Map> map = initial_map;
2191 40 : for (int i = 0; i < kPropCount; i++) {
2192 : map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
2193 35 : Representation::Smi(), any_type);
2194 : }
2195 5 : CHECK(!map->is_deprecated());
2196 5 : CHECK(map->is_stable());
2197 :
2198 : // Generalize representation of property at index |kSplitProp|.
2199 : const int kSplitProp = kPropCount / 2;
2200 : Handle<Map> split_map;
2201 : Handle<Map> map2 = initial_map;
2202 : {
2203 20 : for (int i = 0; i < kSplitProp + 1; i++) {
2204 20 : if (i == kSplitProp) {
2205 : split_map = map2;
2206 : }
2207 :
2208 20 : Handle<String> name = MakeName("prop", i);
2209 : Map target = TransitionsAccessor(isolate, map2)
2210 20 : .SearchTransition(*name, kData, NONE);
2211 20 : CHECK(!target.is_null());
2212 : map2 = handle(target, isolate);
2213 : }
2214 :
2215 : map2 = Map::ReconfigureProperty(isolate, map2, kSplitProp, kData, NONE,
2216 5 : Representation::Double(), any_type);
2217 : expectations.SetDataField(kSplitProp, PropertyConstness::kMutable,
2218 5 : Representation::Double(), any_type);
2219 :
2220 5 : CHECK(expectations.Check(*split_map, kSplitProp));
2221 5 : CHECK(expectations.Check(*map2, kSplitProp + 1));
2222 : }
2223 :
2224 : // At this point |map| should be deprecated and disconnected from the
2225 : // transition tree.
2226 5 : CHECK(map->is_deprecated());
2227 5 : CHECK(!split_map->is_deprecated());
2228 5 : CHECK(map2->is_stable());
2229 5 : CHECK(!map2->is_deprecated());
2230 :
2231 : // Fill in transition tree of |map2| so that it can't have more transitions.
2232 7680 : for (int i = 0; i < TransitionsAccessor::kMaxNumberOfTransitions; i++) {
2233 7680 : CHECK(TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
2234 7680 : Handle<String> name = MakeName("foo", i);
2235 : Map::CopyWithField(isolate, map2, name, any_type, NONE,
2236 : PropertyConstness::kMutable, Representation::Smi(),
2237 7680 : INSERT_TRANSITION)
2238 15360 : .ToHandleChecked();
2239 : }
2240 5 : CHECK(!TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
2241 :
2242 : // Try to update |map|, since there is no place for propX transition at |map2|
2243 : // |map| should become "copy-generalized".
2244 5 : Handle<Map> updated_map = Map::Update(isolate, map);
2245 10 : CHECK(updated_map->GetBackPointer()->IsUndefined(isolate));
2246 :
2247 35 : for (int i = 0; i < kPropCount; i++) {
2248 : expectations.SetDataField(i, PropertyConstness::kMutable,
2249 35 : Representation::Tagged(), any_type);
2250 : }
2251 5 : CHECK(expectations.Check(*updated_map));
2252 5 : }
2253 :
2254 :
2255 : ////////////////////////////////////////////////////////////////////////////////
2256 : // A set of tests involving special transitions (such as elements kind
2257 : // transition, observed transition or prototype transition).
2258 : //
2259 :
2260 : // This test ensures that field generalization is correctly propagated from one
2261 : // branch of transition tree (|map2|) to another (|map|).
2262 : //
2263 : // p4B: |map2|
2264 : // |
2265 : // * - special transition
2266 : // |
2267 : // {} - p0 - p1 - p2A - p3 - p4A: |map|
2268 : //
2269 : // where "p4A" and "p4B" are exactly the same properties.
2270 : //
2271 : // TODO(ishell): unify this test template with
2272 : // TestReconfigureDataFieldAttribute_GeneralizeField once
2273 : // IS_PROTO_TRANS_ISSUE_FIXED and IS_NON_EQUIVALENT_TRANSITION_SUPPORTED are
2274 : // fixed.
2275 : template <typename TestConfig>
2276 40 : static void TestGeneralizeFieldWithSpecialTransition(TestConfig& config,
2277 : const CRFTData& from,
2278 : const CRFTData& to,
2279 : const CRFTData& expected) {
2280 : Isolate* isolate = CcTest::i_isolate();
2281 :
2282 40 : Expectations expectations(isolate);
2283 :
2284 : // Create a map, add required properties to it and initialize expectations.
2285 40 : Handle<Map> initial_map = Map::Create(isolate, 0);
2286 40 : Handle<Map> map = initial_map;
2287 320 : for (int i = 0; i < kPropCount; i++) {
2288 280 : map = expectations.AddDataField(map, NONE, from.constness,
2289 280 : from.representation, from.type);
2290 : }
2291 40 : CHECK(!map->is_deprecated());
2292 40 : CHECK(map->is_stable());
2293 40 : CHECK(expectations.Check(*map));
2294 :
2295 40 : Expectations expectations2 = expectations;
2296 :
2297 : // Apply some special transition to |map|.
2298 40 : CHECK(map->owns_descriptors());
2299 40 : Handle<Map> map2 = config.Transition(map, expectations2);
2300 :
2301 : // |map| should still match expectations.
2302 40 : CHECK(!map->is_deprecated());
2303 40 : CHECK(expectations.Check(*map));
2304 :
2305 : if (config.generalizes_representations()) {
2306 70 : for (int i = 0; i < kPropCount; i++) {
2307 70 : expectations2.GeneralizeField(i);
2308 : }
2309 : }
2310 :
2311 40 : CHECK(!map2->is_deprecated());
2312 40 : CHECK(map2->is_stable());
2313 40 : CHECK(expectations2.Check(*map2));
2314 :
2315 : // Create new maps by generalizing representation of propX field.
2316 280 : Handle<Map> maps[kPropCount];
2317 280 : for (int i = 0; i < kPropCount; i++) {
2318 : Handle<Map> new_map = Map::ReconfigureProperty(isolate, map, i, kData, NONE,
2319 280 : to.representation, to.type);
2320 280 : maps[i] = new_map;
2321 :
2322 280 : expectations.SetDataField(i, expected.constness, expected.representation,
2323 280 : expected.type);
2324 :
2325 280 : CHECK(map->is_deprecated());
2326 840 : CHECK_NE(*map, *new_map);
2327 520 : CHECK(i == 0 || maps[i - 1]->is_deprecated());
2328 280 : CHECK(expectations.Check(*new_map));
2329 :
2330 280 : Handle<Map> new_map2 = Map::Update(isolate, map2);
2331 280 : CHECK(!new_map2->is_deprecated());
2332 280 : CHECK(!new_map2->is_dictionary_map());
2333 :
2334 : Handle<Map> tmp_map;
2335 560 : if (Map::TryUpdate(isolate, map2).ToHandle(&tmp_map)) {
2336 : // If Map::TryUpdate() manages to succeed the result must match the result
2337 : // of Map::Update().
2338 840 : CHECK_EQ(*new_map2, *tmp_map);
2339 : } else {
2340 : // Equivalent transitions should always find the updated map.
2341 0 : CHECK(config.is_non_equivalent_transition());
2342 : }
2343 :
2344 : if (config.is_non_equivalent_transition()) {
2345 : // In case of non-equivalent transition currently we generalize all
2346 : // representations.
2347 490 : for (int i = 0; i < kPropCount; i++) {
2348 490 : expectations2.GeneralizeField(i);
2349 : }
2350 140 : CHECK(new_map2->GetBackPointer()->IsUndefined(isolate));
2351 70 : CHECK(expectations2.Check(*new_map2));
2352 : } else {
2353 210 : expectations2.SetDataField(i, expected.constness, expected.representation,
2354 210 : expected.type);
2355 :
2356 420 : CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate));
2357 210 : CHECK(expectations2.Check(*new_map2));
2358 : }
2359 : }
2360 :
2361 40 : Handle<Map> active_map = maps[kPropCount - 1];
2362 40 : CHECK(!active_map->is_deprecated());
2363 :
2364 : // Update all deprecated maps and check that they are now the same.
2365 40 : Handle<Map> updated_map = Map::Update(isolate, map);
2366 120 : CHECK_EQ(*active_map, *updated_map);
2367 40 : CheckMigrationTarget(isolate, *map, *updated_map);
2368 320 : for (int i = 0; i < kPropCount; i++) {
2369 280 : updated_map = Map::Update(isolate, maps[i]);
2370 840 : CHECK_EQ(*active_map, *updated_map);
2371 560 : CheckMigrationTarget(isolate, *maps[i], *updated_map);
2372 : }
2373 40 : }
2374 :
2375 :
2376 25880 : TEST(ElementsKindTransitionFromMapOwningDescriptor) {
2377 5 : CcTest::InitializeVM();
2378 5 : v8::HandleScope scope(CcTest::isolate());
2379 : Isolate* isolate = CcTest::i_isolate();
2380 :
2381 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2382 : Handle<FieldType> value_type =
2383 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2384 :
2385 : struct TestConfig {
2386 : TestConfig(PropertyAttributes attributes, Handle<Symbol> symbol)
2387 15 : : attributes(attributes), symbol(symbol) {}
2388 :
2389 15 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2390 : expectations.SetElementsKind(DICTIONARY_ELEMENTS);
2391 15 : expectations.ChangeAttributesForAllProperties(attributes);
2392 : return Map::CopyForPreventExtensions(CcTest::i_isolate(), map, attributes,
2393 30 : symbol, "CopyForPreventExtensions");
2394 : }
2395 : // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2396 : bool generalizes_representations() const { return false; }
2397 : bool is_non_equivalent_transition() const { return false; }
2398 :
2399 : PropertyAttributes attributes;
2400 : Handle<Symbol> symbol;
2401 : };
2402 : Factory* factory = isolate->factory();
2403 : TestConfig configs[] = {{FROZEN, factory->frozen_symbol()},
2404 : {SEALED, factory->sealed_symbol()},
2405 : {NONE, factory->nonextensible_symbol()}};
2406 20 : for (size_t i = 0; i < arraysize(configs); i++) {
2407 : TestGeneralizeFieldWithSpecialTransition(
2408 : configs[i],
2409 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2410 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2411 15 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2412 5 : }
2413 5 : }
2414 :
2415 :
2416 25880 : TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
2417 5 : CcTest::InitializeVM();
2418 5 : v8::HandleScope scope(CcTest::isolate());
2419 : Isolate* isolate = CcTest::i_isolate();
2420 :
2421 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2422 : Handle<FieldType> value_type =
2423 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2424 :
2425 : struct TestConfig {
2426 : TestConfig(PropertyAttributes attributes, Handle<Symbol> symbol)
2427 15 : : attributes(attributes), symbol(symbol) {}
2428 :
2429 15 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2430 : Isolate* isolate = CcTest::i_isolate();
2431 15 : Handle<FieldType> any_type = FieldType::Any(isolate);
2432 :
2433 : // Add one more transition to |map| in order to prevent descriptors
2434 : // ownership.
2435 15 : CHECK(map->owns_descriptors());
2436 : Map::CopyWithField(isolate, map, MakeString("foo"), any_type, NONE,
2437 : PropertyConstness::kMutable, Representation::Smi(),
2438 15 : INSERT_TRANSITION)
2439 30 : .ToHandleChecked();
2440 15 : CHECK(!map->owns_descriptors());
2441 :
2442 : expectations.SetElementsKind(DICTIONARY_ELEMENTS);
2443 15 : expectations.ChangeAttributesForAllProperties(attributes);
2444 : return Map::CopyForPreventExtensions(isolate, map, attributes, symbol,
2445 15 : "CopyForPreventExtensions");
2446 : }
2447 : // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2448 : bool generalizes_representations() const { return false; }
2449 : bool is_non_equivalent_transition() const { return false; }
2450 :
2451 : PropertyAttributes attributes;
2452 : Handle<Symbol> symbol;
2453 : };
2454 : Factory* factory = isolate->factory();
2455 : TestConfig configs[] = {{FROZEN, factory->frozen_symbol()},
2456 : {SEALED, factory->sealed_symbol()},
2457 : {NONE, factory->nonextensible_symbol()}};
2458 20 : for (size_t i = 0; i < arraysize(configs); i++) {
2459 : TestGeneralizeFieldWithSpecialTransition(
2460 : configs[i],
2461 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2462 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2463 15 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2464 5 : }
2465 5 : }
2466 :
2467 :
2468 25880 : TEST(PrototypeTransitionFromMapOwningDescriptor) {
2469 5 : CcTest::InitializeVM();
2470 5 : v8::HandleScope scope(CcTest::isolate());
2471 : Isolate* isolate = CcTest::i_isolate();
2472 :
2473 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2474 : Handle<FieldType> value_type =
2475 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2476 :
2477 : struct TestConfig {
2478 : Handle<JSObject> prototype_;
2479 :
2480 5 : TestConfig() {
2481 : Isolate* isolate = CcTest::i_isolate();
2482 : Factory* factory = isolate->factory();
2483 5 : prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
2484 5 : }
2485 :
2486 5 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2487 5 : return Map::TransitionToPrototype(CcTest::i_isolate(), map, prototype_);
2488 : }
2489 : // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2490 : bool generalizes_representations() const {
2491 : return !IS_PROTO_TRANS_ISSUE_FIXED;
2492 : }
2493 : bool is_non_equivalent_transition() const { return true; }
2494 : };
2495 5 : TestConfig config;
2496 : TestGeneralizeFieldWithSpecialTransition(
2497 : config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
2498 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2499 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2500 5 : }
2501 :
2502 :
2503 25880 : TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
2504 5 : CcTest::InitializeVM();
2505 5 : v8::HandleScope scope(CcTest::isolate());
2506 : Isolate* isolate = CcTest::i_isolate();
2507 :
2508 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2509 : Handle<FieldType> value_type =
2510 5 : FieldType::Class(Map::Create(isolate, 0), isolate);
2511 :
2512 : struct TestConfig {
2513 : Handle<JSObject> prototype_;
2514 :
2515 5 : TestConfig() {
2516 : Isolate* isolate = CcTest::i_isolate();
2517 : Factory* factory = isolate->factory();
2518 5 : prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
2519 5 : }
2520 :
2521 5 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2522 : Isolate* isolate = CcTest::i_isolate();
2523 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2524 :
2525 : // Add one more transition to |map| in order to prevent descriptors
2526 : // ownership.
2527 5 : CHECK(map->owns_descriptors());
2528 : Map::CopyWithField(isolate, map, MakeString("foo"), any_type, NONE,
2529 : PropertyConstness::kMutable, Representation::Smi(),
2530 5 : INSERT_TRANSITION)
2531 10 : .ToHandleChecked();
2532 5 : CHECK(!map->owns_descriptors());
2533 :
2534 5 : return Map::TransitionToPrototype(isolate, map, prototype_);
2535 : }
2536 : // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed.
2537 : bool generalizes_representations() const {
2538 : return !IS_PROTO_TRANS_ISSUE_FIXED;
2539 : }
2540 : bool is_non_equivalent_transition() const { return true; }
2541 : };
2542 5 : TestConfig config;
2543 : TestGeneralizeFieldWithSpecialTransition(
2544 : config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
2545 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2546 5 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2547 5 : }
2548 :
2549 :
2550 : ////////////////////////////////////////////////////////////////////////////////
2551 : // A set of tests for higher level transitioning mechanics.
2552 : //
2553 :
2554 : struct TransitionToDataFieldOperator {
2555 : PropertyConstness constness_;
2556 : Representation representation_;
2557 : PropertyAttributes attributes_;
2558 : Handle<FieldType> heap_type_;
2559 : Handle<Object> value_;
2560 :
2561 : TransitionToDataFieldOperator(PropertyConstness constness,
2562 : Representation representation,
2563 : Handle<FieldType> heap_type,
2564 : Handle<Object> value,
2565 : PropertyAttributes attributes = NONE)
2566 : : constness_(constness),
2567 : representation_(representation),
2568 : attributes_(attributes),
2569 : heap_type_(heap_type),
2570 15 : value_(value) {}
2571 :
2572 : Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2573 : return expectations.TransitionToDataField(
2574 15 : map, attributes_, constness_, representation_, heap_type_, value_);
2575 : }
2576 : };
2577 :
2578 :
2579 : struct TransitionToDataConstantOperator {
2580 : PropertyAttributes attributes_;
2581 : Handle<JSFunction> value_;
2582 :
2583 : TransitionToDataConstantOperator(Handle<JSFunction> value,
2584 : PropertyAttributes attributes = NONE)
2585 20 : : attributes_(attributes), value_(value) {}
2586 :
2587 : Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2588 25 : return expectations.TransitionToDataConstant(map, attributes_, value_);
2589 : }
2590 : };
2591 :
2592 :
2593 : struct TransitionToAccessorConstantOperator {
2594 : PropertyAttributes attributes_;
2595 : Handle<AccessorPair> pair_;
2596 :
2597 : TransitionToAccessorConstantOperator(Handle<AccessorPair> pair,
2598 : PropertyAttributes attributes = NONE)
2599 5 : : attributes_(attributes), pair_(pair) {}
2600 :
2601 : Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2602 10 : return expectations.TransitionToAccessorConstant(map, attributes_, pair_);
2603 : }
2604 : };
2605 :
2606 :
2607 : struct ReconfigureAsDataPropertyOperator {
2608 : int descriptor_;
2609 : Representation representation_;
2610 : PropertyAttributes attributes_;
2611 : Handle<FieldType> heap_type_;
2612 :
2613 : ReconfigureAsDataPropertyOperator(int descriptor,
2614 : Representation representation,
2615 : Handle<FieldType> heap_type,
2616 : PropertyAttributes attributes = NONE)
2617 : : descriptor_(descriptor),
2618 : representation_(representation),
2619 : attributes_(attributes),
2620 : heap_type_(heap_type) {}
2621 :
2622 : Handle<Map> DoTransition(Isolate* isolate, Expectations& expectations,
2623 : Handle<Map> map) {
2624 : expectations.SetDataField(descriptor_, PropertyConstness::kMutable,
2625 : representation_, heap_type_);
2626 : return Map::ReconfigureExistingProperty(isolate, map, descriptor_, kData,
2627 : attributes_);
2628 : }
2629 : };
2630 :
2631 :
2632 : struct ReconfigureAsAccessorPropertyOperator {
2633 : int descriptor_;
2634 : PropertyAttributes attributes_;
2635 :
2636 : ReconfigureAsAccessorPropertyOperator(int descriptor,
2637 : PropertyAttributes attributes = NONE)
2638 : : descriptor_(descriptor), attributes_(attributes) {}
2639 :
2640 : Handle<Map> DoTransition(Isolate* isolate, Expectations& expectations,
2641 : Handle<Map> map) {
2642 : expectations.SetAccessorField(descriptor_);
2643 : return Map::ReconfigureExistingProperty(isolate, map, descriptor_,
2644 : kAccessor, attributes_);
2645 : }
2646 : };
2647 :
2648 : // Checks that field generalization happened.
2649 : struct FieldGeneralizationChecker {
2650 : int descriptor_;
2651 : PropertyConstness constness_;
2652 : Representation representation_;
2653 : PropertyAttributes attributes_;
2654 : Handle<FieldType> heap_type_;
2655 :
2656 : FieldGeneralizationChecker(int descriptor, PropertyConstness constness,
2657 : Representation representation,
2658 : Handle<FieldType> heap_type,
2659 : PropertyAttributes attributes = NONE)
2660 : : descriptor_(descriptor),
2661 : constness_(constness),
2662 : representation_(representation),
2663 : attributes_(attributes),
2664 10 : heap_type_(heap_type) {}
2665 :
2666 10 : void Check(Isolate* isolate, Expectations& expectations2, Handle<Map> map1,
2667 : Handle<Map> map2) {
2668 10 : CHECK(!map2->is_deprecated());
2669 :
2670 10 : CHECK(map1->is_deprecated());
2671 30 : CHECK_NE(*map1, *map2);
2672 10 : Handle<Map> updated_map = Map::Update(isolate, map1);
2673 30 : CHECK_EQ(*map2, *updated_map);
2674 10 : CheckMigrationTarget(isolate, *map1, *updated_map);
2675 :
2676 : expectations2.SetDataField(descriptor_, attributes_, constness_,
2677 10 : representation_, heap_type_);
2678 10 : CHECK(expectations2.Check(*map2));
2679 10 : }
2680 : };
2681 :
2682 :
2683 : // Checks that existing transition was taken as is.
2684 : struct SameMapChecker {
2685 15 : void Check(Isolate* isolate, Expectations& expectations, Handle<Map> map1,
2686 : Handle<Map> map2) {
2687 15 : CHECK(!map2->is_deprecated());
2688 45 : CHECK_EQ(*map1, *map2);
2689 15 : CHECK(expectations.Check(*map2));
2690 15 : }
2691 : };
2692 :
2693 :
2694 : // Checks that both |map1| and |map2| should stays non-deprecated, this is
2695 : // the case when property kind is change.
2696 : struct PropertyKindReconfigurationChecker {
2697 : void Check(Expectations& expectations, Handle<Map> map1, Handle<Map> map2) {
2698 : CHECK(!map1->is_deprecated());
2699 : CHECK(!map2->is_deprecated());
2700 : CHECK_NE(*map1, *map2);
2701 : CHECK(expectations.Check(*map2));
2702 : }
2703 : };
2704 :
2705 :
2706 : // This test transitions to various property types under different
2707 : // circumstances.
2708 : // Plan:
2709 : // 1) create a |map| with p0..p3 properties.
2710 : // 2) create |map1| by adding "p4" to |map0|.
2711 : // 3) create |map2| by transition to "p4" from |map0|.
2712 : //
2713 : // + - p4B: |map2|
2714 : // |
2715 : // {} - p0 - p1 - pA - p3: |map|
2716 : // |
2717 : // + - p4A: |map1|
2718 : //
2719 : // where "p4A" and "p4B" differ only in the attributes.
2720 : //
2721 : template <typename TransitionOp1, typename TransitionOp2, typename Checker>
2722 45 : static void TestTransitionTo(TransitionOp1& transition_op1,
2723 15 : TransitionOp2& transition_op2, Checker& checker) {
2724 : Isolate* isolate = CcTest::i_isolate();
2725 25 : Handle<FieldType> any_type = FieldType::Any(isolate);
2726 :
2727 25 : Expectations expectations(isolate);
2728 :
2729 : // Create a map, add required properties to it and initialize expectations.
2730 25 : Handle<Map> initial_map = Map::Create(isolate, 0);
2731 25 : Handle<Map> map = initial_map;
2732 175 : for (int i = 0; i < kPropCount - 1; i++) {
2733 150 : map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
2734 : Representation::Smi(), any_type);
2735 : }
2736 25 : CHECK(expectations.Check(*map));
2737 :
2738 25 : Expectations expectations1 = expectations;
2739 : Handle<Map> map1 = transition_op1.DoTransition(expectations1, map);
2740 25 : CHECK(expectations1.Check(*map1));
2741 :
2742 25 : Expectations expectations2 = expectations;
2743 25 : Handle<Map> map2 = transition_op2.DoTransition(expectations2, map);
2744 :
2745 : // Let the test customization do the check.
2746 25 : checker.Check(isolate, expectations2, map1, map2);
2747 25 : }
2748 :
2749 :
2750 25880 : TEST(TransitionDataFieldToDataField) {
2751 5 : CcTest::InitializeVM();
2752 5 : v8::HandleScope scope(CcTest::isolate());
2753 : Isolate* isolate = CcTest::i_isolate();
2754 :
2755 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2756 :
2757 : Handle<Object> value1 = handle(Smi::kZero, isolate);
2758 : TransitionToDataFieldOperator transition_op1(
2759 : PropertyConstness::kMutable, Representation::Smi(), any_type, value1);
2760 :
2761 5 : Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
2762 : TransitionToDataFieldOperator transition_op2(
2763 : PropertyConstness::kMutable, Representation::Double(), any_type, value2);
2764 :
2765 : FieldGeneralizationChecker checker(kPropCount - 1,
2766 : PropertyConstness::kMutable,
2767 : Representation::Double(), any_type);
2768 5 : TestTransitionTo(transition_op1, transition_op2, checker);
2769 5 : }
2770 :
2771 25880 : TEST(TransitionDataConstantToSameDataConstant) {
2772 5 : CcTest::InitializeVM();
2773 5 : v8::HandleScope scope(CcTest::isolate());
2774 : Isolate* isolate = CcTest::i_isolate();
2775 : Factory* factory = isolate->factory();
2776 :
2777 : Handle<JSFunction> js_func =
2778 5 : factory->NewFunctionForTest(factory->empty_string());
2779 : TransitionToDataConstantOperator transition_op(js_func);
2780 :
2781 : SameMapChecker checker;
2782 5 : TestTransitionTo(transition_op, transition_op, checker);
2783 5 : }
2784 :
2785 :
2786 25880 : TEST(TransitionDataConstantToAnotherDataConstant) {
2787 5 : CcTest::InitializeVM();
2788 5 : v8::HandleScope scope(CcTest::isolate());
2789 : Isolate* isolate = CcTest::i_isolate();
2790 : Factory* factory = isolate->factory();
2791 :
2792 : Handle<String> name = factory->empty_string();
2793 : Handle<Map> sloppy_map =
2794 5 : Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
2795 : Handle<SharedFunctionInfo> info =
2796 5 : factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
2797 5 : Handle<FieldType> function_type = FieldType::Class(sloppy_map, isolate);
2798 5 : CHECK(sloppy_map->is_stable());
2799 :
2800 : Handle<JSFunction> js_func1 =
2801 10 : factory->NewFunction(sloppy_map, info, isolate->native_context());
2802 : TransitionToDataConstantOperator transition_op1(js_func1);
2803 :
2804 : Handle<JSFunction> js_func2 =
2805 10 : factory->NewFunction(sloppy_map, info, isolate->native_context());
2806 : TransitionToDataConstantOperator transition_op2(js_func2);
2807 :
2808 : if (FLAG_track_constant_fields) {
2809 : SameMapChecker checker;
2810 5 : TestTransitionTo(transition_op1, transition_op2, checker);
2811 :
2812 : } else {
2813 : FieldGeneralizationChecker checker(
2814 : kPropCount - 1, PropertyConstness::kMutable,
2815 : Representation::HeapObject(), function_type);
2816 : TestTransitionTo(transition_op1, transition_op2, checker);
2817 5 : }
2818 5 : }
2819 :
2820 :
2821 25880 : TEST(TransitionDataConstantToDataField) {
2822 5 : CcTest::InitializeVM();
2823 5 : v8::HandleScope scope(CcTest::isolate());
2824 : Isolate* isolate = CcTest::i_isolate();
2825 : Factory* factory = isolate->factory();
2826 :
2827 5 : Handle<FieldType> any_type = FieldType::Any(isolate);
2828 :
2829 : Handle<JSFunction> js_func1 =
2830 5 : factory->NewFunctionForTest(factory->empty_string());
2831 : TransitionToDataConstantOperator transition_op1(js_func1);
2832 :
2833 5 : Handle<Object> value2 = isolate->factory()->NewHeapNumber(0);
2834 : TransitionToDataFieldOperator transition_op2(
2835 : PropertyConstness::kMutable, Representation::Double(), any_type, value2);
2836 :
2837 : FieldGeneralizationChecker checker(kPropCount - 1,
2838 : PropertyConstness::kMutable,
2839 : Representation::Tagged(), any_type);
2840 5 : TestTransitionTo(transition_op1, transition_op2, checker);
2841 5 : }
2842 :
2843 :
2844 25880 : TEST(TransitionAccessorConstantToSameAccessorConstant) {
2845 5 : CcTest::InitializeVM();
2846 5 : v8::HandleScope scope(CcTest::isolate());
2847 :
2848 5 : Handle<AccessorPair> pair = CreateAccessorPair(true, true);
2849 : TransitionToAccessorConstantOperator transition_op(pair);
2850 :
2851 : SameMapChecker checker;
2852 5 : TestTransitionTo(transition_op, transition_op, checker);
2853 5 : }
2854 :
2855 : // TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported.
2856 : // TEST(TransitionAccessorConstantToAnotherAccessorConstant)
2857 :
2858 25880 : TEST(HoleyMutableHeapNumber) {
2859 5 : CcTest::InitializeVM();
2860 5 : v8::HandleScope scope(CcTest::isolate());
2861 : Isolate* isolate = CcTest::i_isolate();
2862 :
2863 : auto mhn = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
2864 5 : CHECK_EQ(kHoleNanInt64, mhn->value_as_bits());
2865 :
2866 5 : mhn = isolate->factory()->NewMutableHeapNumber(0.0);
2867 5 : CHECK_EQ(uint64_t{0}, mhn->value_as_bits());
2868 :
2869 : mhn->set_value_as_bits(kHoleNanInt64);
2870 5 : CHECK_EQ(kHoleNanInt64, mhn->value_as_bits());
2871 :
2872 : // Ensure that new storage for uninitialized value or mutable heap number
2873 : // with uninitialized sentinel (kHoleNanInt64) is a mutable heap number
2874 : // with uninitialized sentinel.
2875 : Handle<Object> obj =
2876 : Object::NewStorageFor(isolate, isolate->factory()->uninitialized_value(),
2877 5 : Representation::Double());
2878 10 : CHECK(obj->IsMutableHeapNumber());
2879 5 : CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj)->value_as_bits());
2880 :
2881 5 : obj = Object::NewStorageFor(isolate, mhn, Representation::Double());
2882 10 : CHECK(obj->IsMutableHeapNumber());
2883 5 : CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj)->value_as_bits());
2884 5 : }
2885 :
2886 : } // namespace test_field_type_tracking
2887 : } // namespace compiler
2888 : } // namespace internal
2889 77625 : } // namespace v8
|