Home | History | Annotate | Download | only in compiler
      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.
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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