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 static class ClassWithClinit4Instance { invokeStaticNotInlined()229 void invokeStaticNotInlined() { 230 // ClinitCheck required. 231 $noinline$staticMethod(); 232 } 233 234 static { 235 System.out.println("Main$ClassWithClinit4Instance's static initializer"); 236 } 237 $noinline$staticMethod()238 static void $noinline$staticMethod() { 239 } 240 } 241 242 /* 243 * We used to remove clinit check for calls to static methods in a superclass. However, this 244 * is not a valid optimization when instances of erroneous classes can escape, therefore 245 * we avoid this optimization for classes with non-trivial initialization. b/62478025 246 */ 247 248 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after) 249 /// CHECK-DAG: LoadClass 250 /// CHECK-DAG: ClinitCheck 251 /// CHECK-DAG: InvokeStaticOrDirect 252 253 /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after) 254 /// CHECK-DAG: LoadClass 255 /// CHECK-DAG: ClinitCheck 256 /// CHECK-NOT: InvokeStaticOrDirect 257 258 static class ClassWithClinit5 { $opt$inline$StaticMethod()259 static void $opt$inline$StaticMethod() { 260 } 261 262 static { 263 System.out.println("Main$ClassWithClinit5's static initializer"); 264 } 265 } 266 267 static class SubClassOfClassWithClinit5 extends ClassWithClinit5 { invokeStaticInlined()268 static void invokeStaticInlined() { 269 ClassWithClinit5.$opt$inline$StaticMethod(); 270 } 271 } 272 273 /* 274 * Ensure an inlined call to a static method whose declaring class is a super class 275 * of the caller's class does not require an explicit clinit check if the declaring 276 * class has a trivial initialization. b/62478025 277 */ 278 279 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after) 280 /// CHECK-DAG: InvokeStaticOrDirect 281 282 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() builder (after) 283 /// CHECK-NOT: LoadClass 284 /// CHECK-NOT: ClinitCheck 285 286 /// CHECK-START: void Main$SubClassOfClassWithoutClinit5.invokeStaticInlined() inliner (after) 287 /// CHECK-NOT: LoadClass 288 /// CHECK-NOT: ClinitCheck 289 /// CHECK-NOT: InvokeStaticOrDirect 290 291 static class ClassWithoutClinit5 { // Mimicks ClassWithClinit5 but without the <clinit>. $opt$inline$StaticMethod()292 static void $opt$inline$StaticMethod() { 293 } 294 } 295 296 static class SubClassOfClassWithoutClinit5 extends ClassWithoutClinit5 { 297 static { 298 System.out.println("Main$SubClassOfClassWithoutClinit5's static initializer"); 299 } 300 invokeStaticInlined()301 static void invokeStaticInlined() { 302 ClassWithoutClinit5.$opt$inline$StaticMethod(); 303 } 304 } 305 306 /* 307 * We used to remove clinit check for calls to static methods in a superclass. However, this 308 * is not a valid optimization when instances of erroneous classes can escape, therefore 309 * we avoid this optimization for classes with non-trivial initialization. b/62478025 310 */ 311 312 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after) 313 /// CHECK-DAG: InvokeStaticOrDirect 314 315 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after) 316 /// CHECK-DAG: LoadClass 317 /// CHECK-DAG: ClinitCheck 318 319 /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after) 320 /// CHECK-DAG: LoadClass 321 /// CHECK-DAG: ClinitCheck 322 /// CHECK-DAG: InvokeStaticOrDirect 323 324 static class ClassWithClinit6 { $noinline$staticMethod()325 static void $noinline$staticMethod() { 326 } 327 328 static { 329 System.out.println("Main$ClassWithClinit6's static initializer"); 330 } 331 } 332 333 static class SubClassOfClassWithClinit6 extends ClassWithClinit6 { invokeStaticNotInlined()334 static void invokeStaticNotInlined() { 335 ClassWithClinit6.$noinline$staticMethod(); 336 } 337 } 338 339 /* 340 * Ensure a non-inlined call to a static method whose declaring class is a super class 341 * of the caller's class does not require an explicit clinit check if the declaring 342 * class has a trivial initialization. b/62478025 343 */ 344 345 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after) 346 /// CHECK-DAG: InvokeStaticOrDirect 347 348 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() builder (after) 349 /// CHECK-NOT: LoadClass 350 /// CHECK-NOT: ClinitCheck 351 352 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after) 353 /// CHECK-DAG: InvokeStaticOrDirect 354 355 /// CHECK-START: void Main$SubClassOfClassWithoutClinit6.invokeStaticNotInlined() inliner (after) 356 /// CHECK-NOT: LoadClass 357 /// CHECK-NOT: ClinitCheck 358 359 static class ClassWithoutClinit6 { // Mimicks ClassWithClinit6 but without the <clinit>. $noinline$staticMethod()360 static void $noinline$staticMethod() { 361 } 362 } 363 364 static class SubClassOfClassWithoutClinit6 extends ClassWithoutClinit6 { 365 static { 366 System.out.println("Main$SubClassOfClassWithoutClinit6's static initializer"); 367 } 368 invokeStaticNotInlined()369 static void invokeStaticNotInlined() { 370 ClassWithoutClinit6.$noinline$staticMethod(); 371 } 372 } 373 374 /* 375 * Verify that if we have a static call immediately after the load class 376 * we don't do generate a clinit check. 377 */ 378 379 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before) 380 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0 381 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false 382 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:implicit 383 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>] 384 385 /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before) 386 /// CHECK-NOT: ClinitCheck 387 noClinitBecauseOfInvokeStatic()388 static void noClinitBecauseOfInvokeStatic() { 389 ClassWithClinit2.$noinline$staticMethod(); 390 ClassWithClinit2.staticField = false; 391 } 392 393 /* 394 * Verify that if the static call is after a field access, the load class 395 * will generate a clinit check. 396 */ 397 398 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before) 399 /// CHECK-DAG: <<IntConstant:i\d+>> IntConstant 0 400 /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:true 401 /// CHECK-DAG: StaticFieldSet [<<LoadClass>>,<<IntConstant>>] 402 /// CHECK-DAG: InvokeStaticOrDirect clinit_check:none 403 404 /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before) 405 /// CHECK-NOT: ClinitCheck clinitBecauseOfFieldAccess()406 static void clinitBecauseOfFieldAccess() { 407 ClassWithClinit2.staticField = false; 408 ClassWithClinit2.$noinline$staticMethod(); 409 } 410 411 /* 412 * Verify that LoadClass from const-class is not merged with 413 * later invoke-static (or it's ClinitCheck). 414 */ 415 416 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before) 417 /// CHECK: LoadClass gen_clinit_check:false 418 /// CHECK: InvokeStaticOrDirect clinit_check:implicit 419 420 /// CHECK-START: void Main.constClassAndInvokeStatic(java.lang.Iterable) liveness (before) 421 /// CHECK-NOT: ClinitCheck 422 constClassAndInvokeStatic(Iterable<?> it)423 static void constClassAndInvokeStatic(Iterable<?> it) { 424 $opt$inline$ignoreClass(ClassWithClinit7.class); 425 ClassWithClinit7.$noinline$someStaticMethod(it); 426 } 427 $opt$inline$ignoreClass(Class<?> c)428 static void $opt$inline$ignoreClass(Class<?> c) { 429 } 430 431 static class ClassWithClinit7 { 432 static { 433 System.out.println("Main$ClassWithClinit7's static initializer"); 434 } 435 $noinline$someStaticMethod(Iterable<?> it)436 static void $noinline$someStaticMethod(Iterable<?> it) { 437 it.iterator(); 438 } 439 } 440 441 /* 442 * Verify that LoadClass from sget is not merged with later invoke-static. 443 */ 444 445 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before) 446 /// CHECK: LoadClass gen_clinit_check:true 447 /// CHECK: InvokeStaticOrDirect clinit_check:none 448 449 /// CHECK-START: void Main.sgetAndInvokeStatic(java.lang.Iterable) liveness (before) 450 /// CHECK-NOT: ClinitCheck 451 sgetAndInvokeStatic(Iterable<?> it)452 static void sgetAndInvokeStatic(Iterable<?> it) { 453 $opt$inline$ignoreInt(ClassWithClinit8.value); 454 ClassWithClinit8.$noinline$someStaticMethod(it); 455 } 456 $opt$inline$ignoreInt(int i)457 static void $opt$inline$ignoreInt(int i) { 458 } 459 460 static class ClassWithClinit8 { 461 public static int value = 0; 462 static { 463 System.out.println("Main$ClassWithClinit8's static initializer"); 464 } 465 $noinline$someStaticMethod(Iterable<?> it)466 static void $noinline$someStaticMethod(Iterable<?> it) { 467 it.iterator(); 468 } 469 } 470 471 /* 472 * Verify that LoadClass from const-class, ClinitCheck from sget and 473 * InvokeStaticOrDirect from invoke-static are not merged. 474 */ 475 476 /// CHECK-START: void Main.constClassSgetAndInvokeStatic(java.lang.Iterable) liveness (before) 477 /// CHECK: LoadClass gen_clinit_check:false 478 /// CHECK: ClinitCheck 479 /// CHECK: InvokeStaticOrDirect clinit_check:none 480 constClassSgetAndInvokeStatic(Iterable<?> it)481 static void constClassSgetAndInvokeStatic(Iterable<?> it) { 482 $opt$inline$ignoreClass(ClassWithClinit9.class); 483 $opt$inline$ignoreInt(ClassWithClinit9.value); 484 ClassWithClinit9.$noinline$someStaticMethod(it); 485 } 486 487 static class ClassWithClinit9 { 488 public static int value = 0; 489 static { 490 System.out.println("Main$ClassWithClinit9's static initializer"); 491 } 492 $noinline$someStaticMethod(Iterable<?> it)493 static void $noinline$someStaticMethod(Iterable<?> it) { 494 it.iterator(); 495 } 496 } 497 498 /* 499 * Verify that LoadClass from a fully-inlined invoke-static is not merged 500 * with InvokeStaticOrDirect from a later invoke-static to the same method. 501 */ 502 503 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before) 504 /// CHECK: LoadClass gen_clinit_check:true 505 /// CHECK: InvokeStaticOrDirect clinit_check:none 506 507 /// CHECK-START: void Main.inlinedInvokeStaticViaNonStatic(java.lang.Iterable) liveness (before) 508 /// CHECK-NOT: ClinitCheck 509 inlinedInvokeStaticViaNonStatic(Iterable<?> it)510 static void inlinedInvokeStaticViaNonStatic(Iterable<?> it) { 511 if (it != null) { 512 inlinedInvokeStaticViaNonStaticHelper(null); 513 inlinedInvokeStaticViaNonStaticHelper(it); 514 } 515 } 516 inlinedInvokeStaticViaNonStaticHelper(Iterable<?> it)517 static void inlinedInvokeStaticViaNonStaticHelper(Iterable<?> it) { 518 ClassWithClinit10.inlinedForNull(it); 519 } 520 521 static class ClassWithClinit10 { 522 public static int value = 0; 523 static { 524 System.out.println("Main$ClassWithClinit10's static initializer"); 525 } 526 inlinedForNull(Iterable<?> it)527 static void inlinedForNull(Iterable<?> it) { 528 if (it != null) { 529 it.iterator(); 530 // We're not inlining methods that always throw. 531 throw new Error(""); 532 } 533 } 534 } 535 536 /* 537 * Check that the LoadClass from an invoke-static C.foo() doesn't get merged with 538 * an invoke-static inside C.foo(). This would mess up the stack walk in the 539 * resolution trampoline where we would have to load C (if C isn't loaded yet) 540 * which is not permitted there. 541 * 542 * Note: In case of failure, we would get an failed assertion during compilation, 543 * so we wouldn't really get to the checker tests below. 544 */ 545 546 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before) 547 /// CHECK: LoadClass gen_clinit_check:true 548 /// CHECK: InvokeStaticOrDirect clinit_check:none 549 550 /// CHECK-START: void Main.inlinedInvokeStaticViaStatic(java.lang.Iterable) liveness (before) 551 /// CHECK-NOT: ClinitCheck 552 inlinedInvokeStaticViaStatic(Iterable<?> it)553 static void inlinedInvokeStaticViaStatic(Iterable<?> it) { 554 if (it != null) { 555 ClassWithClinit11.callInlinedForNull(it); 556 } 557 } 558 559 static class ClassWithClinit11 { 560 public static int value = 0; 561 static { 562 System.out.println("Main$ClassWithClinit11's static initializer"); 563 } 564 callInlinedForNull(Iterable<?> it)565 static void callInlinedForNull(Iterable<?> it) { 566 inlinedForNull(it); 567 } 568 inlinedForNull(Iterable<?> it)569 static void inlinedForNull(Iterable<?> it) { 570 it.iterator(); 571 if (it != null) { 572 // We're not inlining methods that always throw. 573 throw new Error(""); 574 } 575 } 576 } 577 578 /* 579 * A test similar to inlinedInvokeStaticViaStatic() but doing the indirect invoke 580 * twice with the first one to be fully inlined. 581 */ 582 583 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before) 584 /// CHECK: LoadClass gen_clinit_check:true 585 /// CHECK: InvokeStaticOrDirect clinit_check:none 586 587 /// CHECK-START: void Main.inlinedInvokeStaticViaStaticTwice(java.lang.Iterable) liveness (before) 588 /// CHECK-NOT: ClinitCheck 589 inlinedInvokeStaticViaStaticTwice(Iterable<?> it)590 static void inlinedInvokeStaticViaStaticTwice(Iterable<?> it) { 591 if (it != null) { 592 ClassWithClinit12.callInlinedForNull(null); 593 ClassWithClinit12.callInlinedForNull(it); 594 } 595 } 596 597 static class ClassWithClinit12 { 598 public static int value = 0; 599 static { 600 System.out.println("Main$ClassWithClinit12's static initializer"); 601 } 602 callInlinedForNull(Iterable<?> it)603 static void callInlinedForNull(Iterable<?> it) { 604 inlinedForNull(it); 605 } 606 inlinedForNull(Iterable<?> it)607 static void inlinedForNull(Iterable<?> it) { 608 if (it != null) { 609 // We're not inlining methods that always throw. 610 throw new Error(""); 611 } 612 } 613 } 614 615 static class ClassWithClinit13 { 616 static { 617 System.out.println("Main$ClassWithClinit13's static initializer"); 618 } 619 $inline$forwardToGetIterator(Iterable<?> it)620 public static void $inline$forwardToGetIterator(Iterable<?> it) { 621 $noinline$getIterator(it); 622 } 623 $noinline$getIterator(Iterable<?> it)624 public static void $noinline$getIterator(Iterable<?> it) { 625 it.iterator(); 626 } 627 } 628 629 // TODO: Write checker statements. $noinline$testInliningAndNewInstance(Iterable<?> it)630 static Object $noinline$testInliningAndNewInstance(Iterable<?> it) { 631 ClassWithClinit13.$inline$forwardToGetIterator(it); 632 return new ClassWithClinit13(); 633 } 634 635 // TODO: Add a test for the case of a static method whose declaring 636 // class type index is not available (i.e. when `storage_index` 637 // equals `dex::kDexNoIndex` in 638 // art::HGraphBuilder::BuildInvoke). 639 main(String[] args)640 public static void main(String[] args) { 641 invokeStaticInlined(); 642 invokeStaticNotInlined(); 643 ClassWithClinit3Static.invokeStaticInlined(); 644 new ClassWithClinit3Instance().invokeStaticInlined(); 645 ClassWithClinit4Static.invokeStaticNotInlined(); 646 new ClassWithClinit4Instance().invokeStaticNotInlined(); 647 SubClassOfClassWithClinit5.invokeStaticInlined(); 648 SubClassOfClassWithoutClinit5.invokeStaticInlined(); 649 SubClassOfClassWithClinit6.invokeStaticNotInlined(); 650 SubClassOfClassWithoutClinit6.invokeStaticNotInlined(); 651 Iterable it = new Iterable() { public java.util.Iterator iterator() { return null; } }; 652 constClassAndInvokeStatic(it); 653 sgetAndInvokeStatic(it); 654 constClassSgetAndInvokeStatic(it); 655 try { 656 inlinedInvokeStaticViaNonStatic(it); 657 } catch (Error e) { 658 // Expected 659 } 660 try { 661 inlinedInvokeStaticViaStatic(it); 662 } catch (Error e) { 663 // Expected 664 } 665 try{ 666 inlinedInvokeStaticViaStaticTwice(it); 667 } catch (Error e) { 668 // Expected 669 } 670 $noinline$testInliningAndNewInstance(it); 671 } 672 } 673