Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <stdlib.h>
6 : #include <sstream>
7 : #include <utility>
8 :
9 : #include "src/api.h"
10 : #include "src/objects-inl.h"
11 : #include "src/objects.h"
12 : #include "src/v8.h"
13 :
14 : #include "test/cctest/cctest.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 : namespace test_inobject_slack_tracking {
19 :
20 : static const int kMaxInobjectProperties = JSObject::kMaxInObjectProperties;
21 :
22 : template <typename T>
23 : static Handle<T> OpenHandle(v8::Local<v8::Value> value) {
24 : Handle<Object> obj = v8::Utils::OpenHandle(*value);
25 : return Handle<T>::cast(obj);
26 : }
27 :
28 :
29 6615 : static inline v8::Local<v8::Value> Run(v8::Local<v8::Script> script) {
30 : v8::Local<v8::Value> result;
31 13230 : if (script->Run(v8::Isolate::GetCurrent()->GetCurrentContext())
32 6615 : .ToLocal(&result)) {
33 6615 : return result;
34 : }
35 0 : return v8::Local<v8::Value>();
36 : }
37 :
38 :
39 :
40 : template <typename T = Object>
41 935 : Handle<T> GetLexical(const char* name) {
42 : Isolate* isolate = CcTest::i_isolate();
43 : Factory* factory = isolate->factory();
44 :
45 935 : Handle<String> str_name = factory->InternalizeUtf8String(name);
46 : Handle<ScriptContextTable> script_contexts(
47 1870 : isolate->native_context()->script_context_table());
48 :
49 : ScriptContextTable::LookupResult lookup_result;
50 935 : if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
51 : Handle<Object> result =
52 : FixedArray::get(*ScriptContextTable::GetContext(
53 935 : script_contexts, lookup_result.context_index),
54 2805 : lookup_result.slot_index, isolate);
55 : return Handle<T>::cast(result);
56 : }
57 0 : return Handle<T>();
58 : }
59 :
60 :
61 : template <typename T = Object>
62 : Handle<T> GetLexical(const std::string& name) {
63 525 : return GetLexical<T>(name.c_str());
64 : }
65 :
66 : template <typename T>
67 : static inline Handle<T> RunI(v8::Local<v8::Script> script) {
68 6605 : return OpenHandle<T>(Run(script));
69 : }
70 :
71 : template <typename T>
72 60 : static inline Handle<T> CompileRunI(const char* script) {
73 60 : return OpenHandle<T>(CompileRun(script));
74 : }
75 :
76 :
77 316570 : static Object* GetFieldValue(JSObject* obj, int property_index) {
78 316570 : FieldIndex index = FieldIndex::ForPropertyIndex(obj->map(), property_index);
79 316570 : return obj->RawFastPropertyAt(index);
80 : }
81 :
82 :
83 440 : static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
84 440 : if (obj->IsUnboxedDoubleField(field_index)) {
85 440 : return obj->RawFastDoublePropertyAt(field_index);
86 : } else {
87 0 : Object* value = obj->RawFastPropertyAt(field_index);
88 0 : CHECK(value->IsMutableHeapNumber());
89 0 : return HeapNumber::cast(value)->value();
90 : }
91 : }
92 :
93 :
94 440 : static double GetDoubleFieldValue(JSObject* obj, int property_index) {
95 440 : FieldIndex index = FieldIndex::ForPropertyIndex(obj->map(), property_index);
96 440 : return GetDoubleFieldValue(obj, index);
97 : }
98 :
99 :
100 6745 : bool IsObjectShrinkable(JSObject* obj) {
101 : Handle<Map> filler_map =
102 : CcTest::i_isolate()->factory()->one_pointer_filler_map();
103 :
104 : int inobject_properties = obj->map()->GetInObjectProperties();
105 : int unused = obj->map()->unused_property_fields();
106 6745 : if (unused == 0) return false;
107 :
108 320455 : for (int i = inobject_properties - unused; i < inobject_properties; i++) {
109 315690 : if (*filler_map != GetFieldValue(obj, i)) {
110 : return false;
111 : }
112 : }
113 : return true;
114 : }
115 :
116 :
117 23728 : TEST(JSObjectBasic) {
118 : // Avoid eventual completion of in-object slack tracking.
119 10 : FLAG_always_opt = false;
120 10 : CcTest::InitializeVM();
121 10 : v8::HandleScope scope(CcTest::isolate());
122 : const char* source =
123 : "function A() {"
124 : " this.a = 42;"
125 : " this.d = 4.2;"
126 : " this.o = this;"
127 : "}";
128 : CompileRun(source);
129 :
130 10 : Handle<JSFunction> func = GetGlobal<JSFunction>("A");
131 :
132 : // Zero instances were created so far.
133 10 : CHECK(!func->has_initial_map());
134 :
135 : v8::Local<v8::Script> new_A_script = v8_compile("new A();");
136 :
137 : Handle<JSObject> obj = RunI<JSObject>(new_A_script);
138 :
139 10 : CHECK(func->has_initial_map());
140 : Handle<Map> initial_map(func->initial_map());
141 :
142 : // One instance created.
143 10 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
144 : initial_map->construction_counter());
145 10 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
146 :
147 : // There must be at least some slack.
148 10 : CHECK_LT(5, obj->map()->GetInObjectProperties());
149 10 : CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0));
150 10 : CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1));
151 20 : CHECK_EQ(*obj, GetFieldValue(*obj, 2));
152 10 : CHECK(IsObjectShrinkable(*obj));
153 :
154 : // Create several objects to complete the tracking.
155 60 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
156 60 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
157 : Handle<JSObject> tmp = RunI<JSObject>(new_A_script);
158 120 : CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
159 : IsObjectShrinkable(*tmp));
160 : }
161 10 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
162 10 : CHECK(!IsObjectShrinkable(*obj));
163 :
164 : // No slack left.
165 10 : CHECK_EQ(3, obj->map()->GetInObjectProperties());
166 10 : }
167 :
168 :
169 23723 : TEST(JSObjectBasicNoInlineNew) {
170 5 : FLAG_inline_new = false;
171 5 : TestJSObjectBasic();
172 5 : }
173 :
174 :
175 23728 : TEST(JSObjectComplex) {
176 : // Avoid eventual completion of in-object slack tracking.
177 10 : FLAG_always_opt = false;
178 10 : CcTest::InitializeVM();
179 10 : v8::HandleScope scope(CcTest::isolate());
180 : const char* source =
181 : "function A(n) {"
182 : " if (n > 0) this.a = 42;"
183 : " if (n > 1) this.d = 4.2;"
184 : " if (n > 2) this.o1 = this;"
185 : " if (n > 3) this.o2 = this;"
186 : " if (n > 4) this.o3 = this;"
187 : " if (n > 5) this.o4 = this;"
188 : "}";
189 : CompileRun(source);
190 :
191 10 : Handle<JSFunction> func = GetGlobal<JSFunction>("A");
192 :
193 : // Zero instances were created so far.
194 10 : CHECK(!func->has_initial_map());
195 :
196 10 : Handle<JSObject> obj1 = CompileRunI<JSObject>("new A(1);");
197 10 : Handle<JSObject> obj3 = CompileRunI<JSObject>("new A(3);");
198 10 : Handle<JSObject> obj5 = CompileRunI<JSObject>("new A(5);");
199 :
200 10 : CHECK(func->has_initial_map());
201 : Handle<Map> initial_map(func->initial_map());
202 :
203 : // Three instances created.
204 10 : CHECK_EQ(Map::kSlackTrackingCounterStart - 3,
205 : initial_map->construction_counter());
206 10 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
207 :
208 : // There must be at least some slack.
209 10 : CHECK_LT(5, obj3->map()->GetInObjectProperties());
210 10 : CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj3, 0));
211 10 : CHECK_EQ(4.2, GetDoubleFieldValue(*obj3, 1));
212 20 : CHECK_EQ(*obj3, GetFieldValue(*obj3, 2));
213 10 : CHECK(IsObjectShrinkable(*obj1));
214 10 : CHECK(IsObjectShrinkable(*obj3));
215 10 : CHECK(IsObjectShrinkable(*obj5));
216 :
217 : // Create several objects to complete the tracking.
218 40 : for (int i = 3; i < Map::kGenerousAllocationCount; i++) {
219 40 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
220 : CompileRun("new A(3);");
221 : }
222 10 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
223 :
224 : // obj1 and obj2 stays shrinkable because we don't clear unused fields.
225 10 : CHECK(IsObjectShrinkable(*obj1));
226 10 : CHECK(IsObjectShrinkable(*obj3));
227 10 : CHECK(!IsObjectShrinkable(*obj5));
228 :
229 10 : CHECK_EQ(5, obj1->map()->GetInObjectProperties());
230 10 : CHECK_EQ(4, obj1->map()->unused_property_fields());
231 :
232 10 : CHECK_EQ(5, obj3->map()->GetInObjectProperties());
233 10 : CHECK_EQ(2, obj3->map()->unused_property_fields());
234 :
235 10 : CHECK_EQ(5, obj5->map()->GetInObjectProperties());
236 10 : CHECK_EQ(0, obj5->map()->unused_property_fields());
237 :
238 : // Since slack tracking is complete, the new objects should not be shrinkable.
239 10 : obj1 = CompileRunI<JSObject>("new A(1);");
240 10 : obj3 = CompileRunI<JSObject>("new A(3);");
241 10 : obj5 = CompileRunI<JSObject>("new A(5);");
242 :
243 10 : CHECK(!IsObjectShrinkable(*obj1));
244 10 : CHECK(!IsObjectShrinkable(*obj3));
245 10 : CHECK(!IsObjectShrinkable(*obj5));
246 10 : }
247 :
248 :
249 23723 : TEST(JSObjectComplexNoInlineNew) {
250 5 : FLAG_inline_new = false;
251 5 : TestJSObjectComplex();
252 5 : }
253 :
254 :
255 23728 : TEST(JSGeneratorObjectBasic) {
256 : // Avoid eventual completion of in-object slack tracking.
257 10 : FLAG_always_opt = false;
258 10 : CcTest::InitializeVM();
259 10 : v8::HandleScope scope(CcTest::isolate());
260 : const char* source =
261 : "function* A() {"
262 : " var i = 0;"
263 : " while(true) {"
264 : " yield i++;"
265 : " }"
266 : "};"
267 : "function CreateGenerator() {"
268 : " var o = A();"
269 : " o.a = 42;"
270 : " o.d = 4.2;"
271 : " o.o = o;"
272 : " return o;"
273 : "}";
274 : CompileRun(source);
275 :
276 10 : Handle<JSFunction> func = GetGlobal<JSFunction>("A");
277 :
278 : // Zero instances were created so far.
279 10 : CHECK(!func->has_initial_map());
280 :
281 : v8::Local<v8::Script> new_A_script = v8_compile("CreateGenerator();");
282 :
283 : Handle<JSObject> obj = RunI<JSObject>(new_A_script);
284 :
285 10 : CHECK(func->has_initial_map());
286 : Handle<Map> initial_map(func->initial_map());
287 :
288 : // One instance created.
289 10 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
290 : initial_map->construction_counter());
291 10 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
292 :
293 : // There must be at least some slack.
294 10 : CHECK_LT(5, obj->map()->GetInObjectProperties());
295 10 : CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0));
296 10 : CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1));
297 20 : CHECK_EQ(*obj, GetFieldValue(*obj, 2));
298 10 : CHECK(IsObjectShrinkable(*obj));
299 :
300 : // Create several objects to complete the tracking.
301 60 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
302 60 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
303 : Handle<JSObject> tmp = RunI<JSObject>(new_A_script);
304 120 : CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
305 : IsObjectShrinkable(*tmp));
306 : }
307 10 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
308 10 : CHECK(!IsObjectShrinkable(*obj));
309 :
310 : // No slack left.
311 10 : CHECK_EQ(3, obj->map()->GetInObjectProperties());
312 10 : }
313 :
314 :
315 23723 : TEST(JSGeneratorObjectBasicNoInlineNew) {
316 5 : FLAG_inline_new = false;
317 5 : TestJSGeneratorObjectBasic();
318 5 : }
319 :
320 :
321 23728 : TEST(SubclassBasicNoBaseClassInstances) {
322 : // Avoid eventual completion of in-object slack tracking.
323 10 : FLAG_always_opt = false;
324 10 : CcTest::InitializeVM();
325 10 : v8::HandleScope scope(CcTest::isolate());
326 :
327 : // Check that base class' and subclass' slack tracking do not interfere with
328 : // each other.
329 : // In this test we never create base class instances.
330 :
331 : const char* source =
332 : "'use strict';"
333 : "class A {"
334 : " constructor(...args) {"
335 : " this.aa = 42;"
336 : " this.ad = 4.2;"
337 : " this.ao = this;"
338 : " }"
339 : "};"
340 : "class B extends A {"
341 : " constructor(...args) {"
342 : " super(...args);"
343 : " this.ba = 142;"
344 : " this.bd = 14.2;"
345 : " this.bo = this;"
346 : " }"
347 : "};";
348 : CompileRun(source);
349 :
350 10 : Handle<JSFunction> a_func = GetLexical<JSFunction>("A");
351 10 : Handle<JSFunction> b_func = GetLexical<JSFunction>("B");
352 :
353 : // Zero instances were created so far.
354 10 : CHECK(!a_func->has_initial_map());
355 10 : CHECK(!b_func->has_initial_map());
356 :
357 : v8::Local<v8::Script> new_B_script = v8_compile("new B();");
358 :
359 : Handle<JSObject> obj = RunI<JSObject>(new_B_script);
360 :
361 10 : CHECK(a_func->has_initial_map());
362 : Handle<Map> a_initial_map(a_func->initial_map());
363 :
364 10 : CHECK(b_func->has_initial_map());
365 : Handle<Map> b_initial_map(b_func->initial_map());
366 :
367 : // Zero instances of A created.
368 10 : CHECK_EQ(Map::kSlackTrackingCounterStart,
369 : a_initial_map->construction_counter());
370 10 : CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
371 :
372 : // One instance of B created.
373 10 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
374 : b_initial_map->construction_counter());
375 10 : CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
376 :
377 : // There must be at least some slack.
378 10 : CHECK_LT(10, obj->map()->GetInObjectProperties());
379 10 : CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0));
380 10 : CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1));
381 20 : CHECK_EQ(*obj, GetFieldValue(*obj, 2));
382 10 : CHECK_EQ(Smi::FromInt(142), GetFieldValue(*obj, 3));
383 10 : CHECK_EQ(14.2, GetDoubleFieldValue(*obj, 4));
384 20 : CHECK_EQ(*obj, GetFieldValue(*obj, 5));
385 10 : CHECK(IsObjectShrinkable(*obj));
386 :
387 : // Create several subclass instances to complete the tracking.
388 60 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
389 60 : CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
390 : Handle<JSObject> tmp = RunI<JSObject>(new_B_script);
391 120 : CHECK_EQ(b_initial_map->IsInobjectSlackTrackingInProgress(),
392 : IsObjectShrinkable(*tmp));
393 : }
394 10 : CHECK(!b_initial_map->IsInobjectSlackTrackingInProgress());
395 10 : CHECK(!IsObjectShrinkable(*obj));
396 :
397 : // Zero instances of A created.
398 10 : CHECK_EQ(Map::kSlackTrackingCounterStart,
399 : a_initial_map->construction_counter());
400 10 : CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
401 :
402 : // No slack left.
403 10 : CHECK_EQ(6, obj->map()->GetInObjectProperties());
404 10 : }
405 :
406 :
407 23723 : TEST(SubclassBasicNoBaseClassInstancesNoInlineNew) {
408 5 : FLAG_inline_new = false;
409 5 : TestSubclassBasicNoBaseClassInstances();
410 5 : }
411 :
412 :
413 23728 : TEST(SubclassBasic) {
414 : // Avoid eventual completion of in-object slack tracking.
415 10 : FLAG_always_opt = false;
416 10 : CcTest::InitializeVM();
417 10 : v8::HandleScope scope(CcTest::isolate());
418 :
419 : // Check that base class' and subclass' slack tracking do not interfere with
420 : // each other.
421 : // In this test we first create enough base class instances to complete
422 : // the slack tracking and then proceed creating subclass instances.
423 :
424 : const char* source =
425 : "'use strict';"
426 : "class A {"
427 : " constructor(...args) {"
428 : " this.aa = 42;"
429 : " this.ad = 4.2;"
430 : " this.ao = this;"
431 : " }"
432 : "};"
433 : "class B extends A {"
434 : " constructor(...args) {"
435 : " super(...args);"
436 : " this.ba = 142;"
437 : " this.bd = 14.2;"
438 : " this.bo = this;"
439 : " }"
440 : "};";
441 : CompileRun(source);
442 :
443 10 : Handle<JSFunction> a_func = GetLexical<JSFunction>("A");
444 10 : Handle<JSFunction> b_func = GetLexical<JSFunction>("B");
445 :
446 : // Zero instances were created so far.
447 10 : CHECK(!a_func->has_initial_map());
448 10 : CHECK(!b_func->has_initial_map());
449 :
450 : v8::Local<v8::Script> new_A_script = v8_compile("new A();");
451 : v8::Local<v8::Script> new_B_script = v8_compile("new B();");
452 :
453 : Handle<JSObject> a_obj = RunI<JSObject>(new_A_script);
454 : Handle<JSObject> b_obj = RunI<JSObject>(new_B_script);
455 :
456 10 : CHECK(a_func->has_initial_map());
457 : Handle<Map> a_initial_map(a_func->initial_map());
458 :
459 10 : CHECK(b_func->has_initial_map());
460 : Handle<Map> b_initial_map(b_func->initial_map());
461 :
462 : // One instance of a base class created.
463 10 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
464 : a_initial_map->construction_counter());
465 10 : CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
466 :
467 : // One instance of a subclass created.
468 10 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
469 : b_initial_map->construction_counter());
470 10 : CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
471 :
472 : // Create several base class instances to complete the tracking.
473 60 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
474 60 : CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
475 : Handle<JSObject> tmp = RunI<JSObject>(new_A_script);
476 120 : CHECK_EQ(a_initial_map->IsInobjectSlackTrackingInProgress(),
477 : IsObjectShrinkable(*tmp));
478 : }
479 10 : CHECK(!a_initial_map->IsInobjectSlackTrackingInProgress());
480 10 : CHECK(!IsObjectShrinkable(*a_obj));
481 :
482 : // No slack left.
483 10 : CHECK_EQ(3, a_obj->map()->GetInObjectProperties());
484 :
485 : // There must be at least some slack.
486 10 : CHECK_LT(10, b_obj->map()->GetInObjectProperties());
487 10 : CHECK_EQ(Smi::FromInt(42), GetFieldValue(*b_obj, 0));
488 10 : CHECK_EQ(4.2, GetDoubleFieldValue(*b_obj, 1));
489 20 : CHECK_EQ(*b_obj, GetFieldValue(*b_obj, 2));
490 10 : CHECK_EQ(Smi::FromInt(142), GetFieldValue(*b_obj, 3));
491 10 : CHECK_EQ(14.2, GetDoubleFieldValue(*b_obj, 4));
492 20 : CHECK_EQ(*b_obj, GetFieldValue(*b_obj, 5));
493 10 : CHECK(IsObjectShrinkable(*b_obj));
494 :
495 : // Create several subclass instances to complete the tracking.
496 60 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
497 60 : CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
498 : Handle<JSObject> tmp = RunI<JSObject>(new_B_script);
499 120 : CHECK_EQ(b_initial_map->IsInobjectSlackTrackingInProgress(),
500 : IsObjectShrinkable(*tmp));
501 : }
502 10 : CHECK(!b_initial_map->IsInobjectSlackTrackingInProgress());
503 10 : CHECK(!IsObjectShrinkable(*b_obj));
504 :
505 : // No slack left.
506 10 : CHECK_EQ(6, b_obj->map()->GetInObjectProperties());
507 10 : }
508 :
509 :
510 23723 : TEST(SubclassBasicNoInlineNew) {
511 5 : FLAG_inline_new = false;
512 5 : TestSubclassBasic();
513 5 : }
514 :
515 :
516 : // Creates class hierarchy of length matching the |hierarchy_desc| length and
517 : // with the number of fields at i'th level equal to |hierarchy_desc[i]|.
518 575 : static void CreateClassHierarchy(const std::vector<int>& hierarchy_desc) {
519 25 : std::ostringstream os;
520 25 : os << "'use strict';\n\n";
521 :
522 25 : int n = static_cast<int>(hierarchy_desc.size());
523 550 : for (int cur_class = 0; cur_class < n; cur_class++) {
524 525 : os << "class A" << cur_class;
525 525 : if (cur_class > 0) {
526 500 : os << " extends A" << (cur_class - 1);
527 : }
528 : os << " {\n"
529 525 : " constructor(...args) {\n";
530 525 : if (cur_class > 0) {
531 500 : os << " super(...args);\n";
532 : }
533 1050 : int fields_count = hierarchy_desc[cur_class];
534 11825 : for (int k = 0; k < fields_count; k++) {
535 11300 : os << " this.f" << cur_class << "_" << k << " = " << k << ";\n";
536 : }
537 : os << " }\n"
538 525 : "};\n\n";
539 : }
540 25 : CompileRun(os.str().c_str());
541 25 : }
542 :
543 :
544 525 : static std::string GetClassName(int class_index) {
545 525 : std::ostringstream os;
546 525 : os << "A" << class_index;
547 525 : return os.str();
548 : }
549 :
550 :
551 525 : static v8::Local<v8::Script> GetNewObjectScript(const std::string& class_name) {
552 525 : std::ostringstream os;
553 1050 : os << "new " << class_name << "();";
554 525 : return v8_compile(os.str().c_str());
555 : }
556 :
557 :
558 : // Test that in-object slack tracking works as expected for first |n| classes
559 : // in the hierarchy.
560 : // This test works only for if the total property count is less than maximum
561 : // in-object properties count.
562 540 : static void TestClassHierarchy(const std::vector<int>& hierarchy_desc, int n) {
563 : int fields_count = 0;
564 540 : for (int cur_class = 0; cur_class < n; cur_class++) {
565 515 : std::string class_name = GetClassName(cur_class);
566 1030 : int fields_count_at_current_level = hierarchy_desc[cur_class];
567 515 : fields_count += fields_count_at_current_level;
568 :
569 : // This test is not suitable for in-object properties count overflow case.
570 515 : CHECK_LT(fields_count, kMaxInobjectProperties);
571 :
572 : // Create |class_name| objects and check slack tracking.
573 515 : v8::Local<v8::Script> new_script = GetNewObjectScript(class_name);
574 :
575 : Handle<JSFunction> func = GetLexical<JSFunction>(class_name);
576 :
577 : Handle<JSObject> obj = RunI<JSObject>(new_script);
578 :
579 515 : CHECK(func->has_initial_map());
580 : Handle<Map> initial_map(func->initial_map());
581 :
582 : // If the object is slow-mode already, bail out.
583 515 : if (obj->map()->is_dictionary_map()) continue;
584 :
585 : // There must be at least some slack.
586 515 : CHECK_LT(fields_count, obj->map()->GetInObjectProperties());
587 :
588 : // One instance was created.
589 515 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
590 : initial_map->construction_counter());
591 515 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
592 :
593 : // Create several instances to complete the tracking.
594 2575 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
595 3090 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
596 : Handle<JSObject> tmp = RunI<JSObject>(new_script);
597 6180 : CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
598 : IsObjectShrinkable(*tmp));
599 3090 : if (!initial_map->IsInobjectSlackTrackingInProgress()) {
600 : // Turbofan can force completion of in-object slack tracking.
601 : break;
602 : }
603 2575 : CHECK_EQ(Map::kSlackTrackingCounterStart - i - 1,
604 : initial_map->construction_counter());
605 : }
606 515 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
607 515 : CHECK(!IsObjectShrinkable(*obj));
608 :
609 : // No slack left.
610 515 : CHECK_EQ(fields_count, obj->map()->GetInObjectProperties());
611 : }
612 25 : }
613 :
614 :
615 30 : static void TestSubclassChain(const std::vector<int>& hierarchy_desc) {
616 : // Avoid eventual completion of in-object slack tracking.
617 15 : FLAG_always_opt = false;
618 15 : CcTest::InitializeVM();
619 15 : v8::HandleScope scope(CcTest::isolate());
620 :
621 15 : CreateClassHierarchy(hierarchy_desc);
622 15 : TestClassHierarchy(hierarchy_desc, static_cast<int>(hierarchy_desc.size()));
623 15 : }
624 :
625 :
626 23723 : TEST(LongSubclassChain1) {
627 : std::vector<int> hierarchy_desc;
628 40 : for (int i = 0; i < 7; i++) {
629 70 : hierarchy_desc.push_back(i * 10);
630 : }
631 5 : TestSubclassChain(hierarchy_desc);
632 5 : }
633 :
634 :
635 23723 : TEST(LongSubclassChain2) {
636 : std::vector<int> hierarchy_desc;
637 10 : hierarchy_desc.push_back(10);
638 215 : for (int i = 0; i < 42; i++) {
639 420 : hierarchy_desc.push_back(0);
640 : }
641 10 : hierarchy_desc.push_back(230);
642 5 : TestSubclassChain(hierarchy_desc);
643 5 : }
644 :
645 :
646 23723 : TEST(LongSubclassChain3) {
647 : std::vector<int> hierarchy_desc;
648 215 : for (int i = 0; i < 42; i++) {
649 420 : hierarchy_desc.push_back(5);
650 : }
651 5 : TestSubclassChain(hierarchy_desc);
652 5 : }
653 :
654 :
655 23723 : TEST(InobjectPropetiesCountOverflowInSubclass) {
656 : // Avoid eventual completion of in-object slack tracking.
657 5 : FLAG_always_opt = false;
658 5 : CcTest::InitializeVM();
659 5 : v8::HandleScope scope(CcTest::isolate());
660 :
661 : std::vector<int> hierarchy_desc;
662 : const int kNoOverflowCount = 5;
663 30 : for (int i = 0; i < kNoOverflowCount; i++) {
664 50 : hierarchy_desc.push_back(50);
665 : }
666 : // In this class we are going to have properties in the backing store.
667 10 : hierarchy_desc.push_back(100);
668 :
669 5 : CreateClassHierarchy(hierarchy_desc);
670 :
671 : // For the last class in the hierarchy we need different checks.
672 : {
673 : int cur_class = kNoOverflowCount;
674 5 : std::string class_name = GetClassName(cur_class);
675 :
676 : // Create |class_name| objects and check slack tracking.
677 5 : v8::Local<v8::Script> new_script = GetNewObjectScript(class_name);
678 :
679 : Handle<JSFunction> func = GetLexical<JSFunction>(class_name);
680 :
681 : Handle<JSObject> obj = RunI<JSObject>(new_script);
682 :
683 5 : CHECK(func->has_initial_map());
684 : Handle<Map> initial_map(func->initial_map());
685 :
686 : // There must be no slack left.
687 5 : CHECK_EQ(JSObject::kMaxInstanceSize, obj->map()->instance_size());
688 5 : CHECK_EQ(kMaxInobjectProperties, obj->map()->GetInObjectProperties());
689 :
690 : // One instance was created.
691 5 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
692 : initial_map->construction_counter());
693 5 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
694 :
695 : // Create several instances to complete the tracking.
696 30 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
697 30 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
698 : Handle<JSObject> tmp = RunI<JSObject>(new_script);
699 30 : CHECK(!IsObjectShrinkable(*tmp));
700 : }
701 5 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
702 5 : CHECK(!IsObjectShrinkable(*obj));
703 :
704 : // No slack left.
705 5 : CHECK_EQ(kMaxInobjectProperties, obj->map()->GetInObjectProperties());
706 : }
707 :
708 : // The other classes in the hierarchy are not affected.
709 10 : TestClassHierarchy(hierarchy_desc, kNoOverflowCount);
710 5 : }
711 :
712 35 : static void CheckExpectedProperties(int expected, std::ostringstream& os) {
713 : Handle<HeapObject> obj = Handle<HeapObject>::cast(
714 35 : v8::Utils::OpenHandle(*CompileRun(os.str().c_str())));
715 35 : CHECK_EQ(expected, obj->map()->GetInObjectProperties());
716 35 : }
717 :
718 23723 : TEST(ObjectLiteralPropertyBackingStoreSize) {
719 5 : v8::HandleScope scope(CcTest::isolate());
720 10 : LocalContext env;
721 :
722 10 : std::ostringstream os;
723 :
724 : // An index key does not require space in the property backing store.
725 : os << "(function() {\n"
726 : " function f() {\n"
727 : " var o = {\n"
728 : " '-1': 42,\n" // Allocate for non-index key.
729 : " 1: 42,\n" // Do not allocate for index key.
730 : " '2': 42\n" // Do not allocate for index key.
731 : " };\n"
732 : " return o;\n"
733 : " }\n"
734 : "\n"
735 : " return f();\n"
736 5 : "} )();";
737 5 : CheckExpectedProperties(1, os);
738 :
739 : // Avoid over-/under-allocation for computed property names.
740 : os << "(function() {\n"
741 : " 'use strict';\n"
742 : " function f(x) {\n"
743 : " var o = {\n"
744 : " 1: 42,\n" // Do not allocate for index key.
745 : " '2': 42,\n" // Do not allocate for index key.
746 : " [x]: 42,\n" // Allocate for property with computed name.
747 : " 3: 42,\n" // Do not allocate for index key.
748 : " '4': 42\n" // Do not allocate for index key.
749 : " };\n"
750 : " return o;\n"
751 : " }\n"
752 : "\n"
753 : " var x = 'hello'\n"
754 : "\n"
755 : " return f(x);\n"
756 5 : "} )();";
757 5 : CheckExpectedProperties(1, os);
758 :
759 : // Conversion to index key.
760 : os << "(function() {\n"
761 : " function f(x) {\n"
762 : " var o = {\n"
763 : " 1: 42,\n" // Do not allocate for index key.
764 : " '2': 42,\n" // Do not allocate for index key.
765 : " [x]: 42,\n" // Allocate for property with computed name.
766 : " 3: 42,\n" // Do not allocate for index key.
767 : " get 12() {}\n" // Do not allocate for index key.
768 : " };\n"
769 : " return o;\n"
770 : " }\n"
771 : "\n"
772 : " var x = 'hello'\n"
773 : "\n"
774 : " return f(x);\n"
775 5 : "} )();";
776 5 : CheckExpectedProperties(1, os);
777 :
778 : os << "(function() {\n"
779 : " function f() {\n"
780 : " var o = {};\n"
781 : " return o;\n"
782 : " }\n"
783 : "\n"
784 : " return f();\n"
785 5 : "} )();";
786 : // Empty objects have slack for 4 properties.
787 5 : CheckExpectedProperties(4, os);
788 :
789 : os << "(function() {\n"
790 : " function f(x) {\n"
791 : " var o = {\n"
792 : " a: 42,\n" // Allocate for constant property.
793 : " [x]: 42,\n" // Allocate for property with computed name.
794 : " b: 42\n" // Allocate for constant property.
795 : " };\n"
796 : " return o;\n"
797 : " }\n"
798 : "\n"
799 : " var x = 'hello'\n"
800 : "\n"
801 : " return f(x);\n"
802 5 : "} )();";
803 5 : CheckExpectedProperties(3, os);
804 :
805 : os << "(function() {\n"
806 : " function f(x) {\n"
807 : " var o = {\n"
808 : " a: 42,\n" // Allocate for constant property.
809 : " __proto__: 42,\n" // Do not allocate for __proto__.
810 : " [x]: 42\n" // Allocate for property with computed name.
811 : " };\n"
812 : " return o;\n"
813 : " }\n"
814 : "\n"
815 : " var x = 'hello'\n"
816 : "\n"
817 : " return f(x);\n"
818 5 : "} )();";
819 : // __proto__ is not allocated in the backing store.
820 5 : CheckExpectedProperties(2, os);
821 :
822 : os << "(function() {\n"
823 : " function f(x) {\n"
824 : " var o = {\n"
825 : " a: 42,\n" // Allocate for constant property.
826 : " [x]: 42,\n" // Allocate for property with computed name.
827 : " __proto__: 42\n" // Do not allocate for __proto__.
828 : " };\n"
829 : " return o;\n"
830 : " }\n"
831 : "\n"
832 : " var x = 'hello'\n"
833 : "\n"
834 : " return f(x);\n"
835 5 : "} )();";
836 10 : CheckExpectedProperties(2, os);
837 5 : }
838 :
839 23723 : TEST(SlowModeSubclass) {
840 : // Avoid eventual completion of in-object slack tracking.
841 5 : FLAG_always_opt = false;
842 5 : CcTest::InitializeVM();
843 5 : v8::HandleScope scope(CcTest::isolate());
844 :
845 : std::vector<int> hierarchy_desc;
846 : const int kNoOverflowCount = 5;
847 30 : for (int i = 0; i < kNoOverflowCount; i++) {
848 50 : hierarchy_desc.push_back(50);
849 : }
850 : // This class should go dictionary mode.
851 10 : hierarchy_desc.push_back(1000);
852 :
853 5 : CreateClassHierarchy(hierarchy_desc);
854 :
855 : // For the last class in the hierarchy we need different checks.
856 : {
857 : int cur_class = kNoOverflowCount;
858 5 : std::string class_name = GetClassName(cur_class);
859 :
860 : // Create |class_name| objects and check slack tracking.
861 5 : v8::Local<v8::Script> new_script = GetNewObjectScript(class_name);
862 :
863 : Handle<JSFunction> func = GetLexical<JSFunction>(class_name);
864 :
865 : Handle<JSObject> obj = RunI<JSObject>(new_script);
866 :
867 5 : CHECK(func->has_initial_map());
868 : Handle<Map> initial_map(func->initial_map());
869 :
870 : // Object should go dictionary mode.
871 5 : CHECK_EQ(JSObject::kHeaderSize, obj->map()->instance_size());
872 5 : CHECK(obj->map()->is_dictionary_map());
873 :
874 : // One instance was created.
875 5 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
876 : initial_map->construction_counter());
877 5 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
878 :
879 : // Create several instances to complete the tracking.
880 30 : for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
881 30 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
882 : Handle<JSObject> tmp = RunI<JSObject>(new_script);
883 30 : CHECK(!IsObjectShrinkable(*tmp));
884 : }
885 5 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
886 5 : CHECK(!IsObjectShrinkable(*obj));
887 :
888 : // Object should stay in dictionary mode.
889 5 : CHECK_EQ(JSObject::kHeaderSize, obj->map()->instance_size());
890 5 : CHECK(obj->map()->is_dictionary_map());
891 : }
892 :
893 : // The other classes in the hierarchy are not affected.
894 10 : TestClassHierarchy(hierarchy_desc, kNoOverflowCount);
895 5 : }
896 :
897 :
898 370 : static void TestSubclassBuiltin(const char* subclass_name,
899 : InstanceType instance_type,
900 : const char* builtin_name,
901 : const char* ctor_arguments = "",
902 : int builtin_properties_count = 0) {
903 : {
904 370 : std::ostringstream os;
905 : os << "'use strict';\n"
906 370 : "class "
907 370 : << subclass_name << " extends " << builtin_name
908 : << " {\n"
909 : " constructor(...args) {\n"
910 : " super(...args);\n"
911 : " this.a = 42;\n"
912 : " this.d = 4.2;\n"
913 : " this.o = this;\n"
914 : " }\n"
915 370 : "};\n";
916 370 : CompileRun(os.str().c_str());
917 : }
918 :
919 370 : Handle<JSFunction> func = GetLexical<JSFunction>(subclass_name);
920 :
921 : // Zero instances were created so far.
922 370 : CHECK(!func->has_initial_map());
923 :
924 : v8::Local<v8::Script> new_script;
925 : {
926 370 : std::ostringstream os;
927 370 : os << "new " << subclass_name << "(" << ctor_arguments << ");";
928 370 : new_script = v8_compile(os.str().c_str());
929 : }
930 :
931 : RunI<JSObject>(new_script);
932 :
933 370 : CHECK(func->has_initial_map());
934 : Handle<Map> initial_map(func->initial_map());
935 :
936 370 : CHECK_EQ(instance_type, initial_map->instance_type());
937 :
938 : // One instance of a subclass created.
939 370 : CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
940 : initial_map->construction_counter());
941 370 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
942 :
943 : // Create two instances in order to ensure that |obj|.o is a data field
944 : // in case of Function subclassing.
945 : Handle<JSObject> obj = RunI<JSObject>(new_script);
946 :
947 : // Two instances of a subclass created.
948 370 : CHECK_EQ(Map::kSlackTrackingCounterStart - 2,
949 : initial_map->construction_counter());
950 370 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
951 :
952 : // There must be at least some slack.
953 370 : CHECK_LT(builtin_properties_count + 5, obj->map()->GetInObjectProperties());
954 370 : CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, builtin_properties_count + 0));
955 740 : CHECK_EQ(4.2, GetDoubleFieldValue(*obj, builtin_properties_count + 1));
956 1110 : CHECK_EQ(*obj, GetFieldValue(*obj, builtin_properties_count + 2));
957 370 : CHECK(IsObjectShrinkable(*obj));
958 :
959 : // Create several subclass instances to complete the tracking.
960 1850 : for (int i = 2; i < Map::kGenerousAllocationCount; i++) {
961 1850 : CHECK(initial_map->IsInobjectSlackTrackingInProgress());
962 : Handle<JSObject> tmp = RunI<JSObject>(new_script);
963 3700 : CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
964 : IsObjectShrinkable(*tmp));
965 : }
966 370 : CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
967 370 : CHECK(!IsObjectShrinkable(*obj));
968 :
969 : // No slack left.
970 370 : CHECK_EQ(builtin_properties_count + 3, obj->map()->GetInObjectProperties());
971 :
972 370 : CHECK_EQ(instance_type, obj->map()->instance_type());
973 370 : }
974 :
975 :
976 23728 : TEST(SubclassObjectBuiltin) {
977 : // Avoid eventual completion of in-object slack tracking.
978 10 : FLAG_always_opt = false;
979 10 : CcTest::InitializeVM();
980 10 : v8::HandleScope scope(CcTest::isolate());
981 :
982 10 : TestSubclassBuiltin("A1", JS_OBJECT_TYPE, "Object", "true");
983 10 : TestSubclassBuiltin("A2", JS_OBJECT_TYPE, "Object", "42");
984 10 : TestSubclassBuiltin("A3", JS_OBJECT_TYPE, "Object", "'some string'");
985 10 : }
986 :
987 :
988 23723 : TEST(SubclassObjectBuiltinNoInlineNew) {
989 5 : FLAG_inline_new = false;
990 5 : TestSubclassObjectBuiltin();
991 5 : }
992 :
993 :
994 23728 : TEST(SubclassFunctionBuiltin) {
995 : // Avoid eventual completion of in-object slack tracking.
996 10 : FLAG_always_opt = false;
997 10 : CcTest::InitializeVM();
998 10 : v8::HandleScope scope(CcTest::isolate());
999 :
1000 10 : TestSubclassBuiltin("A1", JS_FUNCTION_TYPE, "Function", "'return 153;'");
1001 10 : TestSubclassBuiltin("A2", JS_FUNCTION_TYPE, "Function", "'this.a = 44;'");
1002 10 : }
1003 :
1004 :
1005 23723 : TEST(SubclassFunctionBuiltinNoInlineNew) {
1006 5 : FLAG_inline_new = false;
1007 5 : TestSubclassFunctionBuiltin();
1008 5 : }
1009 :
1010 :
1011 23728 : TEST(SubclassBooleanBuiltin) {
1012 : // Avoid eventual completion of in-object slack tracking.
1013 10 : FLAG_always_opt = false;
1014 10 : CcTest::InitializeVM();
1015 10 : v8::HandleScope scope(CcTest::isolate());
1016 :
1017 10 : TestSubclassBuiltin("A1", JS_VALUE_TYPE, "Boolean", "true");
1018 10 : TestSubclassBuiltin("A2", JS_VALUE_TYPE, "Boolean", "false");
1019 10 : }
1020 :
1021 :
1022 23723 : TEST(SubclassBooleanBuiltinNoInlineNew) {
1023 5 : FLAG_inline_new = false;
1024 5 : TestSubclassBooleanBuiltin();
1025 5 : }
1026 :
1027 :
1028 23728 : TEST(SubclassErrorBuiltin) {
1029 : // Avoid eventual completion of in-object slack tracking.
1030 10 : FLAG_always_opt = false;
1031 10 : CcTest::InitializeVM();
1032 10 : v8::HandleScope scope(CcTest::isolate());
1033 :
1034 : const int first_field = 2;
1035 10 : TestSubclassBuiltin("A1", JS_ERROR_TYPE, "Error", "'err'", first_field);
1036 10 : TestSubclassBuiltin("A2", JS_ERROR_TYPE, "EvalError", "'err'", first_field);
1037 10 : TestSubclassBuiltin("A3", JS_ERROR_TYPE, "RangeError", "'err'", first_field);
1038 : TestSubclassBuiltin("A4", JS_ERROR_TYPE, "ReferenceError", "'err'",
1039 10 : first_field);
1040 10 : TestSubclassBuiltin("A5", JS_ERROR_TYPE, "SyntaxError", "'err'", first_field);
1041 10 : TestSubclassBuiltin("A6", JS_ERROR_TYPE, "TypeError", "'err'", first_field);
1042 10 : TestSubclassBuiltin("A7", JS_ERROR_TYPE, "URIError", "'err'", first_field);
1043 10 : }
1044 :
1045 :
1046 23723 : TEST(SubclassErrorBuiltinNoInlineNew) {
1047 5 : FLAG_inline_new = false;
1048 5 : TestSubclassErrorBuiltin();
1049 5 : }
1050 :
1051 :
1052 23728 : TEST(SubclassNumberBuiltin) {
1053 : // Avoid eventual completion of in-object slack tracking.
1054 10 : FLAG_always_opt = false;
1055 10 : CcTest::InitializeVM();
1056 10 : v8::HandleScope scope(CcTest::isolate());
1057 :
1058 10 : TestSubclassBuiltin("A1", JS_VALUE_TYPE, "Number", "42");
1059 10 : TestSubclassBuiltin("A2", JS_VALUE_TYPE, "Number", "4.2");
1060 10 : }
1061 :
1062 :
1063 23723 : TEST(SubclassNumberBuiltinNoInlineNew) {
1064 5 : FLAG_inline_new = false;
1065 5 : TestSubclassNumberBuiltin();
1066 5 : }
1067 :
1068 :
1069 23728 : TEST(SubclassDateBuiltin) {
1070 : // Avoid eventual completion of in-object slack tracking.
1071 10 : FLAG_always_opt = false;
1072 10 : CcTest::InitializeVM();
1073 10 : v8::HandleScope scope(CcTest::isolate());
1074 :
1075 10 : TestSubclassBuiltin("A1", JS_DATE_TYPE, "Date", "123456789");
1076 10 : }
1077 :
1078 :
1079 23723 : TEST(SubclassDateBuiltinNoInlineNew) {
1080 5 : FLAG_inline_new = false;
1081 5 : TestSubclassDateBuiltin();
1082 5 : }
1083 :
1084 :
1085 23728 : TEST(SubclassStringBuiltin) {
1086 : // Avoid eventual completion of in-object slack tracking.
1087 10 : FLAG_always_opt = false;
1088 10 : CcTest::InitializeVM();
1089 10 : v8::HandleScope scope(CcTest::isolate());
1090 :
1091 10 : TestSubclassBuiltin("A1", JS_VALUE_TYPE, "String", "'some string'");
1092 10 : TestSubclassBuiltin("A2", JS_VALUE_TYPE, "String", "");
1093 10 : }
1094 :
1095 :
1096 23723 : TEST(SubclassStringBuiltinNoInlineNew) {
1097 5 : FLAG_inline_new = false;
1098 5 : TestSubclassStringBuiltin();
1099 5 : }
1100 :
1101 :
1102 23728 : TEST(SubclassRegExpBuiltin) {
1103 : // Avoid eventual completion of in-object slack tracking.
1104 10 : FLAG_always_opt = false;
1105 10 : CcTest::InitializeVM();
1106 10 : v8::HandleScope scope(CcTest::isolate());
1107 :
1108 : const int first_field = 1;
1109 : TestSubclassBuiltin("A1", JS_REGEXP_TYPE, "RegExp", "'o(..)h', 'g'",
1110 10 : first_field);
1111 10 : }
1112 :
1113 :
1114 23723 : TEST(SubclassRegExpBuiltinNoInlineNew) {
1115 5 : FLAG_inline_new = false;
1116 5 : TestSubclassRegExpBuiltin();
1117 5 : }
1118 :
1119 :
1120 23728 : TEST(SubclassArrayBuiltin) {
1121 : // Avoid eventual completion of in-object slack tracking.
1122 10 : FLAG_always_opt = false;
1123 10 : CcTest::InitializeVM();
1124 10 : v8::HandleScope scope(CcTest::isolate());
1125 :
1126 10 : TestSubclassBuiltin("A1", JS_ARRAY_TYPE, "Array", "42");
1127 10 : }
1128 :
1129 :
1130 23723 : TEST(SubclassArrayBuiltinNoInlineNew) {
1131 5 : FLAG_inline_new = false;
1132 5 : TestSubclassArrayBuiltin();
1133 5 : }
1134 :
1135 :
1136 23728 : TEST(SubclassTypedArrayBuiltin) {
1137 : // Avoid eventual completion of in-object slack tracking.
1138 10 : FLAG_always_opt = false;
1139 10 : CcTest::InitializeVM();
1140 10 : v8::HandleScope scope(CcTest::isolate());
1141 :
1142 : #define TYPED_ARRAY_TEST(Type, type, TYPE, elementType, size) \
1143 : TestSubclassBuiltin("A" #Type, JS_TYPED_ARRAY_TYPE, #Type "Array", "42");
1144 :
1145 10 : TYPED_ARRAYS(TYPED_ARRAY_TEST)
1146 :
1147 : #undef TYPED_ARRAY_TEST
1148 10 : }
1149 :
1150 :
1151 23723 : TEST(SubclassTypedArrayBuiltinNoInlineNew) {
1152 5 : FLAG_inline_new = false;
1153 5 : TestSubclassTypedArrayBuiltin();
1154 5 : }
1155 :
1156 :
1157 23728 : TEST(SubclassCollectionBuiltin) {
1158 : // Avoid eventual completion of in-object slack tracking.
1159 10 : FLAG_always_opt = false;
1160 10 : CcTest::InitializeVM();
1161 10 : v8::HandleScope scope(CcTest::isolate());
1162 :
1163 10 : TestSubclassBuiltin("A1", JS_SET_TYPE, "Set", "");
1164 10 : TestSubclassBuiltin("A2", JS_MAP_TYPE, "Map", "");
1165 10 : TestSubclassBuiltin("A3", JS_WEAK_SET_TYPE, "WeakSet", "");
1166 10 : TestSubclassBuiltin("A4", JS_WEAK_MAP_TYPE, "WeakMap", "");
1167 10 : }
1168 :
1169 :
1170 23723 : TEST(SubclassCollectionBuiltinNoInlineNew) {
1171 5 : FLAG_inline_new = false;
1172 5 : TestSubclassCollectionBuiltin();
1173 5 : }
1174 :
1175 :
1176 23728 : TEST(SubclassArrayBufferBuiltin) {
1177 : // Avoid eventual completion of in-object slack tracking.
1178 10 : FLAG_always_opt = false;
1179 10 : CcTest::InitializeVM();
1180 10 : v8::HandleScope scope(CcTest::isolate());
1181 :
1182 10 : TestSubclassBuiltin("A1", JS_ARRAY_BUFFER_TYPE, "ArrayBuffer", "42");
1183 : TestSubclassBuiltin("A2", JS_DATA_VIEW_TYPE, "DataView",
1184 10 : "new ArrayBuffer(42)");
1185 10 : }
1186 :
1187 :
1188 23723 : TEST(SubclassArrayBufferBuiltinNoInlineNew) {
1189 5 : FLAG_inline_new = false;
1190 5 : TestSubclassArrayBufferBuiltin();
1191 5 : }
1192 :
1193 :
1194 23728 : TEST(SubclassPromiseBuiltin) {
1195 : // Avoid eventual completion of in-object slack tracking.
1196 10 : FLAG_always_opt = false;
1197 10 : CcTest::InitializeVM();
1198 10 : v8::HandleScope scope(CcTest::isolate());
1199 :
1200 : TestSubclassBuiltin("A1", JS_PROMISE_TYPE, "Promise",
1201 10 : "function(resolve, reject) { resolve('ok'); }");
1202 10 : }
1203 :
1204 :
1205 23723 : TEST(SubclassPromiseBuiltinNoInlineNew) {
1206 5 : FLAG_inline_new = false;
1207 5 : TestSubclassPromiseBuiltin();
1208 5 : }
1209 :
1210 : } // namespace test_inobject_slack_tracking
1211 : } // namespace internal
1212 71154 : } // namespace v8
|