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