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