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