• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 /**
18  * Tests for detecting throwing methods for code sinking.
19  */
20 public class Main {
21 
22   //
23   // Some "runtime library" methods.
24   //
25 
doThrow(String par)26   static private void doThrow(String par) {
27     throw new Error("you are null: " + par);
28   }
29 
checkNotNullDirect(Object obj, String par)30   static private void checkNotNullDirect(Object obj, String par) {
31     if (obj == null)
32       throw new Error("you are null: " + par);
33   }
34 
checkNotNullSplit(Object obj, String par)35   static private void checkNotNullSplit(Object obj, String par) {
36     if (obj == null)
37       doThrow(par);
38   }
39 
checkNotNullSplitAlt(Object obj, String par)40   static private void checkNotNullSplitAlt(Object obj, String par) {
41     if (obj != null)
42       return;
43     doThrow(par);
44   }
45 
46   //
47   // Various ways of enforcing non-null parameter.
48   // In all cases, par should be subject to code sinking.
49   //
50 
51   /// CHECK-START: void Main.doit1(int[]) code_sinking (before)
52   /// CHECK: begin_block
53   /// CHECK:   <<Str:l\d+>> LoadString
54   /// CHECK:   <<Tst:z\d+>> NotEqual
55   /// CHECK:                If [<<Tst>>]
56   /// CHECK: end_block
57   /// CHECK: begin_block
58   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
59   /// CHECK:                Throw
60   /// CHECK: end_block
61   //
62   /// CHECK-START: void Main.doit1(int[]) code_sinking (after)
63   /// CHECK: begin_block
64   /// CHECK:   <<Tst:z\d+>> NotEqual
65   /// CHECK:                If [<<Tst>>]
66   /// CHECK: end_block
67   /// CHECK: begin_block
68   /// CHECK:   <<Str:l\d+>> LoadString
69   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
70   /// CHECK:                Throw
71   /// CHECK: end_block
doit1(int[] a)72   static public void doit1(int[] a) {
73     String par = "a";
74     if (a == null)
75       throw new Error("you are null: " + par);
76     for (int i = 0; i < a.length; i++) {
77       a[i] = 1;
78     }
79   }
80 
81   /// CHECK-START: void Main.doit2(int[]) code_sinking (before)
82   /// CHECK: begin_block
83   /// CHECK:   <<Str:l\d+>> LoadString
84   /// CHECK:   <<Tst:z\d+>> NotEqual
85   /// CHECK:                If [<<Tst>>]
86   /// CHECK: end_block
87   /// CHECK: begin_block
88   /// CHECK:                InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
89   /// CHECK: end_block
90   //
91   /// CHECK-START: void Main.doit2(int[]) code_sinking (after)
92   /// CHECK: begin_block
93   /// CHECK:   <<Tst:z\d+>> NotEqual
94   /// CHECK:                If [<<Tst>>]
95   /// CHECK: end_block
96   /// CHECK: begin_block
97   /// CHECK:   <<Str:l\d+>> LoadString
98   /// CHECK:                InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
99   /// CHECK: end_block
doit2(int[] a)100   static public void doit2(int[] a) {
101     String par = "a";
102     if (a == null)
103       doThrow(par);
104     for (int i = 0; i < a.length; i++) {
105       a[i] = 2;
106     }
107   }
108 
109   /// CHECK-START: void Main.doit3(int[]) code_sinking (before)
110   /// CHECK: begin_block
111   /// CHECK:   <<Str:l\d+>> LoadString
112   /// CHECK:   <<Tst:z\d+>> NotEqual
113   /// CHECK:                If [<<Tst>>]
114   /// CHECK: end_block
115   /// CHECK: begin_block
116   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
117   /// CHECK:                Throw
118   /// CHECK: end_block
119   //
120   /// CHECK-START: void Main.doit3(int[]) code_sinking (after)
121   /// CHECK: begin_block
122   /// CHECK:   <<Tst:z\d+>> NotEqual
123   /// CHECK:                If [<<Tst>>]
124   /// CHECK: end_block
125   /// CHECK: begin_block
126   /// CHECK:   <<Str:l\d+>> LoadString
127   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
128   /// CHECK:                Throw
129   /// CHECK: end_block
doit3(int[] a)130   static public void doit3(int[] a) {
131     String par = "a";
132     checkNotNullDirect(a, par);
133     for (int i = 0; i < a.length; i++) {
134       a[i] = 3;
135     }
136   }
137 
138   /// CHECK-START: void Main.doit4(int[]) code_sinking (before)
139   /// CHECK: begin_block
140   /// CHECK:   <<Str:l\d+>> LoadString
141   /// CHECK:   <<Tst:z\d+>> NotEqual
142   /// CHECK:                If [<<Tst>>]
143   /// CHECK: end_block
144   /// CHECK: begin_block
145   /// CHECK:                InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
146   /// CHECK: end_block
147   //
148   /// CHECK-START: void Main.doit4(int[]) code_sinking (after)
149   /// CHECK: begin_block
150   /// CHECK:   <<Tst:z\d+>> NotEqual
151   /// CHECK:                If [<<Tst>>]
152   /// CHECK: end_block
153   /// CHECK: begin_block
154   /// CHECK:   <<Str:l\d+>> LoadString
155   /// CHECK:                InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
156   /// CHECK: end_block
doit4(int[] a)157   static public void doit4(int[] a) {
158     String par = "a";
159     checkNotNullSplit(a, par);  // resembles Kotlin runtime lib
160                                 // (test is lined, doThrow is not)
161     for (int i = 0; i < a.length; i++) {
162       a[i] = 4;
163     }
164   }
165 
166   // Ensures Phi values are merged properly.
doit5(int[] a)167   static public int doit5(int[] a) {
168     int t = 100;
169     String par = "a";
170     if (a == null) {
171       doThrow(par);
172     } else {
173       t = 1000;
174     }
175     for (int i = 0; i < a.length; i++) {
176       a[i] = 5;
177     }
178     // Phi on t, even though doThrow never reaches.
179     return t;
180   }
181 
182   //
183   // Various ways of exploiting non-null parameter.
184   // In all cases, implicit null checks are redundant.
185   //
186 
187   /// CHECK-START: int Main.deleteNullCheck(int[]) dead_code_elimination$after_inlining (before)
188   /// CHECK:   <<Par:l\d+>>   ParameterValue
189   /// CHECK:   <<Zero:i\d+>>  IntConstant 0
190   /// CHECK:   <<Null:l\d+>>  NullCheck [<<Par>>]
191   /// CHECK:   <<Len:i\d+>>   ArrayLength [<<Null>>]
192   /// CHECK:   <<Check:i\d+>> BoundsCheck [<<Zero>>,<<Len>>]
193   /// CHECK:   <<Get:i\d+>>   ArrayGet [<<Null>>,<<Check>>]
194   /// CHECK:                  Return [<<Get>>]
195   //
196   /// CHECK-START: int Main.deleteNullCheck(int[]) dead_code_elimination$after_inlining (after)
197   /// CHECK:   <<Par:l\d+>>   ParameterValue
198   /// CHECK:   <<Zero:i\d+>>  IntConstant 0
199   /// CHECK:   <<BT:l\d+>>    BoundType [<<Par>>]
200   /// CHECK:   <<Len:i\d+>>   ArrayLength [<<BT>>]
201   /// CHECK:   <<Check:i\d+>> BoundsCheck [<<Zero>>,<<Len>>]
202   /// CHECK:   <<Get:i\d+>>   ArrayGet [<<BT>>,<<Check>>]
203   /// CHECK:                  Return [<<Get>>]
204   //
205   /// CHECK-START: int Main.deleteNullCheck(int[]) dead_code_elimination$after_inlining (after)
206   /// CHECK-NOT:              NullCheck
deleteNullCheck(int[] a)207   static public int deleteNullCheck(int[] a) {
208     checkNotNullSplit(a, "a");
209     return a[0];
210   }
211 
212   /// CHECK-START: int Main.deleteNullCheckAlt(int[]) dead_code_elimination$after_inlining (before)
213   /// CHECK:     NullCheck
214   //
215   /// CHECK-START: int Main.deleteNullCheckAlt(int[]) dead_code_elimination$after_inlining (after)
216   /// CHECK-NOT: NullCheck
deleteNullCheckAlt(int[] a)217   static public int deleteNullCheckAlt(int[] a) {
218     checkNotNullSplitAlt(a, "a");
219     return a[0];
220   }
221 
222   /// CHECK-START: int Main.deleteNullChecks3(int[], int[], int[]) dead_code_elimination$after_inlining (before)
223   /// CHECK:     NullCheck
224   /// CHECK:     NullCheck
225   /// CHECK:     NullCheck
226   //
227   /// CHECK-START: int Main.deleteNullChecks3(int[], int[], int[]) dead_code_elimination$after_inlining (after)
228   /// CHECK-NOT: NullCheck
deleteNullChecks3(int[] a, int[] b, int[] c)229   static public int deleteNullChecks3(int[] a, int[] b, int[] c) {
230     checkNotNullSplit(a, "a");
231     checkNotNullSplit(b, "b");
232     checkNotNullSplit(c, "c");
233     return a[0] + b[0] + c[0];
234   }
235 
236   //
237   // Test driver.
238   //
239 
main(String[] args)240   static public void main(String[] args) {
241     int[] a = new int[100];
242     for (int i = 0; i < 100; i++) {
243       a[i] = 0;
244     }
245 
246     try {
247       doit1(null);
248       System.out.println("should not reach this!");
249     } catch (Error e) {
250       doit1(a);
251     }
252     for (int i = 0; i < 100; i++) {
253       expectEquals(1, a[i]);
254     }
255 
256     try {
257       doit2(null);
258       System.out.println("should not reach this!");
259     } catch (Error e) {
260       doit2(a);
261     }
262     for (int i = 0; i < 100; i++) {
263       expectEquals(2, a[i]);
264     }
265 
266     try {
267       doit3(null);
268       System.out.println("should not reach this!");
269     } catch (Error e) {
270       doit3(a);
271     }
272     for (int i = 0; i < 100; i++) {
273       expectEquals(3, a[i]);
274     }
275 
276     try {
277       doit4(null);
278       System.out.println("should not reach this!");
279     } catch (Error e) {
280       doit4(a);
281     }
282     for (int i = 0; i < 100; i++) {
283       expectEquals(4, a[i]);
284     }
285 
286     try {
287       doit5(null);
288       System.out.println("should not reach this!");
289     } catch (Error e) {
290       expectEquals(1000, doit5(a));
291     }
292     for (int i = 0; i < 100; i++) {
293       expectEquals(5, a[i]);
294     }
295 
296     int[] x = { 11 } ;
297     expectEquals(11, deleteNullCheck(x));
298     int[] y = { 55 } ;
299     int[] z = { 22 } ;
300     expectEquals(88, deleteNullChecks3(x, y, z));
301 
302     try {
303       deleteNullCheck(null);
304       System.out.println("should not reach this!");
305     } catch (Error e) {
306     }
307 
308     System.out.println("passed");
309   }
310 
expectEquals(int expected, int result)311   private static void expectEquals(int expected, int result) {
312     if (expected != result) {
313       throw new Error("Expected: " + expected + ", found: " + result);
314     }
315   }
316 }
317