• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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