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 10772 : return factory->InternalizeUtf8String(str);
57 : }
58 :
59 :
60 10756 : static Handle<String> MakeName(const char* str, int suffix) {
61 : EmbeddedVector<char, 128> buffer;
62 10756 : SNPrintF(buffer, "%s%d", str, suffix);
63 10756 : return MakeString(buffer.start());
64 : }
65 :
66 :
67 32 : static Handle<AccessorPair> CreateAccessorPair(bool with_getter,
68 : bool with_setter) {
69 : Isolate* isolate = CcTest::i_isolate();
70 : Factory* factory = isolate->factory();
71 32 : Handle<AccessorPair> pair = factory->NewAccessorPair();
72 32 : Handle<String> empty_string = factory->empty_string();
73 32 : if (with_getter) {
74 32 : Handle<JSFunction> func = factory->NewFunctionForTest(empty_string);
75 64 : pair->set_getter(*func);
76 : }
77 32 : if (with_setter) {
78 32 : Handle<JSFunction> func = factory->NewFunctionForTest(empty_string);
79 64 : pair->set_setter(*func);
80 : }
81 32 : return pair;
82 : }
83 :
84 : // Check cached migration target map after Map::Update() and Map::TryUpdate()
85 604 : static void CheckMigrationTarget(Isolate* isolate, Map old_map, Map new_map) {
86 : Map target = TransitionsAccessor(isolate, handle(old_map, isolate))
87 604 : .GetMigrationTarget();
88 1208 : 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 : explicit Expectations(Isolate* isolate, ElementsKind elements_kind)
111 : : isolate_(isolate),
112 : elements_kind_(elements_kind),
113 19840 : number_of_properties_(0) {}
114 :
115 448 : explicit Expectations(Isolate* isolate)
116 : : Expectations(
117 : isolate,
118 896 : isolate->object_function()->initial_map()->elements_kind()) {}
119 :
120 5740 : void Init(int index, PropertyKind kind, PropertyAttributes attributes,
121 : PropertyConstness constness, PropertyLocation location,
122 : Representation representation, Handle<Object> value) {
123 5740 : CHECK(index < MAX_PROPERTIES);
124 5740 : kinds_[index] = kind;
125 5740 : locations_[index] = location;
126 11436 : if (kind == kData && location == kField &&
127 5696 : IsTransitionableFastElementsKind(elements_kind_)) {
128 : // Maps with transitionable elements kinds must have the most general
129 : // field type.
130 1440 : value = FieldType::Any(isolate_);
131 : }
132 5740 : constnesses_[index] = constness;
133 5740 : attributes_[index] = attributes;
134 5740 : representations_[index] = representation;
135 5740 : values_[index] = value;
136 5740 : }
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 : 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 24 : 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 5656 : Init(index, kData, attrs, constness, kField, representation, field_type);
181 : }
182 :
183 : void SetDataField(int index, PropertyConstness constness,
184 : Representation representation,
185 : Handle<FieldType> field_type) {
186 1124 : SetDataField(index, attributes_[index], constness, representation,
187 : field_type);
188 : }
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 40 : void SetDataConstant(int index, PropertyAttributes attrs,
200 : Handle<JSFunction> value) {
201 : if (FLAG_track_constant_fields) {
202 80 : Handle<FieldType> field_type(FieldType::Class(value->map()), isolate_);
203 40 : Init(index, kData, attrs, PropertyConstness::kConst, kField,
204 40 : Representation::HeapObject(), field_type);
205 :
206 : } else {
207 : Init(index, kData, attrs, PropertyConstness::kConst, kDescriptor,
208 : Representation::HeapObject(), value);
209 : }
210 40 : }
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 44 : Representation::Tagged(), getter);
220 44 : 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 40 : void SetAccessorConstant(int index, PropertyAttributes attrs,
237 : Handle<AccessorPair> pair) {
238 40 : Handle<Object> getter = handle(pair->getter(), isolate_);
239 40 : Handle<Object> setter = handle(pair->setter(), isolate_);
240 : SetAccessorConstant(index, attrs, getter, setter);
241 40 : }
242 :
243 4 : void SetAccessorConstant(int index, Handle<Object> getter,
244 : Handle<Object> setter) {
245 4 : SetAccessorConstant(index, attributes_[index], getter, setter);
246 4 : }
247 :
248 4 : void SetAccessorConstant(int index, Handle<AccessorPair> pair) {
249 8 : Handle<Object> getter = handle(pair->getter(), isolate_);
250 8 : Handle<Object> setter = handle(pair->setter(), isolate_);
251 4 : SetAccessorConstant(index, getter, setter);
252 4 : }
253 :
254 476 : void GeneralizeField(int index) {
255 476 : CHECK(index < number_of_properties_);
256 476 : representations_[index] = Representation::Tagged();
257 476 : if (locations_[index] == kField) {
258 472 : values_[index] = FieldType::Any(isolate_);
259 : }
260 476 : }
261 :
262 13116 : bool Check(DescriptorArray descriptors, int descriptor) const {
263 13116 : PropertyDetails details = descriptors->GetDetails(descriptor);
264 :
265 13116 : if (details.kind() != kinds_[descriptor]) return false;
266 13116 : if (details.location() != locations_[descriptor]) return false;
267 13116 : if (details.constness() != constnesses_[descriptor]) return false;
268 :
269 13116 : PropertyAttributes expected_attributes = attributes_[descriptor];
270 13116 : if (details.attributes() != expected_attributes) return false;
271 :
272 13116 : Representation expected_representation = representations_[descriptor];
273 :
274 13116 : if (!details.representation().Equals(expected_representation)) return false;
275 :
276 13116 : Object expected_value = *values_[descriptor];
277 13116 : if (details.location() == kField) {
278 13024 : if (details.kind() == kData) {
279 : FieldType type = descriptors->GetFieldType(descriptor);
280 26048 : return FieldType::cast(expected_value) == type;
281 : } else {
282 : // kAccessor
283 0 : UNREACHABLE();
284 : }
285 : } else {
286 92 : Object value = descriptors->GetStrongValue(descriptor);
287 : // kDescriptor
288 92 : if (details.kind() == kData) {
289 0 : CHECK(!FLAG_track_constant_fields);
290 : return value == expected_value;
291 : } else {
292 : // kAccessor
293 92 : if (value == expected_value) return true;
294 92 : if (!value->IsAccessorPair()) return false;
295 92 : AccessorPair pair = AccessorPair::cast(value);
296 184 : return pair->Equals(expected_value, *setter_values_[descriptor]);
297 : }
298 : }
299 : UNREACHABLE();
300 : }
301 :
302 1932 : bool Check(Map map, int expected_nof) const {
303 1932 : CHECK_EQ(elements_kind_, map->elements_kind());
304 1932 : CHECK(number_of_properties_ <= MAX_PROPERTIES);
305 1932 : CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors());
306 1932 : CHECK(!map->is_dictionary_map());
307 :
308 1932 : DescriptorArray descriptors = map->instance_descriptors();
309 1932 : CHECK(expected_nof <= number_of_properties_);
310 28164 : for (int i = 0; i < expected_nof; i++) {
311 13116 : 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 1876 : 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 96 : Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind elements_kind) {
331 96 : elements_kind_ = elements_kind;
332 96 : map = Map::AsElementsKind(isolate_, map, elements_kind);
333 96 : CHECK_EQ(elements_kind_, map->elements_kind());
334 96 : return map;
335 : }
336 :
337 : void ChangeAttributesForAllProperties(PropertyAttributes attributes) {
338 360 : for (int i = 0; i < number_of_properties_; i++) {
339 168 : attributes_[i] = attributes;
340 : }
341 : }
342 :
343 4252 : Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes,
344 : PropertyConstness constness,
345 : Representation representation,
346 : Handle<FieldType> field_type) {
347 4252 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
348 4252 : int property_index = number_of_properties_++;
349 : SetDataField(property_index, attributes, constness, representation,
350 : field_type);
351 :
352 4252 : Handle<String> name = MakeName("prop", property_index);
353 8504 : return Map::CopyWithField(isolate_, map, name, field_type, attributes,
354 8504 : constness, representation, INSERT_TRANSITION)
355 4252 : .ToHandleChecked();
356 : }
357 :
358 20 : Handle<Map> AddDataConstant(Handle<Map> map, PropertyAttributes attributes,
359 : Handle<JSFunction> value) {
360 20 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
361 20 : int property_index = number_of_properties_++;
362 20 : SetDataConstant(property_index, attributes, value);
363 :
364 20 : Handle<String> name = MakeName("prop", property_index);
365 40 : return Map::CopyWithConstant(isolate_, map, name, value, attributes,
366 40 : INSERT_TRANSITION)
367 20 : .ToHandleChecked();
368 : }
369 :
370 12 : 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 12 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
377 12 : int property_index = number_of_properties_++;
378 : SetDataField(property_index, attributes, constness, representation,
379 : heap_type);
380 :
381 12 : Handle<String> name = MakeName("prop", property_index);
382 : return Map::TransitionToDataProperty(isolate_, map, name, value, attributes,
383 12 : constness, StoreOrigin::kNamed);
384 : }
385 :
386 20 : Handle<Map> TransitionToDataConstant(Handle<Map> map,
387 : PropertyAttributes attributes,
388 : Handle<JSFunction> value) {
389 20 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
390 20 : int property_index = number_of_properties_++;
391 20 : SetDataConstant(property_index, attributes, value);
392 :
393 20 : Handle<String> name = MakeName("prop", property_index);
394 : return Map::TransitionToDataProperty(isolate_, map, name, value, attributes,
395 : PropertyConstness::kConst,
396 20 : StoreOrigin::kNamed);
397 : }
398 :
399 252 : Handle<Map> FollowDataTransition(Handle<Map> map,
400 : PropertyAttributes attributes,
401 : PropertyConstness constness,
402 : Representation representation,
403 : Handle<FieldType> heap_type) {
404 252 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
405 252 : int property_index = number_of_properties_++;
406 : SetDataField(property_index, attributes, constness, representation,
407 : heap_type);
408 :
409 252 : Handle<String> name = MakeName("prop", property_index);
410 : Map target = TransitionsAccessor(isolate_, map)
411 504 : .SearchTransition(*name, kData, attributes);
412 252 : CHECK(!target.is_null());
413 504 : return handle(target, isolate_);
414 : }
415 :
416 32 : Handle<Map> AddAccessorConstant(Handle<Map> map,
417 : PropertyAttributes attributes,
418 : Handle<AccessorPair> pair) {
419 32 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
420 32 : int property_index = number_of_properties_++;
421 32 : SetAccessorConstant(property_index, attributes, pair);
422 :
423 32 : Handle<String> name = MakeName("prop", property_index);
424 :
425 32 : Descriptor d = Descriptor::AccessorConstant(name, pair, attributes);
426 32 : 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 8 : Handle<Map> TransitionToAccessorConstant(Handle<Map> map,
458 : PropertyAttributes attributes,
459 : Handle<AccessorPair> pair) {
460 8 : CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors());
461 8 : int property_index = number_of_properties_++;
462 8 : SetAccessorConstant(property_index, attributes, pair);
463 :
464 8 : 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 16 : map->instance_descriptors()->SearchWithCache(isolate, *name, *map);
472 : map = Map::TransitionToAccessorProperty(isolate, map, name, descriptor,
473 8 : getter, setter, attributes);
474 8 : CHECK(!map->is_deprecated());
475 8 : CHECK(!map->is_dictionary_map());
476 8 : 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 26067 : TEST(ReconfigureAccessorToNonExistingDataField) {
487 4 : CcTest::InitializeVM();
488 8 : v8::HandleScope scope(CcTest::isolate());
489 : Isolate* isolate = CcTest::i_isolate();
490 :
491 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
492 4 : Handle<FieldType> none_type = FieldType::None(isolate);
493 4 : Handle<AccessorPair> pair = CreateAccessorPair(true, true);
494 :
495 4 : Expectations expectations(isolate);
496 :
497 : // Create a map, add required properties to it and initialize expectations.
498 4 : Handle<Map> initial_map = Map::Create(isolate, 0);
499 4 : Handle<Map> map = initial_map;
500 4 : map = expectations.AddAccessorConstant(map, NONE, pair);
501 :
502 4 : CHECK(!map->is_deprecated());
503 4 : CHECK(map->is_stable());
504 4 : CHECK(expectations.Check(*map));
505 :
506 : Handle<Map> new_map = Map::ReconfigureProperty(
507 4 : isolate, map, 0, kData, NONE, Representation::None(), none_type);
508 : // |map| did not change except marked unstable.
509 4 : CHECK(!map->is_deprecated());
510 4 : CHECK(!map->is_stable());
511 4 : 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 4 : CHECK(!new_map->is_deprecated());
518 4 : CHECK(new_map->is_stable());
519 4 : CHECK(expectations.Check(*new_map));
520 :
521 : Handle<Map> new_map2 = Map::ReconfigureProperty(
522 4 : isolate, map, 0, kData, NONE, Representation::None(), none_type);
523 4 : CHECK_EQ(*new_map, *new_map2);
524 :
525 : Handle<Object> value(Smi::kZero, isolate);
526 : Handle<Map> prepared_map = Map::PrepareForDataProperty(
527 4 : isolate, new_map, 0, PropertyConstness::kConst, value);
528 : // None to Smi generalization is trivial, map does not change.
529 4 : CHECK_EQ(*new_map, *prepared_map);
530 :
531 : expectations.SetDataField(0, NONE, PropertyConstness::kMutable,
532 : Representation::Smi(), any_type);
533 4 : CHECK(prepared_map->is_stable());
534 4 : 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 4 : Handle<JSObject> obj = factory->NewJSObjectFromMap(map);
540 4 : JSObject::MigrateToMap(obj, prepared_map);
541 4 : FieldIndex index = FieldIndex::ForDescriptor(*prepared_map, 0);
542 8 : CHECK(obj->RawFastPropertyAt(index)->IsUninitialized(isolate));
543 : #ifdef VERIFY_HEAP
544 : obj->ObjectVerify(isolate);
545 : #endif
546 4 : }
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 26067 : TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) {
553 4 : CcTest::InitializeVM();
554 8 : 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 4 : Handle<String> foo_str = factory->InternalizeUtf8String("foo");
567 4 : Handle<String> obj_name = factory->InternalizeUtf8String("o");
568 :
569 : Handle<Object> obj_value =
570 12 : Object::GetProperty(isolate, isolate->global_object(), obj_name)
571 : .ToHandleChecked();
572 4 : CHECK(obj_value->IsJSObject());
573 : Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
574 :
575 4 : CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
576 4 : CHECK(
577 : obj->map()->instance_descriptors()->GetStrongValue(0)->IsAccessorPair());
578 :
579 : Handle<Object> value(Smi::FromInt(42), isolate);
580 8 : JSObject::SetOwnPropertyIgnoreAttributes(obj, foo_str, value, NONE).Check();
581 :
582 : // Check that the property contains |value|.
583 4 : CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors());
584 4 : FieldIndex index = FieldIndex::ForDescriptor(obj->map(), 0);
585 4 : Object the_value = obj->RawFastPropertyAt(index);
586 4 : CHECK(the_value->IsSmi());
587 4 : CHECK_EQ(42, Smi::ToInt(the_value));
588 4 : }
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 192 : 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 : Isolate* isolate = CcTest::i_isolate();
620 192 : Handle<FieldType> any_type = FieldType::Any(isolate);
621 :
622 192 : CHECK(detach_property_at_index >= -1 &&
623 : detach_property_at_index < kPropCount);
624 192 : CHECK_LT(property_index, kPropCount);
625 192 : CHECK_NE(detach_property_at_index, property_index);
626 :
627 : const bool is_detached_map = detach_property_at_index >= 0;
628 :
629 192 : Expectations expectations(isolate);
630 :
631 : // Create a map, add required properties to it and initialize expectations.
632 192 : Handle<Map> initial_map = Map::Create(isolate, 0);
633 192 : Handle<Map> map = initial_map;
634 : Handle<Map> detach_point_map;
635 2880 : for (int i = 0; i < kPropCount; i++) {
636 1344 : if (i == property_index) {
637 192 : map = expectations.AddDataField(map, NONE, from.constness,
638 192 : from.representation, from.type);
639 : } else {
640 : map = expectations.AddDataField(map, NONE, kDefaultFieldConstness,
641 1152 : Representation::Smi(), any_type);
642 1152 : if (i == detach_property_at_index) {
643 : detach_point_map = map;
644 : }
645 : }
646 : }
647 192 : CHECK(!map->is_deprecated());
648 192 : CHECK(map->is_stable());
649 192 : CHECK(expectations.Check(*map));
650 :
651 384 : Zone zone(isolate->allocator(), ZONE_NAME);
652 :
653 192 : if (is_detached_map) {
654 : detach_point_map = Map::ReconfigureProperty(
655 : isolate, detach_point_map, detach_property_at_index, kData, NONE,
656 48 : Representation::Tagged(), any_type);
657 : expectations.SetDataField(detach_property_at_index, kDefaultFieldConstness,
658 : Representation::Tagged(), any_type);
659 48 : CHECK(map->is_deprecated());
660 48 : CHECK(expectations.Check(*detach_point_map,
661 : detach_point_map->NumberOfOwnDescriptors()));
662 : }
663 :
664 : // Create new maps by generalizing representation of propX field.
665 384 : CanonicalHandleScope canonical(isolate);
666 384 : JSHeapBroker broker(isolate, &zone);
667 192 : CompilationDependencies dependencies(&broker, &zone);
668 : MapRef map_ref(&broker, map);
669 192 : map_ref.SerializeOwnDescriptors();
670 192 : dependencies.DependOnFieldType(map_ref, property_index);
671 :
672 : Handle<Map> field_owner(map->FindFieldOwner(isolate, property_index),
673 384 : isolate);
674 : Handle<Map> new_map = Map::ReconfigureProperty(
675 192 : isolate, map, property_index, kData, NONE, to.representation, to.type);
676 :
677 192 : expectations.SetDataField(property_index, expected.constness,
678 : expected.representation, expected.type);
679 :
680 192 : CHECK(!new_map->is_deprecated());
681 192 : CHECK(expectations.Check(*new_map));
682 :
683 192 : if (is_detached_map) {
684 48 : CHECK(!map->is_stable());
685 48 : CHECK(map->is_deprecated());
686 48 : CHECK_NE(*map, *new_map);
687 56 : CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(),
688 : !dependencies.AreValid());
689 :
690 144 : } else if (expected_deprecation) {
691 60 : CHECK(!map->is_stable());
692 60 : CHECK(map->is_deprecated());
693 60 : CHECK(field_owner->is_deprecated());
694 60 : CHECK_NE(*map, *new_map);
695 60 : CHECK(dependencies.AreValid());
696 :
697 : } else {
698 84 : CHECK(!field_owner->is_deprecated());
699 84 : CHECK(map->is_stable()); // Map did not change, must be left stable.
700 84 : CHECK_EQ(*map, *new_map);
701 :
702 84 : CHECK_EQ(expected_field_type_dependency, !dependencies.AreValid());
703 : }
704 :
705 : {
706 : // Check that all previous maps are not stable.
707 192 : Map tmp = *new_map;
708 1344 : while (true) {
709 1536 : Object back = tmp->GetBackPointer();
710 1536 : if (back->IsUndefined(isolate)) break;
711 1344 : tmp = Map::cast(back);
712 1344 : CHECK(!tmp->is_stable());
713 : }
714 : }
715 :
716 : // Update all deprecated maps and check that they are now the same.
717 192 : Handle<Map> updated_map = Map::Update(isolate, map);
718 192 : CHECK_EQ(*new_map, *updated_map);
719 192 : CheckMigrationTarget(isolate, *map, *updated_map);
720 192 : }
721 :
722 40 : 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 40 : int indices[] = {0, 2, kPropCount - 1};
730 280 : for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
731 120 : TestGeneralizeField(-1, indices[i], from, to, expected,
732 120 : expected_deprecation, expected_field_type_dependency);
733 : }
734 :
735 40 : 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 24 : int indices[] = {0, kPropCount - 1};
740 120 : for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) {
741 48 : TestGeneralizeField(indices[i], 2, from, to, expected,
742 48 : expected_deprecation, expected_field_type_dependency);
743 : }
744 :
745 : // Check that reconfiguration to the very same field works correctly.
746 24 : CRFTData data = from;
747 24 : TestGeneralizeField(-1, 2, data, data, data, false, false);
748 : }
749 40 : }
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 20 : 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 20 : expected_field_type_dependency);
767 : }
768 :
769 26067 : TEST(GeneralizeSmiFieldToDouble) {
770 4 : CcTest::InitializeVM();
771 8 : v8::HandleScope scope(CcTest::isolate());
772 : Isolate* isolate = CcTest::i_isolate();
773 :
774 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
775 :
776 8 : TestGeneralizeField(
777 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
778 : {PropertyConstness::kMutable, Representation::Double(), any_type},
779 : {PropertyConstness::kMutable, Representation::Double(), any_type});
780 4 : }
781 :
782 26067 : TEST(GeneralizeSmiFieldToTagged) {
783 4 : CcTest::InitializeVM();
784 8 : v8::HandleScope scope(CcTest::isolate());
785 : Isolate* isolate = CcTest::i_isolate();
786 :
787 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
788 : Handle<FieldType> value_type =
789 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
790 :
791 8 : TestGeneralizeField(
792 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
793 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
794 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
795 4 : }
796 :
797 26067 : TEST(GeneralizeDoubleFieldToTagged) {
798 4 : CcTest::InitializeVM();
799 8 : v8::HandleScope scope(CcTest::isolate());
800 : Isolate* isolate = CcTest::i_isolate();
801 :
802 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
803 : Handle<FieldType> value_type =
804 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
805 :
806 8 : TestGeneralizeField(
807 : {PropertyConstness::kMutable, Representation::Double(), any_type},
808 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
809 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
810 4 : }
811 :
812 26067 : TEST(GeneralizeHeapObjectFieldToTagged) {
813 4 : CcTest::InitializeVM();
814 8 : v8::HandleScope scope(CcTest::isolate());
815 : Isolate* isolate = CcTest::i_isolate();
816 :
817 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
818 : Handle<FieldType> value_type =
819 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
820 :
821 8 : TestGeneralizeField(
822 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
823 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
824 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
825 4 : }
826 :
827 26067 : TEST(GeneralizeHeapObjectFieldToHeapObject) {
828 4 : CcTest::InitializeVM();
829 8 : v8::HandleScope scope(CcTest::isolate());
830 : Isolate* isolate = CcTest::i_isolate();
831 :
832 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
833 :
834 : Handle<FieldType> current_type =
835 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
836 :
837 : Handle<FieldType> new_type =
838 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
839 :
840 4 : Handle<FieldType> expected_type = any_type;
841 :
842 8 : TestGeneralizeFieldTrivial(
843 : {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
844 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
845 : {PropertyConstness::kMutable, Representation::HeapObject(),
846 : expected_type});
847 : current_type = expected_type;
848 :
849 4 : new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
850 :
851 8 : TestGeneralizeFieldTrivial(
852 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
853 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
854 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
855 : false);
856 4 : }
857 :
858 26067 : TEST(GeneralizeNoneFieldToSmi) {
859 4 : CcTest::InitializeVM();
860 8 : v8::HandleScope scope(CcTest::isolate());
861 : Isolate* isolate = CcTest::i_isolate();
862 :
863 4 : Handle<FieldType> none_type = FieldType::None(isolate);
864 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
865 :
866 : // None -> Smi representation change is trivial.
867 8 : TestGeneralizeFieldTrivial(
868 : {PropertyConstness::kMutable, Representation::None(), none_type},
869 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
870 : {PropertyConstness::kMutable, Representation::Smi(), any_type});
871 4 : }
872 :
873 26067 : TEST(GeneralizeNoneFieldToDouble) {
874 4 : CcTest::InitializeVM();
875 8 : v8::HandleScope scope(CcTest::isolate());
876 : Isolate* isolate = CcTest::i_isolate();
877 :
878 4 : Handle<FieldType> none_type = FieldType::None(isolate);
879 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
880 :
881 : // None -> Double representation change is NOT trivial.
882 8 : TestGeneralizeField(
883 : {PropertyConstness::kMutable, Representation::None(), none_type},
884 : {PropertyConstness::kMutable, Representation::Double(), any_type},
885 : {PropertyConstness::kMutable, Representation::Double(), any_type});
886 4 : }
887 :
888 26067 : TEST(GeneralizeNoneFieldToHeapObject) {
889 4 : CcTest::InitializeVM();
890 8 : v8::HandleScope scope(CcTest::isolate());
891 : Isolate* isolate = CcTest::i_isolate();
892 :
893 4 : Handle<FieldType> none_type = FieldType::None(isolate);
894 : Handle<FieldType> value_type =
895 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
896 :
897 : // None -> HeapObject representation change is trivial.
898 8 : TestGeneralizeFieldTrivial(
899 : {PropertyConstness::kMutable, Representation::None(), none_type},
900 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
901 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type});
902 4 : }
903 :
904 26067 : TEST(GeneralizeNoneFieldToTagged) {
905 4 : CcTest::InitializeVM();
906 8 : v8::HandleScope scope(CcTest::isolate());
907 : Isolate* isolate = CcTest::i_isolate();
908 :
909 4 : Handle<FieldType> none_type = FieldType::None(isolate);
910 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
911 :
912 : // None -> HeapObject representation change is trivial.
913 8 : TestGeneralizeFieldTrivial(
914 : {PropertyConstness::kMutable, Representation::None(), none_type},
915 : {PropertyConstness::kMutable, Representation::Tagged(), any_type},
916 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
917 4 : }
918 :
919 :
920 : ////////////////////////////////////////////////////////////////////////////////
921 : // A set of tests for field generalization case with kAccessor properties.
922 : //
923 :
924 26067 : TEST(GeneralizeFieldWithAccessorProperties) {
925 4 : CcTest::InitializeVM();
926 8 : v8::HandleScope scope(CcTest::isolate());
927 : Isolate* isolate = CcTest::i_isolate();
928 :
929 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
930 4 : Handle<AccessorPair> pair = CreateAccessorPair(true, true);
931 :
932 : const int kAccessorProp = kPropCount / 2;
933 4 : Expectations expectations(isolate);
934 :
935 : // Create a map, add required properties to it and initialize expectations.
936 4 : Handle<Map> initial_map = Map::Create(isolate, 0);
937 4 : Handle<Map> map = initial_map;
938 60 : for (int i = 0; i < kPropCount; i++) {
939 28 : if (i == kAccessorProp) {
940 4 : map = expectations.AddAccessorConstant(map, NONE, pair);
941 : } else {
942 : map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
943 24 : Representation::Smi(), any_type);
944 : }
945 : }
946 4 : CHECK(!map->is_deprecated());
947 4 : CHECK(map->is_stable());
948 4 : CHECK(expectations.Check(*map));
949 :
950 : // Create new maps by generalizing representation of propX field.
951 60 : Handle<Map> maps[kPropCount];
952 60 : for (int i = 0; i < kPropCount; i++) {
953 28 : if (i == kAccessorProp) {
954 : // Skip accessor property reconfiguration.
955 4 : maps[i] = maps[i - 1];
956 : continue;
957 : }
958 : Handle<Map> new_map = Map::ReconfigureProperty(
959 24 : isolate, map, i, kData, NONE, Representation::Double(), any_type);
960 24 : maps[i] = new_map;
961 :
962 : expectations.SetDataField(i, PropertyConstness::kMutable,
963 : Representation::Double(), any_type);
964 :
965 24 : CHECK(!map->is_stable());
966 24 : CHECK(map->is_deprecated());
967 24 : CHECK_NE(*map, *new_map);
968 44 : CHECK(i == 0 || maps[i - 1]->is_deprecated());
969 :
970 24 : CHECK(!new_map->is_deprecated());
971 24 : CHECK(expectations.Check(*new_map));
972 : }
973 :
974 4 : Handle<Map> active_map = maps[kPropCount - 1];
975 4 : CHECK(!active_map->is_deprecated());
976 :
977 : // Update all deprecated maps and check that they are now the same.
978 4 : Handle<Map> updated_map = Map::Update(isolate, map);
979 4 : CHECK_EQ(*active_map, *updated_map);
980 4 : CheckMigrationTarget(isolate, *map, *updated_map);
981 60 : for (int i = 0; i < kPropCount; i++) {
982 28 : updated_map = Map::Update(isolate, maps[i]);
983 28 : CHECK_EQ(*active_map, *updated_map);
984 56 : CheckMigrationTarget(isolate, *maps[i], *updated_map);
985 : }
986 4 : }
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 52 : static void TestReconfigureDataFieldAttribute_GeneralizeField(
1003 : const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
1004 : Isolate* isolate = CcTest::i_isolate();
1005 :
1006 52 : Expectations expectations(isolate);
1007 :
1008 : // Create a map, add required properties to it and initialize expectations.
1009 52 : Handle<Map> initial_map = Map::Create(isolate, 0);
1010 52 : Handle<Map> map = initial_map;
1011 780 : for (int i = 0; i < kPropCount; i++) {
1012 364 : map = expectations.AddDataField(map, NONE, from.constness,
1013 364 : from.representation, from.type);
1014 : }
1015 52 : CHECK(!map->is_deprecated());
1016 52 : CHECK(map->is_stable());
1017 52 : 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 52 : Expectations expectations2(isolate);
1024 :
1025 : Handle<Map> map2 = initial_map;
1026 364 : for (int i = 0; i < kSplitProp; i++) {
1027 156 : map2 = expectations2.FollowDataTransition(map2, NONE, from.constness,
1028 156 : from.representation, from.type);
1029 : }
1030 52 : map2 = expectations2.AddDataField(map2, READ_ONLY, to.constness,
1031 52 : to.representation, to.type);
1032 :
1033 364 : for (int i = kSplitProp + 1; i < kPropCount; i++) {
1034 156 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1035 156 : to.representation, to.type);
1036 : }
1037 52 : CHECK(!map2->is_deprecated());
1038 52 : CHECK(map2->is_stable());
1039 52 : CHECK(expectations2.Check(*map2));
1040 :
1041 104 : Zone zone(isolate->allocator(), ZONE_NAME);
1042 104 : CanonicalHandleScope canonical(isolate);
1043 104 : JSHeapBroker broker(isolate, &zone);
1044 52 : CompilationDependencies dependencies(&broker, &zone);
1045 : MapRef map_ref(&broker, map);
1046 52 : map_ref.SerializeOwnDescriptors();
1047 52 : 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 52 : Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
1053 :
1054 : // |map2| should be left unchanged but marked unstable.
1055 52 : CHECK(!map2->is_stable());
1056 52 : CHECK(!map2->is_deprecated());
1057 52 : CHECK_NE(*map2, *new_map);
1058 52 : CHECK(expectations2.Check(*map2));
1059 :
1060 : // |map| should be deprecated and |new_map| should match new expectations.
1061 468 : for (int i = kSplitProp; i < kPropCount; i++) {
1062 208 : expectations.SetDataField(i, expected.constness, expected.representation,
1063 : expected.type);
1064 : }
1065 52 : CHECK(map->is_deprecated());
1066 52 : CHECK(dependencies.AreValid());
1067 52 : CHECK_NE(*map, *new_map);
1068 :
1069 52 : CHECK(!new_map->is_deprecated());
1070 52 : CHECK(expectations.Check(*new_map));
1071 :
1072 : // Update deprecated |map|, it should become |new_map|.
1073 52 : Handle<Map> updated_map = Map::Update(isolate, map);
1074 52 : CHECK_EQ(*new_map, *updated_map);
1075 52 : CheckMigrationTarget(isolate, *map, *updated_map);
1076 52 : }
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 32 : static void TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1089 : const CRFTData& from, const CRFTData& to, const CRFTData& expected,
1090 : bool expected_field_type_dependency = true) {
1091 : Isolate* isolate = CcTest::i_isolate();
1092 :
1093 32 : Expectations expectations(isolate);
1094 :
1095 : // Create a map, add required properties to it and initialize expectations.
1096 32 : Handle<Map> initial_map = Map::Create(isolate, 0);
1097 32 : Handle<Map> map = initial_map;
1098 480 : for (int i = 0; i < kPropCount; i++) {
1099 224 : map = expectations.AddDataField(map, NONE, from.constness,
1100 224 : from.representation, from.type);
1101 : }
1102 32 : CHECK(!map->is_deprecated());
1103 32 : CHECK(map->is_stable());
1104 32 : 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 32 : Expectations expectations2(isolate);
1111 :
1112 : Handle<Map> map2 = initial_map;
1113 224 : for (int i = 0; i < kSplitProp; i++) {
1114 96 : map2 = expectations2.FollowDataTransition(map2, NONE, from.constness,
1115 96 : from.representation, from.type);
1116 : }
1117 32 : map2 = expectations2.AddDataField(map2, READ_ONLY, to.constness,
1118 32 : to.representation, to.type);
1119 :
1120 224 : for (int i = kSplitProp + 1; i < kPropCount; i++) {
1121 96 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1122 96 : to.representation, to.type);
1123 : }
1124 32 : CHECK(!map2->is_deprecated());
1125 32 : CHECK(map2->is_stable());
1126 32 : CHECK(expectations2.Check(*map2));
1127 :
1128 64 : Zone zone(isolate->allocator(), ZONE_NAME);
1129 64 : CanonicalHandleScope canonical(isolate);
1130 64 : JSHeapBroker broker(isolate, &zone);
1131 32 : CompilationDependencies dependencies(&broker, &zone);
1132 : MapRef map_ref(&broker, map);
1133 32 : map_ref.SerializeOwnDescriptors();
1134 32 : dependencies.DependOnFieldType(map_ref, kSplitProp);
1135 32 : 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 32 : Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
1141 :
1142 : // |map2| should be left unchanged but marked unstable.
1143 32 : CHECK(!map2->is_stable());
1144 32 : CHECK(!map2->is_deprecated());
1145 32 : CHECK_NE(*map2, *new_map);
1146 32 : 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 288 : for (int i = kSplitProp; i < kPropCount; i++) {
1153 128 : expectations.SetDataField(i, expected.constness, expected.representation,
1154 : expected.type);
1155 : }
1156 32 : CHECK(!map->is_deprecated());
1157 32 : CHECK_EQ(*map, *new_map);
1158 32 : CHECK_EQ(expected_field_type_dependency, !dependencies.AreValid());
1159 :
1160 32 : CHECK(!new_map->is_deprecated());
1161 32 : CHECK(expectations.Check(*new_map));
1162 :
1163 32 : Handle<Map> updated_map = Map::Update(isolate, map);
1164 32 : CHECK_EQ(*new_map, *updated_map);
1165 32 : }
1166 :
1167 26067 : TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToDouble) {
1168 4 : CcTest::InitializeVM();
1169 8 : v8::HandleScope scope(CcTest::isolate());
1170 : Isolate* isolate = CcTest::i_isolate();
1171 :
1172 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1173 :
1174 : if (FLAG_track_constant_fields) {
1175 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1176 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1177 : {PropertyConstness::kConst, Representation::Double(), any_type},
1178 4 : {PropertyConstness::kConst, Representation::Double(), any_type});
1179 :
1180 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1181 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1182 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1183 4 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1184 :
1185 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1186 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1187 : {PropertyConstness::kConst, Representation::Double(), any_type},
1188 4 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1189 : }
1190 :
1191 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1192 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1193 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1194 4 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1195 4 : }
1196 :
1197 26067 : TEST(ReconfigureDataFieldAttribute_GeneralizeSmiFieldToTagged) {
1198 4 : CcTest::InitializeVM();
1199 8 : v8::HandleScope scope(CcTest::isolate());
1200 : Isolate* isolate = CcTest::i_isolate();
1201 :
1202 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1203 : Handle<FieldType> value_type =
1204 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
1205 :
1206 : if (FLAG_track_constant_fields) {
1207 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1208 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1209 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1210 4 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
1211 :
1212 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1213 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1214 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1215 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1216 :
1217 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1218 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1219 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1220 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1221 : }
1222 :
1223 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1224 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1225 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1226 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1227 4 : }
1228 :
1229 26067 : TEST(ReconfigureDataFieldAttribute_GeneralizeDoubleFieldToTagged) {
1230 4 : CcTest::InitializeVM();
1231 8 : v8::HandleScope scope(CcTest::isolate());
1232 : Isolate* isolate = CcTest::i_isolate();
1233 :
1234 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1235 : Handle<FieldType> value_type =
1236 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
1237 :
1238 : if (FLAG_track_constant_fields) {
1239 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1240 : {PropertyConstness::kConst, Representation::Double(), any_type},
1241 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1242 4 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
1243 :
1244 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1245 : {PropertyConstness::kConst, Representation::Double(), any_type},
1246 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1247 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1248 :
1249 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1250 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1251 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
1252 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1253 : }
1254 :
1255 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1256 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1257 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1258 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1259 4 : }
1260 :
1261 26067 : TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjFieldToHeapObj) {
1262 4 : CcTest::InitializeVM();
1263 8 : v8::HandleScope scope(CcTest::isolate());
1264 : Isolate* isolate = CcTest::i_isolate();
1265 :
1266 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1267 :
1268 : Handle<FieldType> current_type =
1269 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
1270 :
1271 : Handle<FieldType> new_type =
1272 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
1273 :
1274 4 : Handle<FieldType> expected_type = any_type;
1275 :
1276 : // Check generalizations that trigger deopts.
1277 : if (FLAG_track_constant_fields) {
1278 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1279 : {PropertyConstness::kConst, Representation::HeapObject(), current_type},
1280 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1281 : {PropertyConstness::kConst, Representation::HeapObject(),
1282 4 : 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 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1288 : {PropertyConstness::kConst, Representation::HeapObject(),
1289 : current_type},
1290 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1291 : {PropertyConstness::kMutable, Representation::HeapObject(),
1292 4 : 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 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1304 : {PropertyConstness::kMutable, Representation::HeapObject(),
1305 : current_type},
1306 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1307 : {PropertyConstness::kMutable, Representation::HeapObject(),
1308 4 : expected_type});
1309 : }
1310 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1311 : {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
1312 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1313 : {PropertyConstness::kMutable, Representation::HeapObject(),
1314 4 : expected_type});
1315 : current_type = expected_type;
1316 :
1317 : // Check generalizations that do not trigger deopts.
1318 4 : new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
1319 :
1320 : if (FLAG_track_constant_fields) {
1321 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1322 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1323 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1324 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1325 4 : 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 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1331 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
1332 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1333 : {PropertyConstness::kMutable, Representation::HeapObject(),
1334 4 : 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 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1345 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1346 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
1347 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1348 4 : false);
1349 : }
1350 8 : TestReconfigureDataFieldAttribute_GeneralizeFieldTrivial(
1351 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1352 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
1353 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
1354 4 : false);
1355 4 : }
1356 :
1357 26067 : TEST(ReconfigureDataFieldAttribute_GeneralizeHeapObjectFieldToTagged) {
1358 4 : CcTest::InitializeVM();
1359 8 : v8::HandleScope scope(CcTest::isolate());
1360 : Isolate* isolate = CcTest::i_isolate();
1361 :
1362 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1363 : Handle<FieldType> value_type =
1364 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
1365 :
1366 8 : TestReconfigureDataFieldAttribute_GeneralizeField(
1367 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
1368 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1369 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
1370 4 : }
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 12 : 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 12 : CHECK(map->is_stable());
1399 12 : CHECK(!map->is_deprecated());
1400 12 : CHECK_EQ(*map, *new_map);
1401 :
1402 12 : CHECK(!new_map->is_deprecated());
1403 12 : CHECK(expectations.Check(*new_map));
1404 :
1405 : // Update deprecated |map|, it should become |new_map|.
1406 12 : Handle<Map> updated_map = Map::Update(isolate, map);
1407 12 : CHECK_EQ(*new_map, *updated_map);
1408 12 : }
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 8 : void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
1416 : const Expectations& expectations) {
1417 8 : CHECK(!map->is_deprecated());
1418 8 : CHECK_NE(*map, *new_map);
1419 8 : CHECK(expectations.Check(*map));
1420 :
1421 8 : CHECK(new_map->is_stable());
1422 8 : CHECK(!new_map->is_deprecated());
1423 8 : }
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 4 : void Check(Isolate* isolate, Handle<Map> map, Handle<Map> new_map,
1431 : Expectations& expectations) {
1432 4 : CHECK(!map->is_deprecated());
1433 4 : CHECK_NE(*map, *new_map);
1434 :
1435 8 : CHECK(new_map->GetBackPointer()->IsUndefined(isolate));
1436 60 : for (int i = 0; i < kPropCount; i++) {
1437 28 : expectations.GeneralizeField(i);
1438 : }
1439 :
1440 4 : CHECK(!new_map->is_deprecated());
1441 4 : CHECK(expectations.Check(*new_map));
1442 4 : }
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 24 : static void TestReconfigureProperty_CustomPropertyAfterTargetMap(
1460 : TestConfig& config, Checker& checker) {
1461 : Isolate* isolate = CcTest::i_isolate();
1462 24 : Handle<FieldType> any_type = FieldType::Any(isolate);
1463 :
1464 : const int kCustomPropIndex = kPropCount - 2;
1465 24 : Expectations expectations(isolate);
1466 :
1467 : const int kSplitProp = 2;
1468 : CHECK_LT(kSplitProp, kCustomPropIndex);
1469 :
1470 : const PropertyConstness constness = PropertyConstness::kMutable;
1471 24 : const Representation representation = Representation::Smi();
1472 :
1473 : // Create common part of transition tree.
1474 24 : Handle<Map> initial_map = Map::Create(isolate, 0);
1475 24 : Handle<Map> map = initial_map;
1476 120 : for (int i = 0; i < kSplitProp; i++) {
1477 48 : map = expectations.AddDataField(map, NONE, constness, representation,
1478 : any_type);
1479 : }
1480 24 : CHECK(!map->is_deprecated());
1481 24 : CHECK(map->is_stable());
1482 24 : CHECK(expectations.Check(*map));
1483 :
1484 :
1485 : // Create branch to |map1|.
1486 : Handle<Map> map1 = map;
1487 24 : Expectations expectations1 = expectations;
1488 168 : for (int i = kSplitProp; i < kCustomPropIndex; i++) {
1489 72 : map1 = expectations1.AddDataField(map1, NONE, constness, representation,
1490 : any_type);
1491 : }
1492 24 : map1 = config.AddPropertyAtBranch(1, expectations1, map1);
1493 72 : for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
1494 24 : map1 = expectations1.AddDataField(map1, NONE, constness, representation,
1495 : any_type);
1496 : }
1497 24 : CHECK(!map1->is_deprecated());
1498 24 : CHECK(map1->is_stable());
1499 24 : 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 24 : Expectations expectations2 = expectations;
1506 24 : map2 = expectations2.AddDataField(map2, READ_ONLY, constness, representation,
1507 : any_type);
1508 120 : for (int i = kSplitProp + 1; i < kCustomPropIndex; i++) {
1509 48 : map2 = expectations2.AddDataField(map2, NONE, constness, representation,
1510 : any_type);
1511 : }
1512 24 : map2 = config.AddPropertyAtBranch(2, expectations2, map2);
1513 72 : for (int i = kCustomPropIndex + 1; i < kPropCount; i++) {
1514 24 : map2 = expectations2.AddDataField(map2, NONE, constness, representation,
1515 : any_type);
1516 : }
1517 24 : CHECK(!map2->is_deprecated());
1518 24 : CHECK(map2->is_stable());
1519 24 : 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 24 : Map::ReconfigureExistingProperty(isolate, map2, kSplitProp, kData, NONE);
1526 :
1527 : // |map2| should be left unchanged but marked unstable.
1528 24 : CHECK(!map2->is_stable());
1529 24 : CHECK(!map2->is_deprecated());
1530 24 : CHECK_NE(*map2, *new_map);
1531 24 : CHECK(expectations2.Check(*map2));
1532 :
1533 4 : config.UpdateExpectations(kCustomPropIndex, expectations1);
1534 24 : checker.Check(isolate, map1, new_map, expectations1);
1535 24 : }
1536 :
1537 :
1538 26067 : TEST(ReconfigureDataFieldAttribute_SameDataConstantAfterTargetMap) {
1539 4 : CcTest::InitializeVM();
1540 8 : v8::HandleScope scope(CcTest::isolate());
1541 :
1542 : struct TestConfig {
1543 : Handle<JSFunction> js_func_;
1544 4 : TestConfig() {
1545 : Isolate* isolate = CcTest::i_isolate();
1546 : Factory* factory = isolate->factory();
1547 4 : js_func_ = factory->NewFunctionForTest(factory->empty_string());
1548 4 : }
1549 :
1550 8 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1551 : Handle<Map> map) {
1552 8 : CHECK(branch_id == 1 || branch_id == 2);
1553 : // Add the same data constant property at both transition tree branches.
1554 8 : 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 4 : TestConfig config;
1563 : // Two branches are "compatible" so the |map1| should NOT be deprecated.
1564 : CheckSameMap checker;
1565 4 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1566 4 : }
1567 :
1568 :
1569 26067 : TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) {
1570 4 : CcTest::InitializeVM();
1571 8 : 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 4 : 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 4 : Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
1583 : Handle<SharedFunctionInfo> info =
1584 4 : factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
1585 4 : function_type_ = FieldType::Class(sloppy_map, isolate);
1586 4 : CHECK(sloppy_map->is_stable());
1587 :
1588 : js_func1_ =
1589 8 : factory->NewFunction(sloppy_map, info, isolate->native_context());
1590 :
1591 : js_func2_ =
1592 8 : factory->NewFunction(sloppy_map, info, isolate->native_context());
1593 4 : }
1594 :
1595 8 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1596 : Handle<Map> map) {
1597 8 : CHECK(branch_id == 1 || branch_id == 2);
1598 8 : Handle<JSFunction> js_func = branch_id == 1 ? js_func1_ : js_func2_;
1599 8 : return expectations.AddDataConstant(map, NONE, js_func);
1600 : }
1601 :
1602 4 : 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 : Representation::HeapObject(), function_type_);
1608 4 : }
1609 : };
1610 :
1611 4 : TestConfig config;
1612 : if (FLAG_track_constant_fields) {
1613 : CheckSameMap checker;
1614 4 : 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 : }
1621 4 : }
1622 :
1623 :
1624 26067 : TEST(ReconfigureDataFieldAttribute_DataConstantToAccConstantAfterTargetMap) {
1625 4 : CcTest::InitializeVM();
1626 8 : v8::HandleScope scope(CcTest::isolate());
1627 :
1628 : struct TestConfig {
1629 : Handle<JSFunction> js_func_;
1630 : Handle<AccessorPair> pair_;
1631 4 : TestConfig() {
1632 : Isolate* isolate = CcTest::i_isolate();
1633 : Factory* factory = isolate->factory();
1634 4 : js_func_ = factory->NewFunctionForTest(factory->empty_string());
1635 4 : pair_ = CreateAccessorPair(true, true);
1636 4 : }
1637 :
1638 8 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1639 : Handle<Map> map) {
1640 8 : CHECK(branch_id == 1 || branch_id == 2);
1641 8 : if (branch_id == 1) {
1642 4 : return expectations.AddDataConstant(map, NONE, js_func_);
1643 : } else {
1644 4 : return expectations.AddAccessorConstant(map, NONE, pair_);
1645 : }
1646 : }
1647 :
1648 : void UpdateExpectations(int property_index, Expectations& expectations) {}
1649 : };
1650 :
1651 4 : TestConfig config;
1652 : // These are completely separate branches in transition tree.
1653 : CheckUnrelated checker;
1654 4 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1655 4 : }
1656 :
1657 :
1658 26067 : TEST(ReconfigureDataFieldAttribute_SameAccessorConstantAfterTargetMap) {
1659 4 : CcTest::InitializeVM();
1660 8 : v8::HandleScope scope(CcTest::isolate());
1661 :
1662 : struct TestConfig {
1663 : Handle<AccessorPair> pair_;
1664 4 : TestConfig() { pair_ = CreateAccessorPair(true, true); }
1665 :
1666 8 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1667 : Handle<Map> map) {
1668 8 : CHECK(branch_id == 1 || branch_id == 2);
1669 : // Add the same accessor constant property at both transition tree
1670 : // branches.
1671 8 : 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 4 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1682 4 : }
1683 :
1684 :
1685 26067 : TEST(ReconfigureDataFieldAttribute_AccConstantToAccFieldAfterTargetMap) {
1686 4 : CcTest::InitializeVM();
1687 8 : v8::HandleScope scope(CcTest::isolate());
1688 :
1689 : struct TestConfig {
1690 : Handle<AccessorPair> pair1_;
1691 : Handle<AccessorPair> pair2_;
1692 4 : TestConfig() {
1693 4 : pair1_ = CreateAccessorPair(true, true);
1694 4 : pair2_ = CreateAccessorPair(true, true);
1695 4 : }
1696 :
1697 8 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1698 : Handle<Map> map) {
1699 8 : CHECK(branch_id == 1 || branch_id == 2);
1700 8 : Handle<AccessorPair> pair = branch_id == 1 ? pair1_ : pair2_;
1701 8 : 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 4 : expectations.SetAccessorConstant(property_index, pair2_);
1711 : }
1712 : }
1713 : };
1714 :
1715 4 : 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 4 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1723 : }
1724 4 : }
1725 :
1726 :
1727 26067 : TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) {
1728 4 : CcTest::InitializeVM();
1729 8 : v8::HandleScope scope(CcTest::isolate());
1730 :
1731 : struct TestConfig {
1732 : Handle<AccessorPair> pair_;
1733 4 : TestConfig() { pair_ = CreateAccessorPair(true, true); }
1734 :
1735 8 : Handle<Map> AddPropertyAtBranch(int branch_id, Expectations& expectations,
1736 : Handle<Map> map) {
1737 8 : CHECK(branch_id == 1 || branch_id == 2);
1738 8 : if (branch_id == 1) {
1739 4 : return expectations.AddAccessorConstant(map, NONE, pair_);
1740 : } else {
1741 : Isolate* isolate = CcTest::i_isolate();
1742 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1743 : return expectations.AddDataField(map, NONE, kDefaultFieldConstness,
1744 4 : 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 4 : TestReconfigureProperty_CustomPropertyAfterTargetMap(config, checker);
1755 4 : }
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 64 : static void TestReconfigureElementsKind_GeneralizeField(
1774 : const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
1775 : Isolate* isolate = CcTest::i_isolate();
1776 :
1777 : Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
1778 :
1779 : // Create a map, add required properties to it and initialize expectations.
1780 64 : Handle<Map> initial_map = Map::Create(isolate, 0);
1781 : initial_map->set_instance_type(JS_ARRAY_TYPE);
1782 64 : initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
1783 :
1784 : Handle<Map> map = initial_map;
1785 64 : map = expectations.AsElementsKind(map, PACKED_ELEMENTS);
1786 960 : for (int i = 0; i < kPropCount; i++) {
1787 448 : map = expectations.AddDataField(map, NONE, from.constness,
1788 448 : from.representation, from.type);
1789 : }
1790 64 : CHECK(!map->is_deprecated());
1791 64 : CHECK(map->is_stable());
1792 64 : 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 : Expectations expectations2(isolate, PACKED_SMI_ELEMENTS);
1798 :
1799 : Handle<Map> map2 = initial_map;
1800 960 : for (int i = 0; i < kPropCount; i++) {
1801 448 : if (i == kDiffProp) {
1802 64 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1803 64 : to.representation, to.type);
1804 : } else {
1805 384 : map2 = expectations2.AddDataField(map2, NONE, from.constness,
1806 384 : from.representation, from.type);
1807 : }
1808 : }
1809 64 : CHECK(!map2->is_deprecated());
1810 64 : CHECK(map2->is_stable());
1811 64 : CHECK(expectations2.Check(*map2));
1812 :
1813 128 : Zone zone(isolate->allocator(), ZONE_NAME);
1814 128 : CanonicalHandleScope canonical(isolate);
1815 128 : JSHeapBroker broker(isolate, &zone);
1816 64 : CompilationDependencies dependencies(&broker, &zone);
1817 : MapRef map_ref(&broker, map);
1818 64 : map_ref.SerializeOwnDescriptors();
1819 64 : 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 64 : Map::ReconfigureElementsKind(isolate, map2, PACKED_ELEMENTS);
1825 :
1826 : // |map2| should be left unchanged but marked unstable.
1827 64 : CHECK(!map2->is_stable());
1828 64 : CHECK(!map2->is_deprecated());
1829 64 : CHECK_NE(*map2, *new_map);
1830 64 : CHECK(expectations2.Check(*map2));
1831 :
1832 : // |map| should be deprecated and |new_map| should match new expectations.
1833 64 : expectations.SetDataField(kDiffProp, expected.constness,
1834 : expected.representation, expected.type);
1835 :
1836 64 : CHECK(map->is_deprecated());
1837 64 : CHECK(dependencies.AreValid());
1838 64 : CHECK_NE(*map, *new_map);
1839 :
1840 64 : CHECK(!new_map->is_deprecated());
1841 64 : CHECK(expectations.Check(*new_map));
1842 :
1843 : // Update deprecated |map|, it should become |new_map|.
1844 64 : Handle<Map> updated_map = Map::Update(isolate, map);
1845 64 : CHECK_EQ(*new_map, *updated_map);
1846 64 : CheckMigrationTarget(isolate, *map, *updated_map);
1847 :
1848 : // Ensure Map::FindElementsKindTransitionedMap() is able to find the
1849 : // transitioned map.
1850 : {
1851 : MapHandles map_list;
1852 64 : map_list.push_back(updated_map);
1853 : Map transitioned_map =
1854 64 : map2->FindElementsKindTransitionedMap(isolate, map_list);
1855 64 : CHECK_EQ(*updated_map, transitioned_map);
1856 : }
1857 64 : }
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 32 : static void TestReconfigureElementsKind_GeneralizeFieldTrivial(
1872 : const CRFTData& from, const CRFTData& to, const CRFTData& expected) {
1873 : Isolate* isolate = CcTest::i_isolate();
1874 :
1875 : Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
1876 :
1877 : // Create a map, add required properties to it and initialize expectations.
1878 32 : Handle<Map> initial_map = Map::Create(isolate, 0);
1879 : initial_map->set_instance_type(JS_ARRAY_TYPE);
1880 32 : initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
1881 :
1882 : Handle<Map> map = initial_map;
1883 32 : map = expectations.AsElementsKind(map, PACKED_ELEMENTS);
1884 480 : for (int i = 0; i < kPropCount; i++) {
1885 224 : map = expectations.AddDataField(map, NONE, from.constness,
1886 224 : from.representation, from.type);
1887 : }
1888 32 : CHECK(!map->is_deprecated());
1889 32 : CHECK(map->is_stable());
1890 32 : 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 : Expectations expectations2(isolate, PACKED_SMI_ELEMENTS);
1896 :
1897 : Handle<Map> map2 = initial_map;
1898 480 : for (int i = 0; i < kPropCount; i++) {
1899 224 : if (i == kDiffProp) {
1900 32 : map2 = expectations2.AddDataField(map2, NONE, to.constness,
1901 32 : to.representation, to.type);
1902 : } else {
1903 192 : map2 = expectations2.AddDataField(map2, NONE, from.constness,
1904 192 : from.representation, from.type);
1905 : }
1906 : }
1907 32 : CHECK(!map2->is_deprecated());
1908 32 : CHECK(map2->is_stable());
1909 32 : CHECK(expectations2.Check(*map2));
1910 :
1911 64 : Zone zone(isolate->allocator(), ZONE_NAME);
1912 64 : CanonicalHandleScope canonical(isolate);
1913 64 : JSHeapBroker broker(isolate, &zone);
1914 32 : CompilationDependencies dependencies(&broker, &zone);
1915 : MapRef map_ref(&broker, map);
1916 32 : map_ref.SerializeOwnDescriptors();
1917 :
1918 32 : dependencies.DependOnFieldType(map_ref, kDiffProp);
1919 32 : 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 32 : Map::ReconfigureElementsKind(isolate, map2, PACKED_ELEMENTS);
1925 :
1926 : // |map2| should be left unchanged but marked unstable.
1927 32 : CHECK(!map2->is_stable());
1928 32 : CHECK(!map2->is_deprecated());
1929 32 : CHECK_NE(*map2, *new_map);
1930 32 : 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 32 : expectations.SetDataField(kDiffProp, expected.constness,
1937 : expected.representation, expected.type);
1938 32 : CHECK(!map->is_deprecated());
1939 32 : CHECK_EQ(*map, *new_map);
1940 64 : CHECK_EQ(IsGeneralizableTo(to.constness, from.constness),
1941 : dependencies.AreValid());
1942 :
1943 32 : CHECK(!new_map->is_deprecated());
1944 32 : CHECK(expectations.Check(*new_map));
1945 :
1946 32 : Handle<Map> updated_map = Map::Update(isolate, map);
1947 32 : 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 32 : map_list.push_back(updated_map);
1954 : Map transitioned_map =
1955 32 : map2->FindElementsKindTransitionedMap(isolate, map_list);
1956 32 : CHECK_EQ(*updated_map, transitioned_map);
1957 : }
1958 32 : }
1959 :
1960 26067 : TEST(ReconfigureElementsKind_GeneralizeSmiFieldToDouble) {
1961 4 : CcTest::InitializeVM();
1962 8 : v8::HandleScope scope(CcTest::isolate());
1963 : Isolate* isolate = CcTest::i_isolate();
1964 :
1965 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1966 :
1967 : if (FLAG_track_constant_fields) {
1968 8 : TestReconfigureElementsKind_GeneralizeField(
1969 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1970 : {PropertyConstness::kConst, Representation::Double(), any_type},
1971 4 : {PropertyConstness::kConst, Representation::Double(), any_type});
1972 :
1973 8 : TestReconfigureElementsKind_GeneralizeField(
1974 : {PropertyConstness::kConst, Representation::Smi(), any_type},
1975 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1976 4 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1977 :
1978 8 : TestReconfigureElementsKind_GeneralizeField(
1979 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1980 : {PropertyConstness::kConst, Representation::Double(), any_type},
1981 4 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1982 : }
1983 8 : TestReconfigureElementsKind_GeneralizeField(
1984 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
1985 : {PropertyConstness::kMutable, Representation::Double(), any_type},
1986 4 : {PropertyConstness::kMutable, Representation::Double(), any_type});
1987 4 : }
1988 :
1989 26067 : TEST(ReconfigureElementsKind_GeneralizeSmiFieldToTagged) {
1990 4 : CcTest::InitializeVM();
1991 8 : v8::HandleScope scope(CcTest::isolate());
1992 : Isolate* isolate = CcTest::i_isolate();
1993 :
1994 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
1995 : Handle<FieldType> value_type =
1996 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
1997 :
1998 : if (FLAG_track_constant_fields) {
1999 8 : TestReconfigureElementsKind_GeneralizeField(
2000 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2001 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2002 4 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
2003 :
2004 8 : TestReconfigureElementsKind_GeneralizeField(
2005 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2006 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2007 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2008 :
2009 8 : TestReconfigureElementsKind_GeneralizeField(
2010 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2011 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2012 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2013 : }
2014 8 : TestReconfigureElementsKind_GeneralizeField(
2015 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2016 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2017 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2018 4 : }
2019 :
2020 26067 : TEST(ReconfigureElementsKind_GeneralizeDoubleFieldToTagged) {
2021 4 : CcTest::InitializeVM();
2022 8 : v8::HandleScope scope(CcTest::isolate());
2023 : Isolate* isolate = CcTest::i_isolate();
2024 :
2025 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2026 : Handle<FieldType> value_type =
2027 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2028 :
2029 : if (FLAG_track_constant_fields) {
2030 8 : TestReconfigureElementsKind_GeneralizeField(
2031 : {PropertyConstness::kConst, Representation::Double(), any_type},
2032 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2033 4 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
2034 :
2035 8 : TestReconfigureElementsKind_GeneralizeField(
2036 : {PropertyConstness::kConst, Representation::Double(), any_type},
2037 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2038 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2039 :
2040 8 : TestReconfigureElementsKind_GeneralizeField(
2041 : {PropertyConstness::kMutable, Representation::Double(), any_type},
2042 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2043 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2044 : }
2045 8 : TestReconfigureElementsKind_GeneralizeField(
2046 : {PropertyConstness::kMutable, Representation::Double(), any_type},
2047 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2048 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2049 4 : }
2050 :
2051 26067 : TEST(ReconfigureElementsKind_GeneralizeHeapObjFieldToHeapObj) {
2052 4 : CcTest::InitializeVM();
2053 8 : v8::HandleScope scope(CcTest::isolate());
2054 : Isolate* isolate = CcTest::i_isolate();
2055 :
2056 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2057 :
2058 : Handle<FieldType> current_type =
2059 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2060 :
2061 : Handle<FieldType> new_type =
2062 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2063 :
2064 4 : Handle<FieldType> expected_type = any_type;
2065 :
2066 : // Check generalizations that trigger deopts.
2067 : if (FLAG_track_constant_fields) {
2068 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2069 : {PropertyConstness::kConst, Representation::HeapObject(), current_type},
2070 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2071 : {PropertyConstness::kConst, Representation::HeapObject(),
2072 4 : 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 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2077 : {PropertyConstness::kConst, Representation::HeapObject(),
2078 : current_type},
2079 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2080 : {PropertyConstness::kMutable, Representation::HeapObject(),
2081 4 : 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 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2093 : {PropertyConstness::kMutable, Representation::HeapObject(),
2094 : current_type},
2095 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2096 : {PropertyConstness::kMutable, Representation::HeapObject(),
2097 4 : expected_type});
2098 : }
2099 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2100 : {PropertyConstness::kMutable, Representation::HeapObject(), current_type},
2101 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2102 : {PropertyConstness::kMutable, Representation::HeapObject(),
2103 4 : expected_type});
2104 : current_type = expected_type;
2105 :
2106 : // Check generalizations that do not trigger deopts.
2107 4 : new_type = FieldType::Class(Map::Create(isolate, 0), isolate);
2108 :
2109 : if (FLAG_track_constant_fields) {
2110 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2111 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
2112 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2113 4 : {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 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2119 : {PropertyConstness::kConst, Representation::HeapObject(), any_type},
2120 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2121 : {PropertyConstness::kMutable, Representation::HeapObject(),
2122 4 : 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 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2134 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
2135 : {PropertyConstness::kConst, Representation::HeapObject(), new_type},
2136 4 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type});
2137 : }
2138 8 : TestReconfigureElementsKind_GeneralizeFieldTrivial(
2139 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type},
2140 : {PropertyConstness::kMutable, Representation::HeapObject(), new_type},
2141 4 : {PropertyConstness::kMutable, Representation::HeapObject(), any_type});
2142 4 : }
2143 :
2144 26067 : TEST(ReconfigureElementsKind_GeneralizeHeapObjectFieldToTagged) {
2145 4 : CcTest::InitializeVM();
2146 8 : v8::HandleScope scope(CcTest::isolate());
2147 : Isolate* isolate = CcTest::i_isolate();
2148 :
2149 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2150 : Handle<FieldType> value_type =
2151 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2152 :
2153 : if (FLAG_track_constant_fields) {
2154 8 : TestReconfigureElementsKind_GeneralizeField(
2155 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2156 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2157 4 : {PropertyConstness::kConst, Representation::Tagged(), any_type});
2158 :
2159 8 : TestReconfigureElementsKind_GeneralizeField(
2160 : {PropertyConstness::kConst, Representation::HeapObject(), value_type},
2161 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2162 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2163 :
2164 8 : TestReconfigureElementsKind_GeneralizeField(
2165 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2166 : {PropertyConstness::kConst, Representation::Smi(), any_type},
2167 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2168 : }
2169 8 : TestReconfigureElementsKind_GeneralizeField(
2170 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2171 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2172 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2173 4 : }
2174 :
2175 : ////////////////////////////////////////////////////////////////////////////////
2176 : // A set of tests checking split map deprecation.
2177 : //
2178 :
2179 26067 : TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
2180 4 : CcTest::InitializeVM();
2181 8 : v8::HandleScope scope(CcTest::isolate());
2182 : Isolate* isolate = CcTest::i_isolate();
2183 :
2184 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2185 :
2186 4 : Expectations expectations(isolate);
2187 :
2188 : // Create a map, add required properties to it and initialize expectations.
2189 4 : Handle<Map> initial_map = Map::Create(isolate, 0);
2190 4 : Handle<Map> map = initial_map;
2191 60 : for (int i = 0; i < kPropCount; i++) {
2192 : map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
2193 28 : Representation::Smi(), any_type);
2194 : }
2195 4 : CHECK(!map->is_deprecated());
2196 4 : 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 36 : for (int i = 0; i < kSplitProp + 1; i++) {
2204 16 : if (i == kSplitProp) {
2205 : split_map = map2;
2206 : }
2207 :
2208 16 : Handle<String> name = MakeName("prop", i);
2209 : Map target = TransitionsAccessor(isolate, map2)
2210 32 : .SearchTransition(*name, kData, NONE);
2211 16 : CHECK(!target.is_null());
2212 : map2 = handle(target, isolate);
2213 : }
2214 :
2215 : map2 = Map::ReconfigureProperty(isolate, map2, kSplitProp, kData, NONE,
2216 4 : Representation::Double(), any_type);
2217 : expectations.SetDataField(kSplitProp, PropertyConstness::kMutable,
2218 : Representation::Double(), any_type);
2219 :
2220 4 : CHECK(expectations.Check(*split_map, kSplitProp));
2221 4 : CHECK(expectations.Check(*map2, kSplitProp + 1));
2222 : }
2223 :
2224 : // At this point |map| should be deprecated and disconnected from the
2225 : // transition tree.
2226 4 : CHECK(map->is_deprecated());
2227 4 : CHECK(!split_map->is_deprecated());
2228 4 : CHECK(map2->is_stable());
2229 4 : CHECK(!map2->is_deprecated());
2230 :
2231 : // Fill in transition tree of |map2| so that it can't have more transitions.
2232 12292 : for (int i = 0; i < TransitionsAccessor::kMaxNumberOfTransitions; i++) {
2233 6144 : CHECK(TransitionsAccessor(isolate, map2).CanHaveMoreTransitions());
2234 6144 : Handle<String> name = MakeName("foo", i);
2235 12288 : Map::CopyWithField(isolate, map2, name, any_type, NONE,
2236 : PropertyConstness::kMutable, Representation::Smi(),
2237 6144 : INSERT_TRANSITION)
2238 : .ToHandleChecked();
2239 : }
2240 4 : 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 4 : Handle<Map> updated_map = Map::Update(isolate, map);
2245 8 : CHECK(updated_map->GetBackPointer()->IsUndefined(isolate));
2246 :
2247 60 : for (int i = 0; i < kPropCount; i++) {
2248 : expectations.SetDataField(i, PropertyConstness::kMutable,
2249 : Representation::Tagged(), any_type);
2250 : }
2251 4 : CHECK(expectations.Check(*updated_map));
2252 4 : }
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 32 : 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 32 : Expectations expectations(isolate);
2283 :
2284 : // Create a map, add required properties to it and initialize expectations.
2285 32 : Handle<Map> initial_map = Map::Create(isolate, 0);
2286 32 : Handle<Map> map = initial_map;
2287 480 : for (int i = 0; i < kPropCount; i++) {
2288 224 : map = expectations.AddDataField(map, NONE, from.constness,
2289 : from.representation, from.type);
2290 : }
2291 32 : CHECK(!map->is_deprecated());
2292 32 : CHECK(map->is_stable());
2293 32 : CHECK(expectations.Check(*map));
2294 :
2295 32 : Expectations expectations2 = expectations;
2296 :
2297 : // Apply some special transition to |map|.
2298 32 : CHECK(map->owns_descriptors());
2299 32 : Handle<Map> map2 = config.Transition(map, expectations2);
2300 :
2301 : // |map| should still match expectations.
2302 32 : CHECK(!map->is_deprecated());
2303 32 : CHECK(expectations.Check(*map));
2304 :
2305 : if (config.generalizes_representations()) {
2306 120 : for (int i = 0; i < kPropCount; i++) {
2307 56 : expectations2.GeneralizeField(i);
2308 : }
2309 : }
2310 :
2311 32 : CHECK(!map2->is_deprecated());
2312 32 : CHECK(map2->is_stable());
2313 32 : CHECK(expectations2.Check(*map2));
2314 :
2315 : // Create new maps by generalizing representation of propX field.
2316 480 : Handle<Map> maps[kPropCount];
2317 480 : for (int i = 0; i < kPropCount; i++) {
2318 : Handle<Map> new_map = Map::ReconfigureProperty(isolate, map, i, kData, NONE,
2319 224 : to.representation, to.type);
2320 224 : maps[i] = new_map;
2321 :
2322 224 : expectations.SetDataField(i, expected.constness, expected.representation,
2323 : expected.type);
2324 :
2325 224 : CHECK(map->is_deprecated());
2326 224 : CHECK_NE(*map, *new_map);
2327 416 : CHECK(i == 0 || maps[i - 1]->is_deprecated());
2328 224 : CHECK(expectations.Check(*new_map));
2329 :
2330 224 : Handle<Map> new_map2 = Map::Update(isolate, map2);
2331 224 : CHECK(!new_map2->is_deprecated());
2332 224 : CHECK(!new_map2->is_dictionary_map());
2333 :
2334 : Handle<Map> tmp_map;
2335 448 : 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 224 : 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 840 : for (int i = 0; i < kPropCount; i++) {
2348 392 : expectations2.GeneralizeField(i);
2349 : }
2350 112 : CHECK(new_map2->GetBackPointer()->IsUndefined(isolate));
2351 56 : CHECK(expectations2.Check(*new_map2));
2352 : } else {
2353 168 : expectations2.SetDataField(i, expected.constness, expected.representation,
2354 : expected.type);
2355 :
2356 336 : CHECK(!new_map2->GetBackPointer()->IsUndefined(isolate));
2357 168 : CHECK(expectations2.Check(*new_map2));
2358 : }
2359 : }
2360 :
2361 32 : Handle<Map> active_map = maps[kPropCount - 1];
2362 32 : CHECK(!active_map->is_deprecated());
2363 :
2364 : // Update all deprecated maps and check that they are now the same.
2365 32 : Handle<Map> updated_map = Map::Update(isolate, map);
2366 32 : CHECK_EQ(*active_map, *updated_map);
2367 32 : CheckMigrationTarget(isolate, *map, *updated_map);
2368 480 : for (int i = 0; i < kPropCount; i++) {
2369 224 : updated_map = Map::Update(isolate, maps[i]);
2370 224 : CHECK_EQ(*active_map, *updated_map);
2371 448 : CheckMigrationTarget(isolate, *maps[i], *updated_map);
2372 : }
2373 32 : }
2374 :
2375 :
2376 26067 : TEST(ElementsKindTransitionFromMapOwningDescriptor) {
2377 4 : CcTest::InitializeVM();
2378 8 : v8::HandleScope scope(CcTest::isolate());
2379 : Isolate* isolate = CcTest::i_isolate();
2380 :
2381 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2382 : Handle<FieldType> value_type =
2383 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2384 :
2385 : struct TestConfig {
2386 : TestConfig(PropertyAttributes attributes, Handle<Symbol> symbol)
2387 12 : : attributes(attributes), symbol(symbol) {}
2388 :
2389 12 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2390 : expectations.SetElementsKind(DICTIONARY_ELEMENTS);
2391 12 : expectations.ChangeAttributesForAllProperties(attributes);
2392 : return Map::CopyForPreventExtensions(CcTest::i_isolate(), map, attributes,
2393 24 : 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 28 : for (size_t i = 0; i < arraysize(configs); i++) {
2407 24 : TestGeneralizeFieldWithSpecialTransition(
2408 : configs[i],
2409 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2410 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2411 12 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2412 : }
2413 4 : }
2414 :
2415 :
2416 26067 : TEST(ElementsKindTransitionFromMapNotOwningDescriptor) {
2417 4 : CcTest::InitializeVM();
2418 8 : v8::HandleScope scope(CcTest::isolate());
2419 : Isolate* isolate = CcTest::i_isolate();
2420 :
2421 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2422 : Handle<FieldType> value_type =
2423 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2424 :
2425 : struct TestConfig {
2426 : TestConfig(PropertyAttributes attributes, Handle<Symbol> symbol)
2427 12 : : attributes(attributes), symbol(symbol) {}
2428 :
2429 12 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2430 : Isolate* isolate = CcTest::i_isolate();
2431 12 : Handle<FieldType> any_type = FieldType::Any(isolate);
2432 :
2433 : // Add one more transition to |map| in order to prevent descriptors
2434 : // ownership.
2435 12 : CHECK(map->owns_descriptors());
2436 24 : Map::CopyWithField(isolate, map, MakeString("foo"), any_type, NONE,
2437 : PropertyConstness::kMutable, Representation::Smi(),
2438 12 : INSERT_TRANSITION)
2439 : .ToHandleChecked();
2440 12 : CHECK(!map->owns_descriptors());
2441 :
2442 : expectations.SetElementsKind(DICTIONARY_ELEMENTS);
2443 12 : expectations.ChangeAttributesForAllProperties(attributes);
2444 : return Map::CopyForPreventExtensions(isolate, map, attributes, symbol,
2445 12 : "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 28 : for (size_t i = 0; i < arraysize(configs); i++) {
2459 24 : TestGeneralizeFieldWithSpecialTransition(
2460 : configs[i],
2461 : {PropertyConstness::kMutable, Representation::Smi(), any_type},
2462 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2463 12 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2464 : }
2465 4 : }
2466 :
2467 :
2468 26067 : TEST(PrototypeTransitionFromMapOwningDescriptor) {
2469 4 : CcTest::InitializeVM();
2470 8 : v8::HandleScope scope(CcTest::isolate());
2471 : Isolate* isolate = CcTest::i_isolate();
2472 :
2473 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2474 : Handle<FieldType> value_type =
2475 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2476 :
2477 : struct TestConfig {
2478 : Handle<JSObject> prototype_;
2479 :
2480 4 : TestConfig() {
2481 : Isolate* isolate = CcTest::i_isolate();
2482 : Factory* factory = isolate->factory();
2483 4 : prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
2484 4 : }
2485 :
2486 4 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2487 4 : 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 4 : TestConfig config;
2496 8 : TestGeneralizeFieldWithSpecialTransition(
2497 : config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
2498 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2499 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2500 4 : }
2501 :
2502 :
2503 26067 : TEST(PrototypeTransitionFromMapNotOwningDescriptor) {
2504 4 : CcTest::InitializeVM();
2505 8 : v8::HandleScope scope(CcTest::isolate());
2506 : Isolate* isolate = CcTest::i_isolate();
2507 :
2508 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2509 : Handle<FieldType> value_type =
2510 4 : FieldType::Class(Map::Create(isolate, 0), isolate);
2511 :
2512 : struct TestConfig {
2513 : Handle<JSObject> prototype_;
2514 :
2515 4 : TestConfig() {
2516 : Isolate* isolate = CcTest::i_isolate();
2517 : Factory* factory = isolate->factory();
2518 4 : prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0));
2519 4 : }
2520 :
2521 4 : Handle<Map> Transition(Handle<Map> map, Expectations& expectations) {
2522 : Isolate* isolate = CcTest::i_isolate();
2523 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2524 :
2525 : // Add one more transition to |map| in order to prevent descriptors
2526 : // ownership.
2527 4 : CHECK(map->owns_descriptors());
2528 8 : Map::CopyWithField(isolate, map, MakeString("foo"), any_type, NONE,
2529 : PropertyConstness::kMutable, Representation::Smi(),
2530 4 : INSERT_TRANSITION)
2531 : .ToHandleChecked();
2532 4 : CHECK(!map->owns_descriptors());
2533 :
2534 4 : 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 4 : TestConfig config;
2543 8 : TestGeneralizeFieldWithSpecialTransition(
2544 : config, {PropertyConstness::kMutable, Representation::Smi(), any_type},
2545 : {PropertyConstness::kMutable, Representation::HeapObject(), value_type},
2546 4 : {PropertyConstness::kMutable, Representation::Tagged(), any_type});
2547 4 : }
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 12 : value_(value) {}
2571 :
2572 : Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2573 : return expectations.TransitionToDataField(
2574 12 : 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 16 : : attributes_(attributes), value_(value) {}
2586 :
2587 : Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2588 20 : 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 4 : : attributes_(attributes), pair_(pair) {}
2600 :
2601 : Handle<Map> DoTransition(Expectations& expectations, Handle<Map> map) {
2602 8 : 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 8 : heap_type_(heap_type) {}
2665 :
2666 8 : void Check(Isolate* isolate, Expectations& expectations2, Handle<Map> map1,
2667 : Handle<Map> map2) {
2668 8 : CHECK(!map2->is_deprecated());
2669 :
2670 8 : CHECK(map1->is_deprecated());
2671 8 : CHECK_NE(*map1, *map2);
2672 8 : Handle<Map> updated_map = Map::Update(isolate, map1);
2673 8 : CHECK_EQ(*map2, *updated_map);
2674 8 : CheckMigrationTarget(isolate, *map1, *updated_map);
2675 :
2676 8 : expectations2.SetDataField(descriptor_, attributes_, constness_,
2677 : representation_, heap_type_);
2678 8 : CHECK(expectations2.Check(*map2));
2679 8 : }
2680 : };
2681 :
2682 :
2683 : // Checks that existing transition was taken as is.
2684 : struct SameMapChecker {
2685 12 : void Check(Isolate* isolate, Expectations& expectations, Handle<Map> map1,
2686 : Handle<Map> map2) {
2687 12 : CHECK(!map2->is_deprecated());
2688 12 : CHECK_EQ(*map1, *map2);
2689 12 : CHECK(expectations.Check(*map2));
2690 12 : }
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 20 : static void TestTransitionTo(TransitionOp1& transition_op1,
2723 : TransitionOp2& transition_op2, Checker& checker) {
2724 : Isolate* isolate = CcTest::i_isolate();
2725 20 : Handle<FieldType> any_type = FieldType::Any(isolate);
2726 :
2727 20 : Expectations expectations(isolate);
2728 :
2729 : // Create a map, add required properties to it and initialize expectations.
2730 20 : Handle<Map> initial_map = Map::Create(isolate, 0);
2731 20 : Handle<Map> map = initial_map;
2732 260 : for (int i = 0; i < kPropCount - 1; i++) {
2733 120 : map = expectations.AddDataField(map, NONE, PropertyConstness::kMutable,
2734 : Representation::Smi(), any_type);
2735 : }
2736 20 : CHECK(expectations.Check(*map));
2737 :
2738 20 : Expectations expectations1 = expectations;
2739 : Handle<Map> map1 = transition_op1.DoTransition(expectations1, map);
2740 20 : CHECK(expectations1.Check(*map1));
2741 :
2742 20 : Expectations expectations2 = expectations;
2743 20 : Handle<Map> map2 = transition_op2.DoTransition(expectations2, map);
2744 :
2745 : // Let the test customization do the check.
2746 20 : checker.Check(isolate, expectations2, map1, map2);
2747 20 : }
2748 :
2749 :
2750 26067 : TEST(TransitionDataFieldToDataField) {
2751 4 : CcTest::InitializeVM();
2752 8 : v8::HandleScope scope(CcTest::isolate());
2753 : Isolate* isolate = CcTest::i_isolate();
2754 :
2755 4 : 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 4 : 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 4 : TestTransitionTo(transition_op1, transition_op2, checker);
2769 4 : }
2770 :
2771 26067 : TEST(TransitionDataConstantToSameDataConstant) {
2772 4 : CcTest::InitializeVM();
2773 8 : v8::HandleScope scope(CcTest::isolate());
2774 : Isolate* isolate = CcTest::i_isolate();
2775 : Factory* factory = isolate->factory();
2776 :
2777 : Handle<JSFunction> js_func =
2778 4 : factory->NewFunctionForTest(factory->empty_string());
2779 : TransitionToDataConstantOperator transition_op(js_func);
2780 :
2781 : SameMapChecker checker;
2782 4 : TestTransitionTo(transition_op, transition_op, checker);
2783 4 : }
2784 :
2785 :
2786 26067 : TEST(TransitionDataConstantToAnotherDataConstant) {
2787 4 : CcTest::InitializeVM();
2788 8 : 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 4 : Map::CopyInitialMap(isolate, isolate->sloppy_function_map());
2795 : Handle<SharedFunctionInfo> info =
2796 4 : factory->NewSharedFunctionInfoForBuiltin(name, Builtins::kIllegal);
2797 4 : Handle<FieldType> function_type = FieldType::Class(sloppy_map, isolate);
2798 4 : CHECK(sloppy_map->is_stable());
2799 :
2800 : Handle<JSFunction> js_func1 =
2801 8 : factory->NewFunction(sloppy_map, info, isolate->native_context());
2802 : TransitionToDataConstantOperator transition_op1(js_func1);
2803 :
2804 : Handle<JSFunction> js_func2 =
2805 8 : 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 4 : 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 : }
2818 4 : }
2819 :
2820 :
2821 26067 : TEST(TransitionDataConstantToDataField) {
2822 4 : CcTest::InitializeVM();
2823 8 : v8::HandleScope scope(CcTest::isolate());
2824 : Isolate* isolate = CcTest::i_isolate();
2825 : Factory* factory = isolate->factory();
2826 :
2827 4 : Handle<FieldType> any_type = FieldType::Any(isolate);
2828 :
2829 : Handle<JSFunction> js_func1 =
2830 4 : factory->NewFunctionForTest(factory->empty_string());
2831 : TransitionToDataConstantOperator transition_op1(js_func1);
2832 :
2833 4 : 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 4 : TestTransitionTo(transition_op1, transition_op2, checker);
2841 4 : }
2842 :
2843 :
2844 26067 : TEST(TransitionAccessorConstantToSameAccessorConstant) {
2845 4 : CcTest::InitializeVM();
2846 8 : v8::HandleScope scope(CcTest::isolate());
2847 :
2848 4 : Handle<AccessorPair> pair = CreateAccessorPair(true, true);
2849 : TransitionToAccessorConstantOperator transition_op(pair);
2850 :
2851 : SameMapChecker checker;
2852 4 : TestTransitionTo(transition_op, transition_op, checker);
2853 4 : }
2854 :
2855 : // TODO(ishell): add this test once IS_ACCESSOR_FIELD_SUPPORTED is supported.
2856 : // TEST(TransitionAccessorConstantToAnotherAccessorConstant)
2857 :
2858 26067 : TEST(HoleyMutableHeapNumber) {
2859 4 : CcTest::InitializeVM();
2860 8 : v8::HandleScope scope(CcTest::isolate());
2861 : Isolate* isolate = CcTest::i_isolate();
2862 :
2863 : auto mhn = isolate->factory()->NewMutableHeapNumberWithHoleNaN();
2864 4 : CHECK_EQ(kHoleNanInt64, mhn->value_as_bits());
2865 :
2866 4 : mhn = isolate->factory()->NewMutableHeapNumber(0.0);
2867 4 : CHECK_EQ(uint64_t{0}, mhn->value_as_bits());
2868 :
2869 : mhn->set_value_as_bits(kHoleNanInt64);
2870 4 : 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 4 : Representation::Double());
2878 4 : CHECK(obj->IsMutableHeapNumber());
2879 4 : CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj)->value_as_bits());
2880 :
2881 4 : obj = Object::NewStorageFor(isolate, mhn, Representation::Double());
2882 4 : CHECK(obj->IsMutableHeapNumber());
2883 4 : CHECK_EQ(kHoleNanInt64, MutableHeapNumber::cast(*obj)->value_as_bits());
2884 4 : }
2885 :
2886 : } // namespace test_field_type_tracking
2887 : } // namespace compiler
2888 : } // namespace internal
2889 78189 : } // namespace v8
|