1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 public class Main { 18 19 /* 20 * Ensure an inlined static invoke explicitly triggers the 21 * initialization check of the called method's declaring class, and 22 * that the corresponding load class instruction does not get 23 * removed before register allocation & code generation. 24 */ 25 26 /// CHECK-START: void Main.invokeStaticInlined() builder (after) 27 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false 28 /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 29 /// CHECK-DAG: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>] 30 31 /// CHECK-START: void Main.invokeStaticInlined() inliner (after) 32 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false 33 /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 34 35 /// CHECK-START: void Main.invokeStaticInlined() inliner (after) 36 /// CHECK-NOT: InvokeStaticOrDirect 37 38 // The following checks ensure the clinit check instruction added by 39 // the builder is pruned by the PrepareForRegisterAllocation, while 40 // the load class instruction is preserved. As the control flow 41 // graph is not dumped after (nor before) this step, we check the 42 // CFG as it is before the next pass (liveness analysis) instead. 43 44 /// CHECK-START: void Main.invokeStaticInlined() liveness (before) 45 /// CHECK-DAG: LoadClass gen_clinit_check:true 46 47 /// CHECK-START: void Main.invokeStaticInlined() liveness (before) 48 /// CHECK-NOT: ClinitCheck 49 /// CHECK-NOT: InvokeStaticOrDirect 50 invokeStaticInlined()51 static void invokeStaticInlined() { 52 ClassWithClinit1.$opt$inline$StaticMethod(); 53 } 54 55 static class ClassWithClinit1 { 56 static { 57 System.out.println("Main$ClassWithClinit1's static initializer"); 58 } 59 $opt$inline$StaticMethod()60 static void $opt$inline$StaticMethod() { 61 } 62 } 63 64 /* 65 * Ensure a non-inlined static invoke eventually has an implicit 66 * initialization check of the called method's declaring class. 67 */ 68 69 /// CHECK-START: void Main.invokeStaticNotInlined() builder (after) 70 /// CHECK: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false 71 /// CHECK: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 72 /// CHECK: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>] 73 74 /// CHECK-START: void Main.invokeStaticNotInlined() inliner (after) 75 /// CHECK: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false 76 /// CHECK: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] 77 /// CHECK: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>] 78 79 // The following checks ensure the clinit check and load class 80 // instructions added by the builder are pruned by the 81 // PrepareForRegisterAllocation. As the control flow graph is not 82 // dumped after (nor before) this step, we check the CFG as it is 83 // before the next pass (liveness analysis) instead. 84 85 /// CHECK-START: void Main.invokeStaticNotInlined() liveness (before) 86 /// CHECK: InvokeStaticOrDirect clinit_check:implicit 87 88 /// CHECK-START: void Main.invokeStaticNotInlined() liveness (before) 89 /// CHECK-NOT: LoadClass 90 /// CHECK-NOT: ClinitCheck 91 invokeStaticNotInlined()92 static void invokeStaticNotInlined() { 93 ClassWithClinit2.$noinline$staticMethod(); 94 } 95 96 static class ClassWithClinit2 { 97 static { 98 System.out.println("Main$ClassWithClinit2's static initializer"); 99 } 100 101 static boolean staticField = false; 102 $noinline$staticMethod()103 static void $noinline$staticMethod() { 104 } 105 } 106 107 /* 108 * Ensure an inlined call from a static method to a static method 109 * of the same class does not require an explicit clinit check 110 * (already initialized or initializing in the same thread). 111 */ 112 113 /// CHECK-START: void Main$ClassWithClinit3Static.invokeStaticInlined() builder (after) 114 /// CHECK-DAG: InvokeStaticOrDirect 115 116 /// CHECK-START: void Main$ClassWithClinit3Static.invokeStaticInlined() builder (after) 117 /// CHECK-NOT: LoadClass 118 /// CHECK-NOT: ClinitCheck 119 120 /// CHECK-START: void Main$ClassWithClinit3Static.invokeStaticInlined() inliner (after) 121 /// CHECK-NOT: LoadClass 122 /// CHECK-NOT: ClinitCheck 123 /// CHECK-NOT: InvokeStaticOrDirect 124 125 static class ClassWithClinit3Static { invokeStaticInlined()126 static void invokeStaticInlined() { 127 // The invocation of invokeStaticInlined happens only after a clinit check 128 // of ClassWithClinit3Static, meaning that the hereinbelow call to 129 // $opt$inline$StaticMethod does not need another clinit check. 130 $opt$inline$StaticMethod(); 131 } 132 133 static { 134 System.out.println("Main$ClassWithClinit3Static's static initializer"); 135 } 136 $opt$inline$StaticMethod()137 static void $opt$inline$StaticMethod() { 138 } 139 } 140 141 /* 142 * Ensure an inlined call from an instance method to a static method 143 * of the same class actually requires an explicit clinit check when 144 * the class has a non-trivial initialization as we could be executing 145 * the instance method on an escaped object of an erroneous class. b/62478025 146 */ 147 148 /// CHECK-START: void Main$ClassWithClinit3Instance.invokeStaticInlined() builder (after) 149 /// CHECK-DAG: LoadClass 150 /// CHECK-DAG: ClinitCheck 151 /// CHECK-DAG: InvokeStaticOrDirect 152 153 /// CHECK-START: void Main$ClassWithClinit3Instance.invokeStaticInlined() inliner (after) 154 /// CHECK-DAG: LoadClass 155 /// CHECK-DAG: ClinitCheck 156 157 /// CHECK-START: void Main$ClassWithClinit3Instance.invokeStaticInlined() inliner (after) 158 /// CHECK-NOT: InvokeStaticOrDirect 159 160 static class ClassWithClinit3Instance { invokeStaticInlined()161 void invokeStaticInlined() { 162 // ClinitCheck required. 163 $opt$inline$StaticMethod(); 164 } 165 166 static { 167 System.out.println("Main$ClassWithClinit3Instance's static initializer"); 168 } 169 $opt$inline$StaticMethod()170 static void $opt$inline$StaticMethod() { 171 } 172 } 173 174 /* 175 * Ensure a non-inlined call from a static method to a static method 176 * of the same class does not require an explicit clinit check 177 * (already initialized or initializing in the same thread). 178 */ 179 180 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() builder (after) 181 /// CHECK-DAG: InvokeStaticOrDirect 182 183 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() builder (after) 184 /// CHECK-NOT: LoadClass 185 /// CHECK-NOT: ClinitCheck 186 187 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() inliner (after) 188 /// CHECK-DAG: InvokeStaticOrDirect 189 190 /// CHECK-START: void Main$ClassWithClinit4Static.invokeStaticNotInlined() inliner (after) 191 /// CHECK-NOT: LoadClass 192 /// CHECK-NOT: ClinitCheck 193 194 static class ClassWithClinit4Static { invokeStaticNotInlined()195 static void invokeStaticNotInlined() { 196 // The invocation of invokeStaticNotInlined triggers the 197 // initialization of ClassWithClinit4Static, meaning that the 198 // call to staticMethod below does not need a clinit 199 // check. 200 $noinline$staticMethod(); 201 } 202 203 static { 204 System.out.println("Main$ClassWithClinit4Static's static initializer"); 205 } 206 $noinline$staticMethod()207 static void $noinline$staticMethod() { 208 } 209 } 210 211 /* 212 * Ensure a non-inlined call from an instance method to a static method 213 * of the same class actually requires an explicit clinit check when 214 * the class has a non-trivial initialization as we could be executing 215 * the instance method on an escaped object of an erroneous class. b/62478025 216 */ 217 218 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() builder (after) 219 /// CHECK-DAG: LoadClass 220 /// CHECK-DAG: ClinitCheck 221 /// CHECK-DAG: InvokeStaticOrDirect 222 223 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() inliner (after) 224 /// CHECK-DAG: LoadClass 225 /// CHECK-DAG: ClinitCheck 226 /// CHECK-DAG: InvokeStaticOrDirect 227 228 // The following checks ensure the clinit check and load class 229 // instructions added by the builder are pruned by the 230 // PrepareForRegisterAllocation. As the control flow graph is not 231 // dumped after (nor before) this step, we check the CFG as it is 232 // before the next pass (liveness analysis) instead. 233 234 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() liveness (before) 235 /// CHECK: InvokeStaticOrDirect clinit_check:implicit 236 237 /// CHECK-START: void Main$ClassWithClinit4Instance.invokeStaticNotInlined() liveness (before) 238 /// CHECK-NOT: LoadClass 239 /// CHECK-NOT: ClinitCheck 240 241 static class ClassWithClinit4Instance { invokeStaticNotInlined()242 void invokeStaticNotInlined() { 243 // ClinitCheck required. 244 $noinline$staticMethod(); 245 } 246 247 static { 248 System.out.println("Main$ClassWithClinit4Instance's static initializer"); 249 } 250 $noinline$staticMethod()251 static void $noinline$staticMethod() { 252 } 253 } 254 255 /* 256 * We used to remove clinit check for calls to static methods in a superclass. However, this 257 * is not a valid optimization when instances of erroneous classes can escape, therefore 258 * we avoid this optimization for classes with non-trivial initialization. b/62478025 259 */ 260 261 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after) 262 /// CHECK-DAG: LoadClass 263 /// CHECK-DAG: ClinitCheck 264 /// CHECK-DAG: InvokeStaticOrDirect 265 266 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after) 267 /// CHECK-DAG: LoadClass 268 /// CHECK-DAG: ClinitCheck 269 /// CHECK-NOT: InvokeStaticOrDirect 270 271 static class ClassWithClinit5 { $opt$inline$StaticMethod()272 static void $opt$inline$StaticMethod() { 273 } 274 275 static { 276 System.out.println("Main$ClassWithClinit5's static initializer"); 277 } 278 } 279 280 static class SubClassOfClassWithClinit5 extends ClassWithClinit5 { invokeStaticInlined()281 static void invokeStaticInlined() { 282 ClassWithClinit5.$opt$inline$StaticMethod(); 283 } 284 } 285 286 /* 287 * Ensure an inlined call to a static method whose declaring class is a super class 288 * of the caller's class does not require an explicit clinit check if the declaring 289 * class has a trivial initialization. b/62478025 290 */ 291 292 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after) 293 /// CHECK-DAG: InvokeStaticOrDirect 294 295 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after) 296 /// CHECK-NOT: LoadClass 297 /// CHECK-NOT: ClinitCheck 298 299 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() inliner (after) 300 /// CHECK-NOT: LoadClass 301 /// CHECK-NOT: ClinitCheck 302 /// CHECK-NOT: InvokeStaticOrDirect 303 304 static class ClassWithoutClinit5 { // Mimicks ClassWithClinit5 but without the <clinit>. $opt$inline$StaticMethod()305 static void $opt$inline$StaticMethod() { 306 } 307 } 308 309 static class SubClassOfClassWithoutClinit5 extends ClassWithoutClinit5 { 310 static { 311 System.out.println("Main$SubClassOfClassWithoutClinit5's static initializer"); 312 } 313 invokeStaticInlined()314 static void invokeStaticInlined() { 315 ClassWithoutClinit5.$opt$inline$StaticMethod(); 316 } 317 } 318 319 /* 320 * We used to remove clinit check for calls to static methods in a superclass. However, this 321 * is not a valid optimization when instances of erroneous classes can escape, therefore 322 * we avoid this optimization for classes with non-trivial initialization. b/62478025 323 */ 324 325 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after) 326 /// CHECK-DAG: InvokeStaticOrDirect 327 328 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after) 329 /// CHECK-DAG: LoadClass 330 /// CHECK-DAG: ClinitCheck 331 332 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after) 333 /// CHECK-DAG: LoadClass 334 /// CHECK-DAG: ClinitCheck 335 /// CHECK-DAG: InvokeStaticOrDirect 336 337 static class ClassWithClinit6 { $noinline$staticMethod()338 static void $noinline$staticMethod() { 339 } 340 341 static { 342 System.out.println("Main$ClassWithClinit6's static initializer"); 343 } 344 } 345 346 static class SubClassOfClassWithClinit6 extends ClassWithClinit6 { invokeStaticNotInlined()347 static void invokeStaticNotInlined() { 348 ClassWithClinit6.$noinline$staticMethod(); 349 } 350 } 351 352 /* 353 * Ensure a non-inlined call to a static method whose declaring class is a super class 354 * of the caller's class does not require an explicit clinit check if the declaring 355 * class has a trivial initialization. b/62478025 356 */ 357 358 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after) 359 /// CHECK-DAG: InvokeStaticOrDirect 360 361 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after) 362 /// CHECK-NOT: LoadClass 363 /// CHECK-NOT: ClinitCheck 364 365 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after) 366 /// CHECK-DAG: InvokeStaticOrDirect 367 368 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after) 369 /// CHECK-NOT: LoadClass 370 /// CHECK-NOT: ClinitCheck 371 372 static class ClassWithoutClinit6 { // Mimicks ClassWithClinit6 but without the <clinit>. $noinline$staticMethod()373 static void $noinline$staticMethod() { 374 } 375 } 376 377 static class SubClassOfClassWithoutClinit6 extends ClassWithoutClinit6 { 378 static { 379 System.out.println("Main$SubClassOfClassWithoutClinit6's static initializer"); 380 } 381 invokeStaticNotInlined()382 static void invokeStaticNotInlined() { 383 ClassWithoutClinit6.$noinline$staticMethod(); 384 } 385 } 386 387 /* 388 * Verify that if we have a static call immediately after the load class 389 * we don't do generate a clinit check. 390 */ 391 392 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before) 393 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0 394 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false 395 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:implicit 396 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>] 397 398 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before) 399 /// CHECK-NOT: ClinitCheck 400 noClinitBecauseOfInvokeStatic()401 static void noClinitBecauseOfInvokeStatic() { 402 ClassWithClinit2.$noinline$staticMethod(); 403 ClassWithClinit2.staticField = false; 404 } 405 406 /* 407 * Verify that if the static call is after a field access, the load class 408 * will generate a clinit check. 409 */ 410 411 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before) 412 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0 413 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:true 414 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>] 415 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:none 416 417 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before) 418 /// CHECK-NOT: ClinitCheck clinitBecauseOfFieldAccess()419 static void clinitBecauseOfFieldAccess() { 420 ClassWithClinit2.staticField = false; 421 ClassWithClinit2.$noinline$staticMethod(); 422 } 423 424 /* 425 * Verify that LoadClass from const-class is not merged with 426 * later invoke-static (or it's ClinitCheck). 427 */ 428 429 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before) 430 /// CHECK: LoadClass gen_clinit_check:false 431 /// CHECK: InvokeStaticOrDirect clinit_check:implicit 432 433 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before) 434 /// CHECK-NOT: ClinitCheck 435 constClassAndInvokeStatic(Iterable<?> it)436 static void constClassAndInvokeStatic(Iterable<?> it) { 437 $opt$inline$ignoreClass(ClassWithClinit7.class); 438 ClassWithClinit7.$noinline$someStaticMethod(it); 439 } 440 $opt$inline$ignoreClass(Class<?> c)441 static void $opt$inline$ignoreClass(Class<?> c) { 442 } 443 444 static class ClassWithClinit7 { 445 static { 446 System.out.println("Main$ClassWithClinit7's static initializer"); 447 } 448 $noinline$someStaticMethod(Iterable<?> it)449 static void $noinline$someStaticMethod(Iterable<?> it) { 450 it.iterator(); 451 } 452 } 453 454 /* 455 * Verify that LoadClass from sget is not merged with later invoke-static. 456 */ 457 458 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before) 459 /// CHECK: LoadClass gen_clinit_check:true 460 /// CHECK: InvokeStaticOrDirect clinit_check:none 461 462 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before) 463 /// CHECK-NOT: ClinitCheck 464 sgetAndInvokeStatic(Iterable<?> it)465 static void sgetAndInvokeStatic(Iterable<?> it) { 466 $opt$inline$ignoreInt(ClassWithClinit8.value); 467 ClassWithClinit8.$noinline$someStaticMethod(it); 468 } 469 $opt$inline$ignoreInt(int i)470 static void $opt$inline$ignoreInt(int i) { 471 } 472 473 static class ClassWithClinit8 { 474 public static int value = 0; 475 static { 476 System.out.println("Main$ClassWithClinit8's static initializer"); 477 } 478 $noinline$someStaticMethod(Iterable<?> it)479 static void $noinline$someStaticMethod(Iterable<?> it) { 480 it.iterator(); 481 } 482 } 483 484 /* 485 * Verify that LoadClass from const-class, ClinitCheck from sget and 486 * InvokeStaticOrDirect from invoke-static are not merged. 487 */ 488 489 /// CHECK-START: void Main.constClassSgetAndInvokeStatic(java.lang.Iterable) liveness (before) 490 /// CHECK: LoadClass gen_clinit_check:false 491 /// CHECK: ClinitCheck 492 /// CHECK: InvokeStaticOrDirect clinit_check:none 493 constClassSgetAndInvokeStatic(Iterable<?> it)494 static void constClassSgetAndInvokeStatic(Iterable<?> it) { 495 $opt$inline$ignoreClass(ClassWithClinit9.class); 496 $opt$inline$ignoreInt(ClassWithClinit9.value); 497 ClassWithClinit9.$noinline$someStaticMethod(it); 498 } 499 500 static class ClassWithClinit9 { 501 public static int value = 0; 502 static { 503 System.out.println("Main$ClassWithClinit9's static initializer"); 504 } 505 $noinline$someStaticMethod(Iterable<?> it)506 static void $noinline$someStaticMethod(Iterable<?> it) { 507 it.iterator(); 508 } 509 } 510 511 /* 512 * Verify that LoadClass from a fully-inlined invoke-static is not merged 513 * with InvokeStaticOrDirect from a later invoke-static to the same method. 514 */ 515 516 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before) 517 /// CHECK: LoadClass gen_clinit_check:true 518 /// CHECK: InvokeStaticOrDirect clinit_check:none 519 520 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before) 521 /// CHECK-NOT: ClinitCheck 522 inlinedInvokeStaticViaNonStatic(Iterable<?> it)523 static void inlinedInvokeStaticViaNonStatic(Iterable<?> it) { 524 if (it != null) { 525 inlinedInvokeStaticViaNonStaticHelper(null); 526 inlinedInvokeStaticViaNonStaticHelper(it); 527 } 528 } 529 inlinedInvokeStaticViaNonStaticHelper(Iterable<?> it)530 static void inlinedInvokeStaticViaNonStaticHelper(Iterable<?> it) { 531 ClassWithClinit10.inlinedForNull(it); 532 } 533 534 static class ClassWithClinit10 { 535 public static int value = 0; 536 static { 537 System.out.println("Main$ClassWithClinit10's static initializer"); 538 } 539 inlinedForNull(Iterable<?> it)540 static void inlinedForNull(Iterable<?> it) { 541 if (it != null) { 542 it.iterator(); 543 // We're not inlining methods that always throw. 544 throw new Error(""); 545 } 546 } 547 } 548 549 /* 550 * Check that the LoadClass from an invoke-static C.foo() doesn't get merged with 551 * an invoke-static inside C.foo(). This would mess up the stack walk in the 552 * resolution trampoline where we would have to load C (if C isn't loaded yet) 553 * which is not permitted there. 554 * 555 * Note: In case of failure, we would get an failed assertion during compilation, 556 * so we wouldn't really get to the checker tests below. 557 */ 558 559 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before) 560 /// CHECK: LoadClass gen_clinit_check:true 561 /// CHECK: InvokeStaticOrDirect clinit_check:none 562 563 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before) 564 /// CHECK-NOT: ClinitCheck 565 inlinedInvokeStaticViaStatic(Iterable<?> it)566 static void inlinedInvokeStaticViaStatic(Iterable<?> it) { 567 if (it != null) { 568 ClassWithClinit11.callInlinedForNull(it); 569 } 570 } 571 572 static class ClassWithClinit11 { 573 public static int value = 0; 574 static { 575 System.out.println("Main$ClassWithClinit11's static initializer"); 576 } 577 callInlinedForNull(Iterable<?> it)578 static void callInlinedForNull(Iterable<?> it) { 579 inlinedForNull(it); 580 } 581 inlinedForNull(Iterable<?> it)582 static void inlinedForNull(Iterable<?> it) { 583 it.iterator(); 584 if (it != null) { 585 // We're not inlining methods that always throw. 586 throw new Error(""); 587 } 588 } 589 } 590 591 /* 592 * A test similar to inlinedInvokeStaticViaStatic() but doing the indirect invoke 593 * twice with the first one to be fully inlined. 594 */ 595 596 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before) 597 /// CHECK: LoadClass gen_clinit_check:true 598 /// CHECK: InvokeStaticOrDirect clinit_check:none 599 600 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before) 601 /// CHECK-NOT: ClinitCheck 602 inlinedInvokeStaticViaStaticTwice(Iterable<?> it)603 static void inlinedInvokeStaticViaStaticTwice(Iterable<?> it) { 604 if (it != null) { 605 ClassWithClinit12.callInlinedForNull(null); 606 ClassWithClinit12.callInlinedForNull(it); 607 } 608 } 609 610 static class ClassWithClinit12 { 611 public static int value = 0; 612 static { 613 System.out.println("Main$ClassWithClinit12's static initializer"); 614 } 615 callInlinedForNull(Iterable<?> it)616 static void callInlinedForNull(Iterable<?> it) { 617 inlinedForNull(it); 618 } 619 inlinedForNull(Iterable<?> it)620 static void inlinedForNull(Iterable<?> it) { 621 if (it != null) { 622 // We're not inlining methods that always throw. 623 throw new Error(""); 624 } 625 } 626 } 627 628 static class ClassWithClinit13 { 629 static { 630 System.out.println("Main$ClassWithClinit13's static initializer"); 631 } 632 $inline$forwardToGetIterator(Iterable<?> it)633 public static void $inline$forwardToGetIterator(Iterable<?> it) { 634 $noinline$getIterator(it); 635 } 636 $noinline$getIterator(Iterable<?> it)637 public static void $noinline$getIterator(Iterable<?> it) { 638 it.iterator(); 639 } 640 } 641 642 // TODO: Write checker statements. $noinline$testInliningAndNewInstance(Iterable<?> it)643 static Object $noinline$testInliningAndNewInstance(Iterable<?> it) { 644 ClassWithClinit13.$inline$forwardToGetIterator(it); 645 return new ClassWithClinit13(); 646 } 647 648 // TODO: Add a test for the case of a static method whose declaring 649 // class type index is not available (i.e. when `storage_index` 650 // equals `dex::kDexNoIndex` in 651 // art::HGraphBuilder::BuildInvoke). 652 main(String[] args)653 public static void main(String[] args) { 654 invokeStaticInlined(); 655 invokeStaticNotInlined(); 656 ClassWithClinit3Static.invokeStaticInlined(); 657 new ClassWithClinit3Instance().invokeStaticInlined(); 658 ClassWithClinit4Static.invokeStaticNotInlined(); 659 new ClassWithClinit4Instance().invokeStaticNotInlined(); 660 SubClassOfClassWithClinit5.invokeStaticInlined(); 661 SubClassOfClassWithoutClinit5.invokeStaticInlined(); 662 SubClassOfClassWithClinit6.invokeStaticNotInlined(); 663 SubClassOfClassWithoutClinit6.invokeStaticNotInlined(); 664 Iterable it = new Iterable() { public java.util.Iterator iterator() { return null; } }; 665 constClassAndInvokeStatic(it); 666 sgetAndInvokeStatic(it); 667 constClassSgetAndInvokeStatic(it); 668 try { 669 inlinedInvokeStaticViaNonStatic(it); 670 } catch (Error e) { 671 // Expected 672 } 673 try { 674 inlinedInvokeStaticViaStatic(it); 675 } catch (Error e) { 676 // Expected 677 } 678 try{ 679 inlinedInvokeStaticViaStaticTwice(it); 680 } catch (Error e) { 681 // Expected 682 } 683 $noinline$testInliningAndNewInstance(it); 684 } 685 } 686