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