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 interface SuperInterface {
superInterfaceMethod()18   void superInterfaceMethod();
19 }
20 
21 interface OtherInterface extends SuperInterface {
22 }
23 
24 interface Interface extends SuperInterface {
$noinline$f()25   void $noinline$f();
26 }
27 
28 class Super implements Interface {
superInterfaceMethod()29   public void superInterfaceMethod() {}
$noinline$f()30   public void $noinline$f() {
31     throw new RuntimeException();
32   }
33 
$inline$h(boolean cond)34   public int $inline$h(boolean cond) {
35     Super obj = (cond ? this : null);
36     return obj.hashCode();
37   }
38 }
39 
40 class SubclassA extends Super {
$noinline$f()41   public void $noinline$f() {
42     throw new RuntimeException();
43   }
44 
$noinline$h()45   public String $noinline$h() {
46     throw new RuntimeException();
47   }
48 
$noinline$g()49   void $noinline$g() {
50     throw new RuntimeException();
51   }
52 }
53 
54 class SubclassC extends SubclassA {
55 }
56 
57 class SubclassB extends Super {
$noinline$f()58   public void $noinline$f() {
59     throw new RuntimeException();
60   }
61 
$noinline$g()62   void $noinline$g() {
63     throw new RuntimeException();
64   }
65 }
66 
67 class Generic<A> {
68   private A a = null;
get()69   public A get() {
70     return a;
71   }
72 }
73 
74 final class Final {}
75 
76 final class FinalException extends Exception {}
77 
78 public class Main {
79 
80   /// CHECK-START: void Main.testSimpleRemove() instruction_simplifier (before)
81   /// CHECK:         CheckCast
82 
83   /// CHECK-START: void Main.testSimpleRemove() instruction_simplifier (after)
84   /// CHECK-NOT:     CheckCast
testSimpleRemove()85   public void testSimpleRemove() {
86     Super s = new SubclassA();
87     ((SubclassA)s).$noinline$g();
88   }
89 
90   /// CHECK-START: void Main.testSimpleKeep(Super) instruction_simplifier (before)
91   /// CHECK:         CheckCast
92 
93   /// CHECK-START: void Main.testSimpleKeep(Super) instruction_simplifier (after)
94   /// CHECK:         CheckCast
testSimpleKeep(Super s)95   public void testSimpleKeep(Super s) {
96     ((SubclassA)s).$noinline$f();
97   }
98 
99   /// CHECK-START: java.lang.String Main.testClassRemove() instruction_simplifier (before)
100   /// CHECK:         CheckCast
101 
102   /// CHECK-START: java.lang.String Main.testClassRemove() instruction_simplifier (after)
103   /// CHECK-NOT:     CheckCast
testClassRemove()104   public String testClassRemove() {
105     Object s = SubclassA.class;
106     return ((Class<?>)s).getName();
107   }
108 
109   /// CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier (before)
110   /// CHECK:         CheckCast
111 
112   /// CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier (after)
113   /// CHECK:         CheckCast
testClassKeep()114   public String testClassKeep() {
115     Object s = SubclassA.class;
116     return ((SubclassA)s).$noinline$h();
117   }
118 
119   /// CHECK-START: void Main.testIfRemove(int) instruction_simplifier (before)
120   /// CHECK:         CheckCast
121 
122   /// CHECK-START: void Main.testIfRemove(int) instruction_simplifier (after)
123   /// CHECK-NOT:     CheckCast
testIfRemove(int x)124   public void testIfRemove(int x) {
125     Super s;
126     if (x % 2 == 0) {
127       s = new SubclassA();
128     } else {
129       s = new SubclassC();
130     }
131     ((SubclassA)s).$noinline$g();
132   }
133 
134   /// CHECK-START: void Main.testIfKeep(int) instruction_simplifier (before)
135   /// CHECK:         CheckCast
136 
137   /// CHECK-START: void Main.testIfKeep(int) instruction_simplifier (after)
138   /// CHECK:         CheckCast
testIfKeep(int x)139   public void testIfKeep(int x) {
140     Super s;
141     if (x % 2 == 0) {
142       s = new SubclassA();
143     } else {
144       s = new SubclassB();
145     }
146     ((SubclassA)s).$noinline$g();
147   }
148 
149   /// CHECK-START: void Main.testForRemove(int) instruction_simplifier (before)
150   /// CHECK:         CheckCast
151 
152   /// CHECK-START: void Main.testForRemove(int) instruction_simplifier (after)
153   /// CHECK-NOT:     CheckCast
testForRemove(int x)154   public void testForRemove(int x) {
155     Super s = new SubclassA();
156     for (int i = 0 ; i < x; i++) {
157       if (x % 2 == 0) {
158         s = new SubclassC();
159       }
160     }
161     ((SubclassA)s).$noinline$g();
162   }
163 
164   /// CHECK-START: void Main.testForKeep(int) instruction_simplifier (before)
165   /// CHECK:         CheckCast
166 
167   /// CHECK-START: void Main.testForKeep(int) instruction_simplifier (after)
168   /// CHECK:         CheckCast
testForKeep(int x)169   public void testForKeep(int x) {
170     Super s = new SubclassA();
171     for (int i = 0 ; i < x; i++) {
172       if (x % 2 == 0) {
173         s = new SubclassC();
174       }
175     }
176     ((SubclassC)s).$noinline$g();
177   }
178 
179   /// CHECK-START: void Main.testPhiFromCall(int) instruction_simplifier (before)
180   /// CHECK:         CheckCast
181 
182   /// CHECK-START: void Main.testPhiFromCall(int) instruction_simplifier (after)
183   /// CHECK:         CheckCast
testPhiFromCall(int i)184   public void testPhiFromCall(int i) {
185     Object x;
186     if (i % 2 == 0) {
187       x = new SubclassC();
188     } else {
189       x = newObject();  // this one will have an unknown type.
190     }
191     ((SubclassC)x).$noinline$g();
192   }
193 
194   /// CHECK-START: void Main.testInstanceOf(java.lang.Object) instruction_simplifier (before)
195   /// CHECK:         CheckCast
196   /// CHECK:         CheckCast
197   /// CHECK-NOT:     CheckCast
198 
199   /// CHECK-START: void Main.testInstanceOf(java.lang.Object) instruction_simplifier (after)
200   /// CHECK-NOT:     CheckCast
testInstanceOf(Object o)201   public void testInstanceOf(Object o) {
202     if (o instanceof SubclassC) {
203       ((SubclassC)o).$noinline$g();
204     }
205     if (o instanceof SubclassB) {
206       ((SubclassB)o).$noinline$g();
207     }
208   }
209 
$inline$InstanceofSubclassB(Object o)210   public static boolean $inline$InstanceofSubclassB(Object o) { return o instanceof SubclassB; }
$inline$InstanceofSubclassC(Object o)211   public static boolean $inline$InstanceofSubclassC(Object o) { return o instanceof SubclassC; }
212 
213   /// CHECK-START: void Main.testInstanceOf_NotInlined(java.lang.Object) builder (after)
214   /// CHECK-DAG:     <<Cst0:i\d+>> IntConstant 0
215   /// CHECK-DAG:     <<Cst1:i\d+>> IntConstant 1
216   /// CHECK-DAG:     <<IOf1:z\d+>> InstanceOf
217   /// CHECK-DAG:                   NotEqual [<<IOf1>>,<<Cst1>>]
218   /// CHECK-DAG:     <<IOf2:z\d+>> InstanceOf
219   /// CHECK-DAG:                   Equal [<<IOf2>>,<<Cst0>>]
220 
221   /// CHECK-START: void Main.testInstanceOf_NotInlined(java.lang.Object) instruction_simplifier (before)
222   /// CHECK:         CheckCast
223   /// CHECK:         CheckCast
224   /// CHECK-NOT:     CheckCast
225 
226   /// CHECK-START: void Main.testInstanceOf_NotInlined(java.lang.Object) instruction_simplifier (after)
227   /// CHECK-NOT:     CheckCast
testInstanceOf_NotInlined(Object o)228   public void testInstanceOf_NotInlined(Object o) {
229     if ((o instanceof SubclassC) == true) {
230       ((SubclassC)o).$noinline$g();
231     }
232     if ((o instanceof SubclassB) != false) {
233       ((SubclassB)o).$noinline$g();
234     }
235   }
236 
237   /// CHECK-START: void Main.testNotInstanceOf_NotInlined(java.lang.Object) builder (after)
238   /// CHECK-DAG:     <<Cst0:i\d+>> IntConstant 0
239   /// CHECK-DAG:     <<Cst1:i\d+>> IntConstant 1
240   /// CHECK-DAG:     <<IOf1:z\d+>> InstanceOf
241   /// CHECK-DAG:                   Equal [<<IOf1>>,<<Cst1>>]
242   /// CHECK-DAG:     <<IOf2:z\d+>> InstanceOf
243   /// CHECK-DAG:                   NotEqual [<<IOf2>>,<<Cst0>>]
244 
245   /// CHECK-START: void Main.testNotInstanceOf_NotInlined(java.lang.Object) instruction_simplifier (before)
246   /// CHECK:         CheckCast
247   /// CHECK:         CheckCast
248   /// CHECK-NOT:     CheckCast
249 
250   /// CHECK-START: void Main.testNotInstanceOf_NotInlined(java.lang.Object) instruction_simplifier (after)
251   /// CHECK-NOT:     CheckCast
testNotInstanceOf_NotInlined(Object o)252   public void testNotInstanceOf_NotInlined(Object o) {
253     if ((o instanceof SubclassC) != true) {
254       // Empty branch to flip the condition.
255     } else {
256       ((SubclassC)o).$noinline$g();
257     }
258     if ((o instanceof SubclassB) == false) {
259       // Empty branch to flip the condition.
260     } else {
261       ((SubclassB)o).$noinline$g();
262     }
263   }
264 
265   /// CHECK-START: void Main.testInstanceOf_Inlined(java.lang.Object) inliner (after)
266   /// CHECK-DAG:     <<IOf:z\d+>>  InstanceOf
267   /// CHECK-DAG:                   If [<<IOf>>]
268 
269   /// CHECK-START: void Main.testInstanceOf_Inlined(java.lang.Object) instruction_simplifier$after_inlining (before)
270   /// CHECK:         CheckCast
271   /// CHECK-NOT:     CheckCast
272 
273   /// CHECK-START: void Main.testInstanceOf_Inlined(java.lang.Object) instruction_simplifier$after_inlining (after)
274   /// CHECK-NOT:     CheckCast
testInstanceOf_Inlined(Object o)275   public void testInstanceOf_Inlined(Object o) {
276     if (!$inline$InstanceofSubclassC(o)) {
277       // Empty branch to flip the condition.
278     } else {
279       ((SubclassC)o).$noinline$g();
280     }
281   }
282 
283   /// CHECK-START: void Main.testInstanceOfKeep(java.lang.Object) instruction_simplifier (before)
284   /// CHECK:         CheckCast
285   /// CHECK:         CheckCast
286 
287   /// CHECK-START: void Main.testInstanceOfKeep(java.lang.Object) instruction_simplifier (after)
288   /// CHECK:         CheckCast
289   /// CHECK:         CheckCast
testInstanceOfKeep(Object o)290   public void testInstanceOfKeep(Object o) {
291     if (o instanceof SubclassC) {
292       ((SubclassB)o).$noinline$g();
293     }
294     if (o instanceof SubclassB) {
295       ((SubclassA)o).$noinline$g();
296     }
297   }
298 
299   /// CHECK-START: void Main.testInstanceOfNested(java.lang.Object) instruction_simplifier (before)
300   /// CHECK:         CheckCast
301   /// CHECK:         CheckCast
302 
303   /// CHECK-START: void Main.testInstanceOfNested(java.lang.Object) instruction_simplifier (after)
304   /// CHECK-NOT:     CheckCast
testInstanceOfNested(Object o)305   public void testInstanceOfNested(Object o) {
306     if (o instanceof SubclassC) {
307       if (o instanceof SubclassB) {
308         ((SubclassB)o).$noinline$g();
309       } else {
310         ((SubclassC)o).$noinline$g();
311       }
312     }
313   }
314 
315   /// CHECK-START: void Main.testInstanceOfWithPhi(int) instruction_simplifier (before)
316   /// CHECK:         CheckCast
317 
318   /// CHECK-START: void Main.testInstanceOfWithPhi(int) instruction_simplifier (after)
319   /// CHECK-NOT:     CheckCast
testInstanceOfWithPhi(int i)320   public void testInstanceOfWithPhi(int i) {
321     Object o;
322     if (i == 0) {
323       o = new SubclassA();
324     } else {
325       o = new SubclassB();
326     }
327 
328     if (o instanceof SubclassB) {
329       ((SubclassB)o).$noinline$g();
330     }
331   }
332 
333   /// CHECK-START: void Main.testInstanceOfInFor(int) instruction_simplifier (before)
334   /// CHECK:         CheckCast
335 
336   /// CHECK-START: void Main.testInstanceOfInFor(int) instruction_simplifier (after)
337   /// CHECK-NOT:     CheckCast
testInstanceOfInFor(int n)338   public void testInstanceOfInFor(int n) {
339     Object o = new SubclassA();
340     for (int i = 0; i < n; i++) {
341       if (i / 2 == 0) {
342         o = new SubclassB();
343       }
344       if (o instanceof SubclassB) {
345         ((SubclassB)o).$noinline$g();
346       }
347     }
348   }
349 
350   /// CHECK-START: void Main.testInstanceOfSubclass() instruction_simplifier (before)
351   /// CHECK:         CheckCast
352 
353   /// CHECK-START: void Main.testInstanceOfSubclass() instruction_simplifier (after)
354   /// CHECK-NOT:     CheckCast
testInstanceOfSubclass()355   public void testInstanceOfSubclass() {
356     Object o = new SubclassA();
357     if (o instanceof Super) {
358       ((SubclassA)o).$noinline$g();
359     }
360   }
361 
362   /// CHECK-START: void Main.testInstanceOfWithPhiSubclass(int) instruction_simplifier (before)
363   /// CHECK:         CheckCast
364 
365   /// CHECK-START: void Main.testInstanceOfWithPhiSubclass(int) instruction_simplifier (after)
366   /// CHECK-NOT:     CheckCast
testInstanceOfWithPhiSubclass(int i)367   public void testInstanceOfWithPhiSubclass(int i) {
368     Object o;
369     if (i == 0) {
370       o = new SubclassA();
371     } else {
372       o = new SubclassC();
373     }
374 
375     if (o instanceof Super) {
376       ((SubclassA)o).$noinline$g();
377     }
378   }
379 
380   /// CHECK-START: void Main.testInstanceOfWithPhiTop(int) instruction_simplifier (before)
381   /// CHECK:         CheckCast
382 
383   /// CHECK-START: void Main.testInstanceOfWithPhiTop(int) instruction_simplifier (after)
384   /// CHECK-NOT:     CheckCast
testInstanceOfWithPhiTop(int i)385   public void testInstanceOfWithPhiTop(int i) {
386     Object o;
387     if (i == 0) {
388       o = new Object();
389     } else {
390       o = new SubclassC();
391     }
392 
393     if (o instanceof Super) {
394       ((Super)o).$noinline$f();
395     }
396   }
397 
398   /// CHECK-START: void Main.testInstanceOfSubclassInFor(int) instruction_simplifier (before)
399   /// CHECK:         CheckCast
400 
401   /// CHECK-START: void Main.testInstanceOfSubclassInFor(int) instruction_simplifier (after)
402   /// CHECK-NOT:     CheckCast
testInstanceOfSubclassInFor(int n)403   public void testInstanceOfSubclassInFor(int n) {
404     Object o = new SubclassA();
405     for (int i = 0; i < n; i++) {
406       if (o instanceof Super) {
407         ((SubclassA)o).$noinline$g();
408       }
409       if (i / 2 == 0) {
410         o = new SubclassC();
411       }
412     }
413   }
414 
415   /// CHECK-START: void Main.testInstanceOfTopInFor(int) instruction_simplifier (before)
416   /// CHECK:         CheckCast
417 
418   /// CHECK-START: void Main.testInstanceOfTopInFor(int) instruction_simplifier (after)
419   /// CHECK-NOT:     CheckCast
testInstanceOfTopInFor(int n)420   public void testInstanceOfTopInFor(int n) {
421     Object o = new SubclassA();
422     for (int i = 0; i < n; i++) {
423       if (o instanceof Super) {
424         ((Super)o).$noinline$f();
425       }
426       if (i / 2 == 0) {
427         o = new Object();
428       }
429     }
430   }
431 
newObject()432   public Object newObject() {
433     try {
434       return Object.class.newInstance();
435     } catch (Exception e) {
436       return null;
437     }
438   }
439 
440   public SubclassA a = new SubclassA();
441   public static SubclassA b = new SubclassA();
442 
443   /// CHECK-START: void Main.testInstanceFieldGetSimpleRemove() instruction_simplifier (before)
444   /// CHECK:         CheckCast
445 
446   /// CHECK-START: void Main.testInstanceFieldGetSimpleRemove() instruction_simplifier (after)
447   /// CHECK-NOT:     CheckCast
testInstanceFieldGetSimpleRemove()448   public void testInstanceFieldGetSimpleRemove() {
449     Main m = new Main();
450     Super a = m.a;
451     ((SubclassA)a).$noinline$g();
452   }
453 
454   /// CHECK-START: void Main.testStaticFieldGetSimpleRemove() instruction_simplifier (before)
455   /// CHECK:         CheckCast
456 
457   /// CHECK-START: void Main.testStaticFieldGetSimpleRemove() instruction_simplifier (after)
458   /// CHECK-NOT:     CheckCast
testStaticFieldGetSimpleRemove()459   public void testStaticFieldGetSimpleRemove() {
460     Super b = Main.b;
461     ((SubclassA)b).$noinline$g();
462   }
463 
$noinline$getSubclass()464   public SubclassA $noinline$getSubclass() { throw new RuntimeException(); }
465 
466   /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier (before)
467   /// CHECK:         CheckCast
468 
469   /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier (after)
470   /// CHECK-NOT:     CheckCast
testInvokeSimpleRemove()471   public void testInvokeSimpleRemove() {
472     Super b = $noinline$getSubclass();
473     ((SubclassA)b).$noinline$g();
474   }
475   /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier (before)
476   /// CHECK:         CheckCast
477 
478   /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier (after)
479   /// CHECK-NOT:     CheckCast
testArrayGetSimpleRemove()480   public void testArrayGetSimpleRemove() {
481     Super[] a = new SubclassA[10];
482     ((SubclassA)a[0]).$noinline$g();
483   }
484 
485   /// CHECK-START: int Main.testLoadExceptionInCatchNonExact(int, int) builder (after)
486   /// CHECK:         LoadException klass:java.lang.ArithmeticException can_be_null:false exact:false
testLoadExceptionInCatchNonExact(int x, int y)487   public int testLoadExceptionInCatchNonExact(int x, int y) {
488     try {
489       return x / y;
490     } catch (ArithmeticException ex) {
491       return ex.hashCode();
492     }
493   }
494 
495   /// CHECK-START: int Main.testLoadExceptionInCatchExact(int) builder (after)
496   /// CHECK:         LoadException klass:FinalException can_be_null:false exact:true
testLoadExceptionInCatchExact(int x)497   public int testLoadExceptionInCatchExact(int x) {
498     try {
499       if (x == 42) {
500         throw new FinalException();
501       } else {
502         return x;
503       }
504     } catch (FinalException ex) {
505       return ex.hashCode();
506     }
507   }
508 
509   /// CHECK-START: int Main.testLoadExceptionInCatchAll(int, int) builder (after)
510   /// CHECK:         LoadException klass:java.lang.Throwable can_be_null:false exact:false
testLoadExceptionInCatchAll(int x, int y)511   public int testLoadExceptionInCatchAll(int x, int y) {
512     try {
513       x = x / y;
514     } finally {
515       return x;
516     }
517   }
518 
519   private Generic<SubclassC> genericC = new Generic<SubclassC>();
520   private Generic<Final> genericFinal = new Generic<Final>();
521 
get()522   private SubclassC get() {
523     return genericC.get();
524   }
525 
getFinal()526   private Final getFinal() {
527     return genericFinal.get();
528   }
529 
530   /// CHECK-START: SubclassC Main.inlineGenerics() builder (after)
531   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:SubclassC exact:false
532   /// CHECK-NEXT:                    Return [<<Invoke>>]
533 
534   /// CHECK-START: SubclassC Main.inlineGenerics() inliner (after)
535   /// CHECK:      <<BoundType:l\d+>> BoundType klass:SubclassC exact:false
536   /// CHECK:                         Return [<<BoundType>>]
inlineGenerics()537   private SubclassC inlineGenerics() {
538     SubclassC c = get();
539     return c;
540   }
541 
542   /// CHECK-START: Final Main.inlineGenericsFinal() builder (after)
543   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:Final exact:true
544   /// CHECK-NEXT:                    Return [<<Invoke>>]
545 
546   /// CHECK-START: Final Main.inlineGenericsFinal() inliner (after)
547   /// CHECK:      <<BoundType:l\d+>> BoundType klass:Final exact:true
548   /// CHECK:                         Return [<<BoundType>>]
inlineGenericsFinal()549   private Final inlineGenericsFinal() {
550     Final f = getFinal();
551     return f;
552   }
553 
554   /// CHECK-START: void Main.boundOnlyOnceIfNotNull(java.lang.Object) inliner (after)
555   /// CHECK:      BoundType
556   /// CHECK-NOT:  BoundType
boundOnlyOnceIfNotNull(Object o)557   private void boundOnlyOnceIfNotNull(Object o) {
558     if (o != null) {
559       o.toString();
560     }
561   }
562 
563   /// CHECK-START: void Main.boundOnlyOnceIfInstanceOf(java.lang.Object) inliner (after)
564   /// CHECK:      BoundType
565   /// CHECK-NOT:  BoundType
boundOnlyOnceIfInstanceOf(Object o)566   private void boundOnlyOnceIfInstanceOf(Object o) {
567     if (o instanceof Main) {
568       o.toString();
569     }
570   }
571 
572   /// CHECK-START: Final Main.boundOnlyOnceCheckCast(Generic) inliner (after)
573   /// CHECK:      BoundType
574   /// CHECK-NOT:  BoundType
boundOnlyOnceCheckCast(Generic<Final> o)575   private Final boundOnlyOnceCheckCast(Generic<Final> o) {
576     Final f = o.get();
577     return f;
578   }
579 
getSuper()580   private Super getSuper() {
581     return new SubclassA();
582   }
583 
584   /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) builder (after)
585   /// CHECK:      <<Phi:l\d+>> Phi klass:Super
586   /// CHECK:                   NullCheck [<<Phi>>] klass:Super
587 
588   /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) inliner (after)
589   /// CHECK:      <<Phi:l\d+>> Phi klass:SubclassA
590   /// CHECK:                   NullCheck [<<Phi>>] klass:SubclassA
updateNodesInTheSameBlockAsPhi(boolean cond)591   private void updateNodesInTheSameBlockAsPhi(boolean cond) {
592     Super s = getSuper();
593     if (cond) {
594       s = new SubclassA();
595     }
596     s.$noinline$f();
597   }
598 
599   /// CHECK-START: java.lang.String Main.checkcastPreserveNullCheck(java.lang.Object) inliner (after)
600   /// CHECK:      <<This:l\d+>>     ParameterValue
601   /// CHECK:      <<Param:l\d+>>    ParameterValue
602   /// CHECK:      <<Clazz:l\d+>>    LoadClass
603   /// CHECK:                        CheckCast [<<Param>>,<<Clazz>>]
604   /// CHECK:                        BoundType [<<Param>>] can_be_null:true
605 
606   /// CHECK-START: java.lang.String Main.checkcastPreserveNullCheck(java.lang.Object) instruction_simplifier (after)
607   /// CHECK:      <<This:l\d+>>     ParameterValue
608   /// CHECK:      <<Param:l\d+>>    ParameterValue
609   /// CHECK:      <<Clazz:l\d+>>    LoadClass
610   /// CHECK:                        CheckCast [<<Param>>,<<Clazz>>]
611   /// CHECK:      <<Bound:l\d+>>    BoundType [<<Param>>]
612   /// CHECK:                        NullCheck [<<Bound>>]
checkcastPreserveNullCheck(Object a)613   public String checkcastPreserveNullCheck(Object a) {
614     return ((SubclassA)a).toString();
615   }
616 
617 
618   /// CHECK-START: void Main.argumentCheck(Super, double, SubclassA, Final) builder (after)
619   /// CHECK:      ParameterValue klass:Main can_be_null:false exact:false
620   /// CHECK:      ParameterValue klass:Super can_be_null:true exact:false
621   /// CHECK:      ParameterValue
622   /// CHECK:      ParameterValue klass:SubclassA can_be_null:true exact:false
623   /// CHECK:      ParameterValue klass:Final can_be_null:true exact:true
624   /// CHECK-NOT:  ParameterValue
argumentCheck(Super s, double d, SubclassA a, Final f)625   private void argumentCheck(Super s, double d, SubclassA a, Final f) {
626   }
627 
getNull()628   private Main getNull() {
629     return null;
630   }
631 
632   private int mainField = 0;
633 
634   /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) builder (after)
635   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
636   /// CHECK:                         Return [<<Phi>>]
getWiderType(boolean cond, Interface a, OtherInterface b)637   private SuperInterface getWiderType(boolean cond, Interface a, OtherInterface b) {
638     return cond ? a : b;
639   }
640 
641   /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (before)
642   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:SuperInterface
643   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:SuperInterface exact:false
644   /// CHECK:                         InvokeInterface [<<NullCheck>>]
645 
646   /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (after)
647   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
648   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:SuperInterface exact:false
649   /// CHECK:                         InvokeInterface [<<NullCheck>>]
testInlinerWidensReturnType(boolean cond, Interface a, OtherInterface b)650   private void testInlinerWidensReturnType(boolean cond, Interface a, OtherInterface b) {
651     getWiderType(cond, a, b).superInterfaceMethod();
652   }
653 
654   /// CHECK-START: void Main.testInlinerReturnsNull() inliner (before)
655   /// CHECK:      <<Int:i\d+>>       IntConstant 0
656   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:Main
657   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:Main exact:false
658   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
659 
660   /// CHECK-START: void Main.testInlinerReturnsNull() inliner (after)
661   /// CHECK:      <<Int:i\d+>>       IntConstant 0
662   /// CHECK:      <<Null:l\d+>>      NullConstant klass:java.lang.Object
663   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Null>>] klass:Main exact:false
664   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
testInlinerReturnsNull()665   private void testInlinerReturnsNull() {
666     Main o = getNull();
667     o.mainField = 0;
668   }
669 
670   /// CHECK-START: void Main.testThisArgumentMoreSpecific(boolean) inliner (before)
671   /// CHECK-DAG:     <<Arg:l\d+>>   NewInstance
672   /// CHECK-DAG:                    InvokeVirtual [<<Arg>>,{{z\d+}}] method_name:Super.$inline$h
673 
674   /// CHECK-START: void Main.testThisArgumentMoreSpecific(boolean) inliner (after)
675   /// CHECK-DAG:     <<Arg:l\d+>>   NewInstance
676   /// CHECK-DAG:     <<Null:l\d+>>  NullConstant
677   /// CHECK-DAG:     <<Phi:l\d+>>   Phi [<<Arg>>,<<Null>>] klass:SubclassA
678   /// CHECK-DAG:     <<NCPhi:l\d+>> NullCheck [<<Phi>>]
679   /// CHECK-DAG:                    InvokeVirtual [<<NCPhi>>] method_name:java.lang.Object.hashCode
680 
testThisArgumentMoreSpecific(boolean cond)681   public void testThisArgumentMoreSpecific(boolean cond) {
682     // Inlining method from Super will build it with `this` typed as Super.
683     // Running RTP will sharpen it to SubclassA.
684     SubclassA obj = new SubclassA();
685     ((Super) obj).$inline$h(cond);
686   }
687 
$inline$hashCode(Super obj)688   public static int $inline$hashCode(Super obj) {
689     return obj.hashCode();
690   }
691 
692   /// CHECK-START: void Main.testExplicitArgumentMoreSpecific(SubclassA) inliner (before)
693   /// CHECK-DAG:     <<Arg:l\d+>>   ParameterValue klass:SubclassA
694   // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
695   /// CHECK-DAG:                    InvokeStaticOrDirect [<<Arg>>{{(,[ij]\d+)?}}] method_name:Main.$inline$hashCode
696 
697   /// CHECK-START: void Main.testExplicitArgumentMoreSpecific(SubclassA) inliner (after)
698   /// CHECK-DAG:     <<Arg:l\d+>>   ParameterValue klass:SubclassA
699   /// CHECK-DAG:     <<NCArg:l\d+>> NullCheck [<<Arg>>] klass:SubclassA
700   /// CHECK-DAG:                    InvokeVirtual [<<NCArg>>] method_name:java.lang.Object.hashCode
701 
testExplicitArgumentMoreSpecific(SubclassA obj)702   public static void testExplicitArgumentMoreSpecific(SubclassA obj) {
703     // Inlining a method will build it with reference types from its signature,
704     // here the callee graph is built with Super as the type of its only argument.
705     // Running RTP after its ParameterValue instructions are replaced with actual
706     // arguments will type the inner graph more precisely.
707     $inline$hashCode(obj);
708   }
709 
710   /// CHECK-START: void Main.testPhiHasOnlyNullInputs(boolean) inliner (before)
711   /// CHECK:      <<Int:i\d+>>       IntConstant 0
712   /// CHECK:      <<Phi:l\d+>>       Phi klass:Main exact:false
713   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:Main exact:false
714   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
715 
716   /// CHECK-START: void Main.testPhiHasOnlyNullInputs(boolean) inliner (after)
717   /// CHECK:      <<Int:i\d+>>       IntConstant 0
718   /// CHECK:      <<Null:l\d+>>      NullConstant klass:java.lang.Object
719   /// CHECK:      <<Phi:l\d+>>       Phi [<<Null>>,<<Null>>] klass:java.lang.Object exact:false
720   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:java.lang.Object exact:false
721   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
testPhiHasOnlyNullInputs(boolean cond)722   private void testPhiHasOnlyNullInputs(boolean cond) {
723     Main o = cond ? null : getNull();
724     o.mainField = 0;
725     // getSuper() will force a type propagation after inlining
726     // because returns a more precise type.
727     getSuper();
728   }
729 
730   /// CHECK-START: void Main.testLoopPhiWithNullFirstInput(boolean) builder (after)
731   /// CHECK-DAG:  <<Null:l\d+>>      NullConstant
732   /// CHECK-DAG:  <<Main:l\d+>>      NewInstance klass:Main exact:true
733   /// CHECK-DAG:  <<LoopPhi:l\d+>>   Phi [<<Null>>,<<LoopPhi>>,<<Main>>] klass:Main exact:true
testLoopPhiWithNullFirstInput(boolean cond)734   private void testLoopPhiWithNullFirstInput(boolean cond) {
735     Main a = null;
736     while (a == null) {
737       if (cond) {
738         a = new Main();
739       }
740     }
741   }
742 
743   /// CHECK-START: java.lang.Object[] Main.testInstructionsWithUntypedParent() builder (after)
744   /// CHECK-DAG:  <<Null:l\d+>>      NullConstant
745   /// CHECK-DAG:  <<LoopPhi:l\d+>>   Phi [<<Null>>,<<Phi:l\d+>>] klass:java.lang.Object[] exact:true
746   /// CHECK-DAG:  <<Array:l\d+>>     NewArray klass:java.lang.Object[] exact:true
747   /// CHECK-DAG:  <<Phi>>            Phi [<<Array>>,<<LoopPhi>>] klass:java.lang.Object[] exact:true
748   /// CHECK-DAG:  <<NC:l\d+>>        NullCheck [<<LoopPhi>>] klass:java.lang.Object[] exact:true
749   /// CHECK-DAG:                     ArrayGet [<<NC>>,{{i\d+}}] klass:java.lang.Object exact:false
testInstructionsWithUntypedParent()750   private Object[] testInstructionsWithUntypedParent() {
751     Object[] array = null;
752     boolean cond = true;
753     for (int i = 0; i < 10; ++i) {
754       if (cond) {
755         array = new Object[10];
756         array[0] = new Object();
757         cond = false;
758       } else {
759         array[i] = array[0];
760       }
761     }
762     return array;
763   }
764 
main(String[] args)765   public static void main(String[] args) {
766   }
767 }
768