blob: c2344b23e86579b63c95749e1e822e02d107f6ee [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) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +010073 // Being in the boot image means we know the load string cannot throw. Create one that is
74 // unlikely to be there to ensure we handle that case.
75 String par = "stringUnlikelyToBeInBootImage";
Aart Bika8b8e9b2018-01-09 11:01:02 -080076 if (a == null)
77 throw new Error("you are null: " + par);
78 for (int i = 0; i < a.length; i++) {
79 a[i] = 1;
80 }
81 }
82
83 /// CHECK-START: void Main.doit2(int[]) code_sinking (before)
84 /// CHECK: begin_block
85 /// CHECK: <<Str:l\d+>> LoadString
86 /// CHECK: <<Tst:z\d+>> NotEqual
87 /// CHECK: If [<<Tst>>]
88 /// CHECK: end_block
89 /// CHECK: begin_block
90 /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
91 /// CHECK: end_block
92 //
93 /// CHECK-START: void Main.doit2(int[]) code_sinking (after)
94 /// CHECK: begin_block
95 /// CHECK: <<Tst:z\d+>> NotEqual
96 /// CHECK: If [<<Tst>>]
97 /// CHECK: end_block
98 /// CHECK: begin_block
99 /// CHECK: <<Str:l\d+>> LoadString
100 /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
101 /// CHECK: end_block
102 static public void doit2(int[] a) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100103 // Being in the boot image means we know the load string cannot throw. Create one that is
104 // unlikely to be there to ensure we handle that case.
105 String par = "stringUnlikelyToBeInBootImage";
Aart Bika8b8e9b2018-01-09 11:01:02 -0800106 if (a == null)
107 doThrow(par);
108 for (int i = 0; i < a.length; i++) {
109 a[i] = 2;
110 }
111 }
112
113 /// CHECK-START: void Main.doit3(int[]) code_sinking (before)
114 /// CHECK: begin_block
115 /// CHECK: <<Str:l\d+>> LoadString
Tamas Kenez7124f7d2018-06-18 14:59:23 +0200116 /// CHECK: <<Tst:z\d+>> Equal
Aart Bika8b8e9b2018-01-09 11:01:02 -0800117 /// CHECK: If [<<Tst>>]
118 /// CHECK: end_block
119 /// CHECK: begin_block
120 /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
121 /// CHECK: Throw
122 /// CHECK: end_block
123 //
124 /// CHECK-START: void Main.doit3(int[]) code_sinking (after)
125 /// CHECK: begin_block
Tamas Kenez7124f7d2018-06-18 14:59:23 +0200126 /// CHECK: <<Tst:z\d+>> Equal
Aart Bika8b8e9b2018-01-09 11:01:02 -0800127 /// CHECK: If [<<Tst>>]
128 /// CHECK: end_block
129 /// CHECK: begin_block
130 /// CHECK: <<Str:l\d+>> LoadString
131 /// CHECK: InvokeVirtual [{{l\d+}},<<Str>>]
132 /// CHECK: Throw
133 /// CHECK: end_block
134 static public void doit3(int[] a) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100135 // Being in the boot image means we know the load string cannot throw. Create one that is
136 // unlikely to be there to ensure we handle that case.
137 String par = "stringUnlikelyToBeInBootImage";
Aart Bika8b8e9b2018-01-09 11:01:02 -0800138 checkNotNullDirect(a, par);
139 for (int i = 0; i < a.length; i++) {
140 a[i] = 3;
141 }
142 }
143
144 /// CHECK-START: void Main.doit4(int[]) code_sinking (before)
145 /// CHECK: begin_block
146 /// CHECK: <<Str:l\d+>> LoadString
147 /// CHECK: <<Tst:z\d+>> NotEqual
148 /// CHECK: If [<<Tst>>]
149 /// CHECK: end_block
150 /// CHECK: begin_block
151 /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
152 /// CHECK: end_block
153 //
154 /// CHECK-START: void Main.doit4(int[]) code_sinking (after)
155 /// CHECK: begin_block
156 /// CHECK: <<Tst:z\d+>> NotEqual
157 /// CHECK: If [<<Tst>>]
158 /// CHECK: end_block
159 /// CHECK: begin_block
160 /// CHECK: <<Str:l\d+>> LoadString
161 /// CHECK: InvokeStaticOrDirect [<<Str>>] method_name:Main.doThrow
162 /// CHECK: end_block
163 static public void doit4(int[] a) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100164 // Being in the boot image means we know the load string cannot throw. Create one that is
165 // unlikely to be there to ensure we handle that case.
166 String par = "stringUnlikelyToBeInBootImage";
Aart Bika8b8e9b2018-01-09 11:01:02 -0800167 checkNotNullSplit(a, par); // resembles Kotlin runtime lib
168 // (test is lined, doThrow is not)
169 for (int i = 0; i < a.length; i++) {
170 a[i] = 4;
171 }
172 }
173
174 // Ensures Phi values are merged properly.
175 static public int doit5(int[] a) {
176 int t = 100;
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100177 // Being in the boot image means we know the load string cannot throw. Create one that is
178 // unlikely to be there to ensure we handle that case.
179 String par = "stringUnlikelyToBeInBootImage";
Aart Bika8b8e9b2018-01-09 11:01:02 -0800180 if (a == null) {
181 doThrow(par);
182 } else {
183 t = 1000;
184 }
185 for (int i = 0; i < a.length; i++) {
186 a[i] = 5;
187 }
188 // Phi on t, even though doThrow never reaches.
189 return t;
190 }
191
192 //
Aart Bik4c563ca2018-01-24 16:34:25 -0800193 // Various ways of exploiting non-null parameter.
194 // In all cases, implicit null checks are redundant.
195 //
196
197 /// CHECK-START: int Main.deleteNullCheck(int[]) dead_code_elimination$after_inlining (before)
198 /// CHECK: <<Par:l\d+>> ParameterValue
199 /// CHECK: <<Zero:i\d+>> IntConstant 0
200 /// CHECK: <<Null:l\d+>> NullCheck [<<Par>>]
201 /// CHECK: <<Len:i\d+>> ArrayLength [<<Null>>]
202 /// CHECK: <<Check:i\d+>> BoundsCheck [<<Zero>>,<<Len>>]
203 /// CHECK: <<Get:i\d+>> ArrayGet [<<Null>>,<<Check>>]
204 /// CHECK: Return [<<Get>>]
205 //
206 /// CHECK-START: int Main.deleteNullCheck(int[]) dead_code_elimination$after_inlining (after)
207 /// CHECK: <<Par:l\d+>> ParameterValue
208 /// CHECK: <<Zero:i\d+>> IntConstant 0
209 /// CHECK: <<BT:l\d+>> BoundType [<<Par>>]
210 /// CHECK: <<Len:i\d+>> ArrayLength [<<BT>>]
211 /// CHECK: <<Check:i\d+>> BoundsCheck [<<Zero>>,<<Len>>]
212 /// CHECK: <<Get:i\d+>> ArrayGet [<<BT>>,<<Check>>]
213 /// CHECK: Return [<<Get>>]
214 //
215 /// CHECK-START: int Main.deleteNullCheck(int[]) dead_code_elimination$after_inlining (after)
216 /// CHECK-NOT: NullCheck
217 static public int deleteNullCheck(int[] a) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100218 checkNotNullSplit(a, "stringUnlikelyToBeInBootImage");
Aart Bik4c563ca2018-01-24 16:34:25 -0800219 return a[0];
220 }
221
222 /// CHECK-START: int Main.deleteNullCheckAlt(int[]) dead_code_elimination$after_inlining (before)
223 /// CHECK: NullCheck
224 //
225 /// CHECK-START: int Main.deleteNullCheckAlt(int[]) dead_code_elimination$after_inlining (after)
226 /// CHECK-NOT: NullCheck
227 static public int deleteNullCheckAlt(int[] a) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100228 checkNotNullSplitAlt(a, "stringUnlikeltyToBeInBootImage");
Aart Bik4c563ca2018-01-24 16:34:25 -0800229 return a[0];
230 }
231
232 /// CHECK-START: int Main.deleteNullChecks3(int[], int[], int[]) dead_code_elimination$after_inlining (before)
233 /// CHECK: NullCheck
234 /// CHECK: NullCheck
235 /// CHECK: NullCheck
236 //
237 /// CHECK-START: int Main.deleteNullChecks3(int[], int[], int[]) dead_code_elimination$after_inlining (after)
238 /// CHECK-NOT: NullCheck
239 static public int deleteNullChecks3(int[] a, int[] b, int[] c) {
Nicolas Geoffray33c091e2020-05-14 14:51:11 +0100240 checkNotNullSplit(a, "stringUnlikelytoBeInBootImage1");
241 checkNotNullSplit(b, "stringUnlikelytoBeInBootImage2");
242 checkNotNullSplit(c, "stringUnlikelytoBeInBootImage3");
Aart Bik4c563ca2018-01-24 16:34:25 -0800243 return a[0] + b[0] + c[0];
244 }
245
246 //
Aart Bika8b8e9b2018-01-09 11:01:02 -0800247 // Test driver.
248 //
249
250 static public void main(String[] args) {
251 int[] a = new int[100];
252 for (int i = 0; i < 100; i++) {
253 a[i] = 0;
254 }
255
256 try {
257 doit1(null);
258 System.out.println("should not reach this!");
259 } catch (Error e) {
260 doit1(a);
261 }
262 for (int i = 0; i < 100; i++) {
263 expectEquals(1, a[i]);
264 }
265
266 try {
267 doit2(null);
268 System.out.println("should not reach this!");
269 } catch (Error e) {
270 doit2(a);
271 }
272 for (int i = 0; i < 100; i++) {
273 expectEquals(2, a[i]);
274 }
275
276 try {
277 doit3(null);
278 System.out.println("should not reach this!");
279 } catch (Error e) {
280 doit3(a);
281 }
282 for (int i = 0; i < 100; i++) {
283 expectEquals(3, a[i]);
284 }
285
286 try {
287 doit4(null);
288 System.out.println("should not reach this!");
289 } catch (Error e) {
290 doit4(a);
291 }
292 for (int i = 0; i < 100; i++) {
293 expectEquals(4, a[i]);
294 }
295
296 try {
297 doit5(null);
298 System.out.println("should not reach this!");
299 } catch (Error e) {
300 expectEquals(1000, doit5(a));
301 }
302 for (int i = 0; i < 100; i++) {
303 expectEquals(5, a[i]);
304 }
305
Aart Bik4c563ca2018-01-24 16:34:25 -0800306 int[] x = { 11 } ;
307 expectEquals(11, deleteNullCheck(x));
308 int[] y = { 55 } ;
309 int[] z = { 22 } ;
310 expectEquals(88, deleteNullChecks3(x, y, z));
311
312 try {
313 deleteNullCheck(null);
314 System.out.println("should not reach this!");
315 } catch (Error e) {
316 }
317
Aart Bika8b8e9b2018-01-09 11:01:02 -0800318 System.out.println("passed");
319 }
320
321 private static void expectEquals(int expected, int result) {
322 if (expected != result) {
323 throw new Error("Expected: " + expected + ", found: " + result);
324 }
325 }
326}