blob: 360b52c79d8924e8722dfc2bc20197a882c95be0 [file] [log] [blame]
Aart Bika8b8e9b2018-01-09 11:01:02 -08001/*
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 */
20public class Main {
21
22 //
23 // Some "runtime library" methods.
24 //
25
26 static private void doThrow(String par) {
27 throw new Error("you are null: " + par);
28 }
29
30 static private void checkNotNullDirect(Object obj, String par) {
31 if (obj == null)
32 throw new Error("you are null: " + par);
33 }
34
35 static private void checkNotNullSplit(Object obj, String par) {
36 if (obj == null)
37 doThrow(par);
38 }
39
Aart Bik4c563ca2018-01-24 16:34:25 -080040 static private void checkNotNullSplitAlt(Object obj, String par) {
41 if (obj != null)
42 return;
43 doThrow(par);
44 }
45
Aart Bika8b8e9b2018-01-09 11:01:02 -080046 //
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
Tamas Kenez7124f7d2018-06-18 14:59:23 +020054 /// CHECK: <<Tst:z\d+>> Equal
Aart Bika8b8e9b2018-01-09 11:01:02 -080055 /// 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
Tamas Kenez7124f7d2018-06-18 14:59:23 +020064 /// CHECK: <<Tst:z\d+>> Equal
Aart Bika8b8e9b2018-01-09 11:01:02 -080065 /// 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
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
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
Tamas Kenez7124f7d2018-06-18 14:59:23 +0200112 /// CHECK: <<Tst:z\d+>> Equal
Aart Bika8b8e9b2018-01-09 11:01:02 -0800113 /// 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
Tamas Kenez7124f7d2018-06-18 14:59:23 +0200122 /// CHECK: <<Tst:z\d+>> Equal
Aart Bika8b8e9b2018-01-09 11:01:02 -0800123 /// 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
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
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.
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 //
Aart Bik4c563ca2018-01-24 16:34:25 -0800183 // 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
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
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
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 //
Aart Bika8b8e9b2018-01-09 11:01:02 -0800237 // Test driver.
238 //
239
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
Aart Bik4c563ca2018-01-24 16:34:25 -0800296 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
Aart Bika8b8e9b2018-01-09 11:01:02 -0800308 System.out.println("passed");
309 }
310
311 private static void expectEquals(int expected, int result) {
312 if (expected != result) {
313 throw new Error("Expected: " + expected + ", found: " + result);
314 }
315 }
316}