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.testArraySimpleRemove() instruction_simplifier (before)
467   /// CHECK:         CheckCast
468 
469   /// CHECK-START: void Main.testArraySimpleRemove() instruction_simplifier (after)
470   /// CHECK-NOT:     CheckCast
testArraySimpleRemove()471   public void testArraySimpleRemove() {
472     Super[] b = new SubclassA[10];
473     SubclassA[] c = (SubclassA[])b;
474   }
475 
476   /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier (before)
477   /// CHECK:         CheckCast
478 
479   /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier (after)
480   /// CHECK-NOT:     CheckCast
testInvokeSimpleRemove()481   public void testInvokeSimpleRemove() {
482     Super b = $noinline$getSubclass();
483     ((SubclassA)b).$noinline$g();
484   }
485   /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier (before)
486   /// CHECK:         CheckCast
487 
488   /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier (after)
489   /// CHECK-NOT:     CheckCast
testArrayGetSimpleRemove()490   public void testArrayGetSimpleRemove() {
491     Super[] a = new SubclassA[10];
492     ((SubclassA)a[0]).$noinline$g();
493   }
494 
495   /// CHECK-START: int Main.testLoadExceptionInCatchNonExact(int, int) builder (after)
496   /// CHECK:         LoadException klass:java.lang.ArithmeticException can_be_null:false exact:false
testLoadExceptionInCatchNonExact(int x, int y)497   public int testLoadExceptionInCatchNonExact(int x, int y) {
498     try {
499       return x / y;
500     } catch (ArithmeticException ex) {
501       return ex.hashCode();
502     }
503   }
504 
505   /// CHECK-START: int Main.testLoadExceptionInCatchExact(int) builder (after)
506   /// CHECK:         LoadException klass:FinalException can_be_null:false exact:true
testLoadExceptionInCatchExact(int x)507   public int testLoadExceptionInCatchExact(int x) {
508     try {
509       if (x == 42) {
510         throw new FinalException();
511       } else {
512         return x;
513       }
514     } catch (FinalException ex) {
515       return ex.hashCode();
516     }
517   }
518 
519   /// CHECK-START: int Main.testLoadExceptionInCatchAll(int, int) builder (after)
520   /// CHECK:         LoadException klass:java.lang.Throwable can_be_null:false exact:false
testLoadExceptionInCatchAll(int x, int y)521   public int testLoadExceptionInCatchAll(int x, int y) {
522     try {
523       x = x / y;
524     } finally {
525       return x;
526     }
527   }
528 
529   private Generic<SubclassC> genericC = new Generic<SubclassC>();
530   private Generic<Final> genericFinal = new Generic<Final>();
531 
get()532   private SubclassC get() {
533     return genericC.get();
534   }
535 
getFinal()536   private Final getFinal() {
537     return genericFinal.get();
538   }
539 
540   /// CHECK-START: SubclassC Main.inlineGenerics() builder (after)
541   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:SubclassC exact:false
542   /// CHECK-NEXT:                    Return [<<Invoke>>]
543 
544   /// CHECK-START: SubclassC Main.inlineGenerics() inliner (after)
545   /// CHECK:      <<BoundType:l\d+>> BoundType klass:SubclassC exact:false
546   /// CHECK:                         Return [<<BoundType>>]
inlineGenerics()547   private SubclassC inlineGenerics() {
548     SubclassC c = get();
549     return c;
550   }
551 
552   /// CHECK-START: Final Main.inlineGenericsFinal() builder (after)
553   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:Final exact:true
554   /// CHECK-NEXT:                    Return [<<Invoke>>]
555 
556   /// CHECK-START: Final Main.inlineGenericsFinal() inliner (after)
557   /// CHECK:      <<BoundType:l\d+>> BoundType klass:Final exact:true
558   /// CHECK:                         Return [<<BoundType>>]
inlineGenericsFinal()559   private Final inlineGenericsFinal() {
560     Final f = getFinal();
561     return f;
562   }
563 
564   /// CHECK-START: void Main.boundOnlyOnceIfNotNull(java.lang.Object) inliner (after)
565   /// CHECK:      BoundType
566   /// CHECK-NOT:  BoundType
boundOnlyOnceIfNotNull(Object o)567   private void boundOnlyOnceIfNotNull(Object o) {
568     if (o != null) {
569       o.toString();
570     }
571   }
572 
573   /// CHECK-START: void Main.boundOnlyOnceIfInstanceOf(java.lang.Object) inliner (after)
574   /// CHECK:      BoundType
575   /// CHECK-NOT:  BoundType
boundOnlyOnceIfInstanceOf(Object o)576   private void boundOnlyOnceIfInstanceOf(Object o) {
577     if (o instanceof Main) {
578       o.toString();
579     }
580   }
581 
582   /// CHECK-START: Final Main.boundOnlyOnceCheckCast(Generic) inliner (after)
583   /// CHECK:      BoundType
584   /// CHECK-NOT:  BoundType
boundOnlyOnceCheckCast(Generic<Final> o)585   private Final boundOnlyOnceCheckCast(Generic<Final> o) {
586     Final f = o.get();
587     return f;
588   }
589 
getSuper()590   private Super getSuper() {
591     return new SubclassA();
592   }
593 
594   /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) builder (after)
595   /// CHECK:      <<Phi:l\d+>> Phi klass:Super
596   /// CHECK:                   NullCheck [<<Phi>>] klass:Super
597 
598   /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) inliner (after)
599   /// CHECK:      <<Phi:l\d+>> Phi klass:SubclassA
600   /// CHECK:                   NullCheck [<<Phi>>] klass:SubclassA
updateNodesInTheSameBlockAsPhi(boolean cond)601   private void updateNodesInTheSameBlockAsPhi(boolean cond) {
602     Super s = getSuper();
603     if (cond) {
604       s = new SubclassA();
605     }
606     s.$noinline$f();
607   }
608 
609   /// CHECK-START: java.lang.String Main.checkcastPreserveNullCheck(java.lang.Object) inliner (after)
610   /// CHECK:      <<This:l\d+>>     ParameterValue
611   /// CHECK:      <<Param:l\d+>>    ParameterValue
612   /// CHECK:      <<Clazz:l\d+>>    LoadClass
613   /// CHECK:                        CheckCast [<<Param>>,<<Clazz>>]
614   /// CHECK:                        BoundType [<<Param>>] can_be_null:true
615 
616   /// CHECK-START: java.lang.String Main.checkcastPreserveNullCheck(java.lang.Object) instruction_simplifier (after)
617   /// CHECK:      <<This:l\d+>>     ParameterValue
618   /// CHECK:      <<Param:l\d+>>    ParameterValue
619   /// CHECK:      <<Clazz:l\d+>>    LoadClass
620   /// CHECK:                        CheckCast [<<Param>>,<<Clazz>>]
621   /// CHECK:      <<Bound:l\d+>>    BoundType [<<Param>>]
622   /// CHECK:                        NullCheck [<<Bound>>]
checkcastPreserveNullCheck(Object a)623   public String checkcastPreserveNullCheck(Object a) {
624     return ((SubclassA)a).toString();
625   }
626 
627 
628   /// CHECK-START: void Main.argumentCheck(Super, double, SubclassA, Final) builder (after)
629   /// CHECK:      ParameterValue klass:Main can_be_null:false exact:false
630   /// CHECK:      ParameterValue klass:Super can_be_null:true exact:false
631   /// CHECK:      ParameterValue
632   /// CHECK:      ParameterValue klass:SubclassA can_be_null:true exact:false
633   /// CHECK:      ParameterValue klass:Final can_be_null:true exact:true
634   /// CHECK-NOT:  ParameterValue
argumentCheck(Super s, double d, SubclassA a, Final f)635   private void argumentCheck(Super s, double d, SubclassA a, Final f) {
636   }
637 
getNull()638   private Main getNull() {
639     return null;
640   }
641 
642   private int mainField = 0;
643 
644   /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) builder (after)
645   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
646   /// CHECK:                         Return [<<Phi>>]
getWiderType(boolean cond, Interface a, OtherInterface b)647   private SuperInterface getWiderType(boolean cond, Interface a, OtherInterface b) {
648     return cond ? a : b;
649   }
650 
651   /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (before)
652   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:SuperInterface
653   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:SuperInterface exact:false
654   /// CHECK:                         InvokeInterface [<<NullCheck>>]
655 
656   /// CHECK-START: void Main.testInlinerWidensReturnType(boolean, Interface, OtherInterface) inliner (after)
657   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
658   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:SuperInterface exact:false
659   /// CHECK:                         InvokeInterface [<<NullCheck>>]
testInlinerWidensReturnType(boolean cond, Interface a, OtherInterface b)660   private void testInlinerWidensReturnType(boolean cond, Interface a, OtherInterface b) {
661     getWiderType(cond, a, b).superInterfaceMethod();
662   }
663 
664   /// CHECK-START: void Main.testInlinerReturnsNull() inliner (before)
665   /// CHECK:      <<Int:i\d+>>       IntConstant 0
666   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:Main
667   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Invoke>>] klass:Main exact:false
668   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
669 
670   /// CHECK-START: void Main.testInlinerReturnsNull() inliner (after)
671   /// CHECK:      <<Int:i\d+>>       IntConstant 0
672   /// CHECK:      <<Null:l\d+>>      NullConstant klass:java.lang.Object
673   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Null>>] klass:Main exact:false
674   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
testInlinerReturnsNull()675   private void testInlinerReturnsNull() {
676     Main o = getNull();
677     o.mainField = 0;
678   }
679 
680   /// CHECK-START: void Main.testThisArgumentMoreSpecific(boolean) inliner (before)
681   /// CHECK-DAG:     <<Arg:l\d+>>   NewInstance
682   /// CHECK-DAG:                    InvokeVirtual [<<Arg>>,{{z\d+}}] method_name:Super.$inline$h
683 
684   /// CHECK-START: void Main.testThisArgumentMoreSpecific(boolean) inliner (after)
685   /// CHECK-DAG:     <<Arg:l\d+>>   NewInstance
686   /// CHECK-DAG:     <<Null:l\d+>>  NullConstant
687   /// CHECK-DAG:     <<Phi:l\d+>>   Phi [<<Arg>>,<<Null>>] klass:SubclassA
688   /// CHECK-DAG:     <<NCPhi:l\d+>> NullCheck [<<Phi>>]
689   /// CHECK-DAG:                    InvokeVirtual [<<NCPhi>>] method_name:java.lang.Object.hashCode
690 
testThisArgumentMoreSpecific(boolean cond)691   public void testThisArgumentMoreSpecific(boolean cond) {
692     // Inlining method from Super will build it with `this` typed as Super.
693     // Running RTP will sharpen it to SubclassA.
694     SubclassA obj = new SubclassA();
695     ((Super) obj).$inline$h(cond);
696   }
697 
$inline$hashCode(Super obj)698   public static int $inline$hashCode(Super obj) {
699     return obj.hashCode();
700   }
701 
702   /// CHECK-START: void Main.testExplicitArgumentMoreSpecific(SubclassA) inliner (before)
703   /// CHECK-DAG:     <<Arg:l\d+>>   ParameterValue klass:SubclassA
704   // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
705   /// CHECK-DAG:                    InvokeStaticOrDirect [<<Arg>>{{(,[ij]\d+)?}}] method_name:Main.$inline$hashCode
706 
707   /// CHECK-START: void Main.testExplicitArgumentMoreSpecific(SubclassA) inliner (after)
708   /// CHECK-DAG:     <<Arg:l\d+>>   ParameterValue klass:SubclassA
709   /// CHECK-DAG:     <<NCArg:l\d+>> NullCheck [<<Arg>>] klass:SubclassA
710   /// CHECK-DAG:                    InvokeVirtual [<<NCArg>>] method_name:java.lang.Object.hashCode
711 
testExplicitArgumentMoreSpecific(SubclassA obj)712   public static void testExplicitArgumentMoreSpecific(SubclassA obj) {
713     // Inlining a method will build it with reference types from its signature,
714     // here the callee graph is built with Super as the type of its only argument.
715     // Running RTP after its ParameterValue instructions are replaced with actual
716     // arguments will type the inner graph more precisely.
717     $inline$hashCode(obj);
718   }
719 
720   /// CHECK-START: void Main.testPhiHasOnlyNullInputs(boolean) inliner (before)
721   /// CHECK:      <<Int:i\d+>>       IntConstant 0
722   /// CHECK:      <<Phi:l\d+>>       Phi klass:Main exact:false
723   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:Main exact:false
724   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
725 
726   /// CHECK-START: void Main.testPhiHasOnlyNullInputs(boolean) inliner (after)
727   /// CHECK:      <<Int:i\d+>>       IntConstant 0
728   /// CHECK:      <<Null:l\d+>>      NullConstant klass:java.lang.Object
729   /// CHECK:      <<Phi:l\d+>>       Phi [<<Null>>,<<Null>>] klass:java.lang.Object exact:false
730   /// CHECK:      <<NullCheck:l\d+>> NullCheck [<<Phi>>] klass:java.lang.Object exact:false
731   /// CHECK:                         InstanceFieldSet [<<NullCheck>>,<<Int>>]
testPhiHasOnlyNullInputs(boolean cond)732   private void testPhiHasOnlyNullInputs(boolean cond) {
733     Main o = cond ? null : getNull();
734     o.mainField = 0;
735     // getSuper() will force a type propagation after inlining
736     // because returns a more precise type.
737     getSuper();
738   }
739 
740   /// CHECK-START: void Main.testLoopPhiWithNullFirstInput(boolean) builder (after)
741   /// CHECK-DAG:  <<Null:l\d+>>      NullConstant
742   /// CHECK-DAG:  <<Main:l\d+>>      NewInstance klass:Main exact:true
743   /// CHECK-DAG:  <<LoopPhi:l\d+>>   Phi [<<Null>>,<<LoopPhi>>,<<Main>>] klass:Main exact:true
testLoopPhiWithNullFirstInput(boolean cond)744   private void testLoopPhiWithNullFirstInput(boolean cond) {
745     Main a = null;
746     while (a == null) {
747       if (cond) {
748         a = new Main();
749       }
750     }
751   }
752 
753   /// CHECK-START: java.lang.Object[] Main.testInstructionsWithUntypedParent() builder (after)
754   /// CHECK-DAG:  <<Null:l\d+>>      NullConstant
755   /// CHECK-DAG:  <<LoopPhi:l\d+>>   Phi [<<Null>>,<<Phi:l\d+>>] klass:java.lang.Object[] exact:true
756   /// CHECK-DAG:  <<Array:l\d+>>     NewArray klass:java.lang.Object[] exact:true
757   /// CHECK-DAG:  <<Phi>>            Phi [<<Array>>,<<LoopPhi>>] klass:java.lang.Object[] exact:true
758   /// CHECK-DAG:  <<NC:l\d+>>        NullCheck [<<LoopPhi>>] klass:java.lang.Object[] exact:true
759   /// CHECK-DAG:                     ArrayGet [<<NC>>,{{i\d+}}] klass:java.lang.Object exact:false
testInstructionsWithUntypedParent()760   private Object[] testInstructionsWithUntypedParent() {
761     Object[] array = null;
762     boolean cond = true;
763     for (int i = 0; i < 10; ++i) {
764       if (cond) {
765         array = new Object[10];
766         array[0] = new Object();
767         cond = false;
768       } else {
769         array[i] = array[0];
770       }
771     }
772     return array;
773   }
774 
main(String[] args)775   public static void main(String[] args) {
776   }
777 }
778