1 // Copyright 2014 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 "src/frames-inl.h"
6 #include "test/cctest/compiler/function-tester.h"
7
8 namespace v8 {
9 namespace internal {
10 namespace compiler {
11
12 namespace {
13
14 // Helper to determine inline count via JavaScriptFrame::GetFunctions.
15 // Note that a count of 1 indicates that no inlining has occured.
AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value> & args)16 void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
17 StackTraceFrameIterator it(CcTest::i_isolate());
18 int frames_seen = 0;
19 JavaScriptFrame* topmost = it.javascript_frame();
20 while (!it.done()) {
21 JavaScriptFrame* frame = it.javascript_frame();
22 List<JSFunction*> functions(2);
23 frame->GetFunctions(&functions);
24 PrintF("%d %s, inline count: %d\n", frames_seen,
25 frame->function()->shared()->DebugName()->ToCString().get(),
26 functions.length());
27 frames_seen++;
28 it.Advance();
29 }
30 List<JSFunction*> functions(2);
31 topmost->GetFunctions(&functions);
32 CHECK_EQ(args[0]
33 ->ToInt32(args.GetIsolate()->GetCurrentContext())
34 .ToLocalChecked()
35 ->Value(),
36 functions.length());
37 }
38
39
InstallAssertInlineCountHelper(v8::Isolate * isolate)40 void InstallAssertInlineCountHelper(v8::Isolate* isolate) {
41 v8::Local<v8::Context> context = isolate->GetCurrentContext();
42 v8::Local<v8::FunctionTemplate> t =
43 v8::FunctionTemplate::New(isolate, AssertInlineCount);
44 CHECK(context->Global()
45 ->Set(context, v8_str("AssertInlineCount"),
46 t->GetFunction(context).ToLocalChecked())
47 .FromJust());
48 }
49
50 const uint32_t kRestrictedInliningFlags =
51 CompilationInfo::kFunctionContextSpecializing;
52
53 const uint32_t kInlineFlags = CompilationInfo::kInliningEnabled |
54 CompilationInfo::kFunctionContextSpecializing;
55
56 } // namespace
57
58
TEST(SimpleInlining)59 TEST(SimpleInlining) {
60 FunctionTester T(
61 "(function(){"
62 " function foo(s) { AssertInlineCount(2); return s; };"
63 " function bar(s, t) { return foo(s); };"
64 " return bar;"
65 "})();",
66 kInlineFlags);
67
68 InstallAssertInlineCountHelper(CcTest::isolate());
69 T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
70 }
71
72
TEST(SimpleInliningDeopt)73 TEST(SimpleInliningDeopt) {
74 FunctionTester T(
75 "(function(){"
76 " function foo(s) { %DeoptimizeFunction(bar); return s; };"
77 " function bar(s, t) { return foo(s); };"
78 " return bar;"
79 "})();",
80 kInlineFlags);
81
82 InstallAssertInlineCountHelper(CcTest::isolate());
83 T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
84 }
85
86
TEST(SimpleInliningDeoptSelf)87 TEST(SimpleInliningDeoptSelf) {
88 FunctionTester T(
89 "(function(){"
90 " function foo(s) { %_DeoptimizeNow(); return s; };"
91 " function bar(s, t) { return foo(s); };"
92 " return bar;"
93 "})();",
94 kInlineFlags);
95
96 InstallAssertInlineCountHelper(CcTest::isolate());
97 T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
98 }
99
100
TEST(SimpleInliningContext)101 TEST(SimpleInliningContext) {
102 FunctionTester T(
103 "(function () {"
104 " function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
105 " function bar(s, t) { return foo(s); };"
106 " return bar;"
107 "})();",
108 kInlineFlags);
109
110 InstallAssertInlineCountHelper(CcTest::isolate());
111 T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
112 }
113
114
TEST(SimpleInliningContextDeopt)115 TEST(SimpleInliningContextDeopt) {
116 FunctionTester T(
117 "(function () {"
118 " function foo(s) {"
119 " AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
120 " return s + x;"
121 " };"
122 " function bar(s, t) { return foo(s); };"
123 " return bar;"
124 "})();",
125 kInlineFlags);
126
127 InstallAssertInlineCountHelper(CcTest::isolate());
128 T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
129 }
130
131
TEST(CaptureContext)132 TEST(CaptureContext) {
133 FunctionTester T(
134 "var f = (function () {"
135 " var x = 42;"
136 " function bar(s) { return x + s; };"
137 " return (function (s) { return bar(s); });"
138 "})();"
139 "(function (s) { return f(s) })",
140 kInlineFlags);
141
142 InstallAssertInlineCountHelper(CcTest::isolate());
143 T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
144 }
145
146
147 // TODO(sigurds) For now we do not inline any native functions. If we do at
148 // some point, change this test.
TEST(DontInlineEval)149 TEST(DontInlineEval) {
150 FunctionTester T(
151 "var x = 42;"
152 "(function () {"
153 " function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
154 " return bar;"
155 "})();",
156 kInlineFlags);
157
158 InstallAssertInlineCountHelper(CcTest::isolate());
159 T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
160 }
161
162
TEST(InlineOmitArguments)163 TEST(InlineOmitArguments) {
164 FunctionTester T(
165 "(function () {"
166 " var x = 42;"
167 " function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
168 " function foo(s, t) { return bar(s); };"
169 " return foo;"
170 "})();",
171 kInlineFlags);
172
173 InstallAssertInlineCountHelper(CcTest::isolate());
174 T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
175 }
176
177
TEST(InlineOmitArgumentsObject)178 TEST(InlineOmitArgumentsObject) {
179 FunctionTester T(
180 "(function () {"
181 " function bar(s, t, u, v) { AssertInlineCount(2); return arguments; };"
182 " function foo(s, t) { var args = bar(s);"
183 " return args.length == 1 &&"
184 " args[0] == 11; };"
185 " return foo;"
186 "})();",
187 kInlineFlags);
188
189 InstallAssertInlineCountHelper(CcTest::isolate());
190 T.CheckCall(T.true_value(), T.Val(11), T.undefined());
191 }
192
193
TEST(InlineOmitArgumentsDeopt)194 TEST(InlineOmitArgumentsDeopt) {
195 FunctionTester T(
196 "(function () {"
197 " function foo(s,t,u,v) { AssertInlineCount(2);"
198 " %DeoptimizeFunction(bar); return baz(); };"
199 " function bar() { return foo(11); };"
200 " function baz() { return foo.arguments.length == 1 &&"
201 " foo.arguments[0] == 11; }"
202 " return bar;"
203 "})();",
204 kInlineFlags);
205
206 InstallAssertInlineCountHelper(CcTest::isolate());
207 T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
208 }
209
210
TEST(InlineSurplusArguments)211 TEST(InlineSurplusArguments) {
212 FunctionTester T(
213 "(function () {"
214 " var x = 42;"
215 " function foo(s) { AssertInlineCount(2); return x + s; };"
216 " function bar(s, t) { return foo(s, t, 13); };"
217 " return bar;"
218 "})();",
219 kInlineFlags);
220
221 InstallAssertInlineCountHelper(CcTest::isolate());
222 T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
223 }
224
225
TEST(InlineSurplusArgumentsObject)226 TEST(InlineSurplusArgumentsObject) {
227 FunctionTester T(
228 "(function () {"
229 " function foo(s) { AssertInlineCount(2); return arguments; };"
230 " function bar(s, t) { var args = foo(s, t, 13);"
231 " return args.length == 3 &&"
232 " args[0] == 11 &&"
233 " args[1] == 12 &&"
234 " args[2] == 13; };"
235 " return bar;"
236 "})();",
237 kInlineFlags);
238
239 InstallAssertInlineCountHelper(CcTest::isolate());
240 T.CheckCall(T.true_value(), T.Val(11), T.Val(12));
241 }
242
243
TEST(InlineSurplusArgumentsDeopt)244 TEST(InlineSurplusArgumentsDeopt) {
245 FunctionTester T(
246 "(function () {"
247 " function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar);"
248 " return baz(); };"
249 " function bar() { return foo(13, 14, 15); };"
250 " function baz() { return foo.arguments.length == 3 &&"
251 " foo.arguments[0] == 13 &&"
252 " foo.arguments[1] == 14 &&"
253 " foo.arguments[2] == 15; }"
254 " return bar;"
255 "})();",
256 kInlineFlags);
257
258 InstallAssertInlineCountHelper(CcTest::isolate());
259 T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
260 }
261
262
TEST(InlineTwice)263 TEST(InlineTwice) {
264 FunctionTester T(
265 "(function () {"
266 " var x = 42;"
267 " function bar(s) { AssertInlineCount(2); return x + s; };"
268 " function foo(s, t) { return bar(s) + bar(t); };"
269 " return foo;"
270 "})();",
271 kInlineFlags);
272
273 InstallAssertInlineCountHelper(CcTest::isolate());
274 T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
275 }
276
277
TEST(InlineTwiceDependent)278 TEST(InlineTwiceDependent) {
279 FunctionTester T(
280 "(function () {"
281 " var x = 42;"
282 " function foo(s) { AssertInlineCount(2); return x + s; };"
283 " function bar(s,t) { return foo(foo(s)); };"
284 " return bar;"
285 "})();",
286 kInlineFlags);
287
288 InstallAssertInlineCountHelper(CcTest::isolate());
289 T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
290 }
291
292
TEST(InlineTwiceDependentDiamond)293 TEST(InlineTwiceDependentDiamond) {
294 FunctionTester T(
295 "(function () {"
296 " var x = 41;"
297 " function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
298 " return x - s } else { return x + s; } };"
299 " function bar(s,t) { return foo(foo(s)); };"
300 " return bar;"
301 "})();",
302 kInlineFlags);
303
304 InstallAssertInlineCountHelper(CcTest::isolate());
305 T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
306 }
307
308
TEST(InlineTwiceDependentDiamondDifferent)309 TEST(InlineTwiceDependentDiamondDifferent) {
310 FunctionTester T(
311 "(function () {"
312 " var x = 41;"
313 " function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
314 " return x - s * t } else { return x + s * t; } };"
315 " function bar(s,t) { return foo(foo(s, 3), 5); };"
316 " return bar;"
317 "})();",
318 kInlineFlags);
319
320 InstallAssertInlineCountHelper(CcTest::isolate());
321 T.CheckCall(T.Val(-329), T.Val(11), T.Val(4));
322 }
323
324
TEST(InlineLoopGuardedEmpty)325 TEST(InlineLoopGuardedEmpty) {
326 FunctionTester T(
327 "(function () {"
328 " function foo(s) { AssertInlineCount(2); if (s) while (s); return s; };"
329 " function bar(s,t) { return foo(s); };"
330 " return bar;"
331 "})();",
332 kInlineFlags);
333
334 InstallAssertInlineCountHelper(CcTest::isolate());
335 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
336 }
337
338
TEST(InlineLoopGuardedOnce)339 TEST(InlineLoopGuardedOnce) {
340 FunctionTester T(
341 "(function () {"
342 " function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
343 " s = s - 1; }; return s; };"
344 " function bar(s,t) { return foo(s,t); };"
345 " return bar;"
346 "})();",
347 kInlineFlags);
348
349 InstallAssertInlineCountHelper(CcTest::isolate());
350 T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
351 }
352
353
TEST(InlineLoopGuardedTwice)354 TEST(InlineLoopGuardedTwice) {
355 FunctionTester T(
356 "(function () {"
357 " function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
358 " s = s - 1; }; return s; };"
359 " function bar(s,t) { return foo(foo(s,t),t); };"
360 " return bar;"
361 "})();",
362 kInlineFlags);
363
364 InstallAssertInlineCountHelper(CcTest::isolate());
365 T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
366 }
367
368
TEST(InlineLoopUnguardedEmpty)369 TEST(InlineLoopUnguardedEmpty) {
370 FunctionTester T(
371 "(function () {"
372 " function foo(s) { AssertInlineCount(2); while (s); return s; };"
373 " function bar(s, t) { return foo(s); };"
374 " return bar;"
375 "})();",
376 kInlineFlags);
377
378 InstallAssertInlineCountHelper(CcTest::isolate());
379 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
380 }
381
382
TEST(InlineLoopUnguardedOnce)383 TEST(InlineLoopUnguardedOnce) {
384 FunctionTester T(
385 "(function () {"
386 " function foo(s) { AssertInlineCount(2); while (s) {"
387 " s = s - 1; }; return s; };"
388 " function bar(s, t) { return foo(s); };"
389 " return bar;"
390 "})();",
391 kInlineFlags);
392
393 InstallAssertInlineCountHelper(CcTest::isolate());
394 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
395 }
396
397
TEST(InlineLoopUnguardedTwice)398 TEST(InlineLoopUnguardedTwice) {
399 FunctionTester T(
400 "(function () {"
401 " function foo(s) { AssertInlineCount(2); while (s > 0) {"
402 " s = s - 1; }; return s; };"
403 " function bar(s,t) { return foo(foo(s,t),t); };"
404 " return bar;"
405 "})();",
406 kInlineFlags);
407
408 InstallAssertInlineCountHelper(CcTest::isolate());
409 T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
410 }
411
412
TEST(InlineStrictIntoNonStrict)413 TEST(InlineStrictIntoNonStrict) {
414 FunctionTester T(
415 "(function () {"
416 " var x = Object.create({}, { y: { value:42, writable:false } });"
417 " function foo(s) { 'use strict';"
418 " x.y = 9; };"
419 " function bar(s,t) { return foo(s); };"
420 " return bar;"
421 "})();",
422 kInlineFlags);
423
424 InstallAssertInlineCountHelper(CcTest::isolate());
425 T.CheckThrows(T.undefined(), T.undefined());
426 }
427
428
TEST(InlineNonStrictIntoStrict)429 TEST(InlineNonStrictIntoStrict) {
430 FunctionTester T(
431 "(function () {"
432 " var x = Object.create({}, { y: { value:42, writable:false } });"
433 " function foo(s) { x.y = 9; return x.y; };"
434 " function bar(s,t) { \'use strict\'; return foo(s); };"
435 " return bar;"
436 "})();",
437 kInlineFlags);
438
439 InstallAssertInlineCountHelper(CcTest::isolate());
440 T.CheckCall(T.Val(42), T.undefined(), T.undefined());
441 }
442
443
TEST(InlineIntrinsicIsSmi)444 TEST(InlineIntrinsicIsSmi) {
445 FunctionTester T(
446 "(function () {"
447 " var x = 42;"
448 " function bar(s,t) { return %_IsSmi(x); };"
449 " return bar;"
450 "})();",
451 kInlineFlags);
452
453 InstallAssertInlineCountHelper(CcTest::isolate());
454 T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
455 }
456
457
TEST(InlineIntrinsicIsArray)458 TEST(InlineIntrinsicIsArray) {
459 FunctionTester T(
460 "(function () {"
461 " var x = [1,2,3];"
462 " function bar(s,t) { return %_IsArray(x); };"
463 " return bar;"
464 "})();",
465 kInlineFlags);
466
467 InstallAssertInlineCountHelper(CcTest::isolate());
468 T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
469
470 FunctionTester T2(
471 "(function () {"
472 " var x = 32;"
473 " function bar(s,t) { return %_IsArray(x); };"
474 " return bar;"
475 "})();",
476 kInlineFlags);
477
478 T2.CheckCall(T.false_value(), T.Val(12), T.Val(4));
479
480 FunctionTester T3(
481 "(function () {"
482 " var x = bar;"
483 " function bar(s,t) { return %_IsArray(x); };"
484 " return bar;"
485 "})();",
486 kInlineFlags);
487
488 T3.CheckCall(T.false_value(), T.Val(12), T.Val(4));
489 }
490
491
TEST(InlineWithArguments)492 TEST(InlineWithArguments) {
493 FunctionTester T(
494 "(function () {"
495 " function foo(s,t,u) { AssertInlineCount(2);"
496 " return foo.arguments.length == 3 &&"
497 " foo.arguments[0] == 13 &&"
498 " foo.arguments[1] == 14 &&"
499 " foo.arguments[2] == 15;"
500 " }"
501 " function bar() { return foo(13, 14, 15); };"
502 " return bar;"
503 "})();",
504 kInlineFlags);
505
506 InstallAssertInlineCountHelper(CcTest::isolate());
507 T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
508 }
509
510
TEST(InlineBuiltin)511 TEST(InlineBuiltin) {
512 FunctionTester T(
513 "(function () {"
514 " function foo(s,t,u) { AssertInlineCount(2); return true; }"
515 " function bar() { return foo(); };"
516 " %SetForceInlineFlag(foo);"
517 " return bar;"
518 "})();",
519 kRestrictedInliningFlags);
520
521 InstallAssertInlineCountHelper(CcTest::isolate());
522 T.CheckCall(T.true_value());
523 }
524
525
TEST(InlineNestedBuiltin)526 TEST(InlineNestedBuiltin) {
527 FunctionTester T(
528 "(function () {"
529 " function foo(s,t,u) { AssertInlineCount(3); return true; }"
530 " function baz(s,t,u) { return foo(s,t,u); }"
531 " function bar() { return baz(); };"
532 " %SetForceInlineFlag(foo);"
533 " %SetForceInlineFlag(baz);"
534 " return bar;"
535 "})();",
536 kRestrictedInliningFlags);
537
538 InstallAssertInlineCountHelper(CcTest::isolate());
539 T.CheckCall(T.true_value());
540 }
541
542
TEST(InlineSelfRecursive)543 TEST(InlineSelfRecursive) {
544 FunctionTester T(
545 "(function () {"
546 " function foo(x) { "
547 " AssertInlineCount(1);"
548 " if (x == 1) return foo(12);"
549 " return x;"
550 " }"
551 " return foo;"
552 "})();",
553 kInlineFlags);
554
555 InstallAssertInlineCountHelper(CcTest::isolate());
556 T.CheckCall(T.Val(12), T.Val(1));
557 }
558
559
TEST(InlineMutuallyRecursive)560 TEST(InlineMutuallyRecursive) {
561 FunctionTester T(
562 "(function () {"
563 " function bar(x) { AssertInlineCount(2); return foo(x); }"
564 " function foo(x) { "
565 " if (x == 1) return bar(42);"
566 " return x;"
567 " }"
568 " return foo;"
569 "})();",
570 kInlineFlags);
571
572 InstallAssertInlineCountHelper(CcTest::isolate());
573 T.CheckCall(T.Val(42), T.Val(1));
574 }
575
576 } // namespace compiler
577 } // namespace internal
578 } // namespace v8
579