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