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