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