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