blob: 91c3ec48ab97993777a926188e3b4dc3a095ac89 [file] [log] [blame]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +00001/*
2 * Copyright (C) 2017 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
17public class Main {
18
19 public static void main(String[] args) {
20 testSimpleUse();
21 testTwoUses();
22 testFieldStores(doThrow);
23 testFieldStoreCycle();
24 testArrayStores();
25 testOnlyStoreUses();
26 testNoUse();
27 testPhiInput();
28 testVolatileStore();
29 doThrow = true;
30 try {
31 testInstanceSideEffects();
32 } catch (Error e) {
33 // expected
34 System.out.println(e.getMessage());
35 }
36 try {
37 testStaticSideEffects();
38 } catch (Error e) {
39 // expected
40 System.out.println(e.getMessage());
41 }
42
43 try {
44 testStoreStore(doThrow);
45 } catch (Error e) {
46 // expected
47 System.out.println(e.getMessage());
48 }
49 }
50
51 /// CHECK-START: void Main.testSimpleUse() code_sinking (before)
52 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
Igor Murashkin79d8fa72017-04-18 09:37:23 -070053 /// CHECK: <<New:l\d+>> NewInstance [<<LoadClass>>]
54 /// CHECK: ConstructorFence [<<New>>]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +000055 /// CHECK: If
56 /// CHECK: begin_block
57 /// CHECK: Throw
58
59 /// CHECK-START: void Main.testSimpleUse() code_sinking (after)
60 /// CHECK-NOT: NewInstance
61 /// CHECK: If
62 /// CHECK: begin_block
63 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
64 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
65 /// CHECK-NOT: begin_block
Igor Murashkin79d8fa72017-04-18 09:37:23 -070066 /// CHECK: <<New:l\d+>> NewInstance [<<LoadClass>>]
67 /// CHECK: ConstructorFence [<<New>>]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +000068 /// CHECK-NOT: begin_block
69 /// CHECK: NewInstance [<<Error>>]
70 /// CHECK: Throw
71 public static void testSimpleUse() {
72 Object o = new Object();
73 if (doThrow) {
74 throw new Error(o.toString());
75 }
76 }
77
78 /// CHECK-START: void Main.testTwoUses() code_sinking (before)
79 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
80 /// CHECK: NewInstance [<<LoadClass>>]
81 /// CHECK: If
82 /// CHECK: begin_block
83 /// CHECK: Throw
84
85 /// CHECK-START: void Main.testTwoUses() code_sinking (after)
86 /// CHECK-NOT: NewInstance
87 /// CHECK: If
88 /// CHECK: begin_block
89 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
90 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
91 /// CHECK-NOT: begin_block
92 /// CHECK: NewInstance [<<LoadClass>>]
93 /// CHECK-NOT: begin_block
94 /// CHECK: NewInstance [<<Error>>]
95 /// CHECK: Throw
96 public static void testTwoUses() {
97 Object o = new Object();
98 if (doThrow) {
99 throw new Error(o.toString() + o.toString());
100 }
101 }
102
Alex Light3a73ffb2021-01-25 14:11:05 +0000103 // NB It might seem that we'd move the allocation and ifield-set but those are
104 // already moved into the throw block by a combo of partial-LSE and DCE.
105 // Instead all that is actually moved is the LoadClass. Also note the
106 // LoadClass can only be moved since it refers to the 'Main' class itself,
107 // meaning there's no need for any clinit/actual loading.
108 //
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000109 /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (before)
110 /// CHECK: <<Int42:i\d+>> IntConstant 42
Alex Light3a73ffb2021-01-25 14:11:05 +0000111 /// CHECK: begin_block
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000112 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
Alex Light3a73ffb2021-01-25 14:11:05 +0000113 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
114 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000115 /// CHECK: Throw
116
117 /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (after)
118 /// CHECK: <<Int42:i\d+>> IntConstant 42
119 /// CHECK-NOT: NewInstance
120 /// CHECK: If
121 /// CHECK: begin_block
Nicolas Geoffray18074d22021-09-13 14:07:10 +0100122 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
123 /// CHECK-NOT: begin_block
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000124 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
125 /// CHECK-NOT: begin_block
126 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
127 /// CHECK-NOT: begin_block
128 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
129 /// CHECK-NOT: begin_block
Alex Light3a73ffb2021-01-25 14:11:05 +0000130 /// CHECK: <<Throw:l\d+>> NewInstance [<<Error>>]
131 /// CHECK-NOT: begin_block
132 /// CHECK: Throw [<<Throw>>]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000133 public static void testFieldStores(boolean doThrow) {
134 Main m = new Main();
135 m.intField = 42;
136 if (doThrow) {
137 throw new Error(m.toString());
138 }
139 }
140
141 /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (before)
142 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
143 /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
144 /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
145 /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
146 /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
147 /// CHECK: If
148 /// CHECK: begin_block
149 /// CHECK: Throw
150
151 // TODO(ngeoffray): Handle allocation/store cycles.
152 /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (after)
153 /// CHECK: begin_block
154 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
155 /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
156 /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
157 /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
158 /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
159 /// CHECK: If
160 /// CHECK: begin_block
161 /// CHECK: Throw
162 public static void testFieldStoreCycle() {
163 Main m1 = new Main();
164 Main m2 = new Main();
165 m1.objectField = m2;
166 m2.objectField = m1;
167 if (doThrow) {
168 throw new Error(m1.toString() + m2.toString());
169 }
170 }
171
172 /// CHECK-START: void Main.testArrayStores() code_sinking (before)
173 /// CHECK: <<Int1:i\d+>> IntConstant 1
174 /// CHECK: <<Int0:i\d+>> IntConstant 0
175 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
176 /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>]
177 /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
178 /// CHECK: If
179 /// CHECK: begin_block
180 /// CHECK: Throw
181
182 /// CHECK-START: void Main.testArrayStores() code_sinking (after)
183 /// CHECK: <<Int1:i\d+>> IntConstant 1
184 /// CHECK: <<Int0:i\d+>> IntConstant 0
185 /// CHECK-NOT: NewArray
186 /// CHECK: If
187 /// CHECK: begin_block
188 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
189 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
190 /// CHECK-NOT: begin_block
191 /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>]
192 /// CHECK-NOT: begin_block
193 /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
194 /// CHECK-NOT: begin_block
195 /// CHECK: NewInstance [<<Error>>]
196 /// CHECK: Throw
197 public static void testArrayStores() {
198 Object[] o = new Object[1];
199 o[0] = o;
200 if (doThrow) {
201 throw new Error(o.toString());
202 }
203 }
204
205 // Make sure code sinking does not crash on dead allocations.
206 public static void testOnlyStoreUses() {
207 Main m = new Main();
208 Object[] o = new Object[1]; // dead allocation, should eventually be removed b/35634932.
209 o[0] = m;
210 o = null; // Avoid environment uses for the array allocation.
211 if (doThrow) {
212 throw new Error(m.toString());
213 }
214 }
215
216 // Make sure code sinking does not crash on dead code.
217 public static void testNoUse() {
218 Main m = new Main();
219 boolean load = Main.doLoop; // dead code, not removed because of environment use.
220 // Ensure one environment use for the static field
221 $opt$noinline$foo();
222 load = false;
223 if (doThrow) {
224 throw new Error(m.toString());
225 }
226 }
227
228 // Make sure we can move code only used by a phi.
229 /// CHECK-START: void Main.testPhiInput() code_sinking (before)
230 /// CHECK: <<Null:l\d+>> NullConstant
231 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
232 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
233 /// CHECK: If
234 /// CHECK: begin_block
235 /// CHECK: Phi [<<Null>>,<<NewInstance>>]
236 /// CHECK: Throw
237
238 /// CHECK-START: void Main.testPhiInput() code_sinking (after)
239 /// CHECK: <<Null:l\d+>> NullConstant
240 /// CHECK-NOT: NewInstance
241 /// CHECK: If
242 /// CHECK: begin_block
243 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
244 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
245 /// CHECK: begin_block
246 /// CHECK: Phi [<<Null>>,<<NewInstance>>]
247 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
248 /// CHECK: NewInstance [<<Error>>]
249 /// CHECK: Throw
250 public static void testPhiInput() {
251 Object f = new Object();
252 if (doThrow) {
253 Object o = null;
254 int i = 2;
255 if (doLoop) {
256 o = f;
257 i = 42;
258 }
259 throw new Error(o.toString() + i);
260 }
261 }
262
263 static void $opt$noinline$foo() {}
264
265 // Check that we do not move volatile stores.
266 /// CHECK-START: void Main.testVolatileStore() code_sinking (before)
267 /// CHECK: <<Int42:i\d+>> IntConstant 42
268 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
269 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
270 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
271 /// CHECK: If
272 /// CHECK: begin_block
273 /// CHECK: Throw
274
275 /// CHECK-START: void Main.testVolatileStore() code_sinking (after)
276 /// CHECK: <<Int42:i\d+>> IntConstant 42
277 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
278 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
279 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
280 /// CHECK: If
281 /// CHECK: begin_block
282 /// CHECK: Throw
283 public static void testVolatileStore() {
284 Main m = new Main();
285 m.volatileField = 42;
286 if (doThrow) {
287 throw new Error(m.toString());
288 }
289 }
290
291 public static void testInstanceSideEffects() {
292 int a = mainField.intField;
293 $noinline$changeIntField();
294 if (doThrow) {
295 throw new Error("" + a);
296 }
297 }
298
299 static void $noinline$changeIntField() {
300 mainField.intField = 42;
301 }
302
303 public static void testStaticSideEffects() {
304 Object o = obj;
305 $noinline$changeStaticObjectField();
306 if (doThrow) {
307 throw new Error(o.getClass().toString());
308 }
309 }
310
311 static void $noinline$changeStaticObjectField() {
312 obj = new Main();
313 }
314
315 // Test that we preserve the order of stores.
Alex Light3a73ffb2021-01-25 14:11:05 +0000316 // NB It might seem that we'd move the allocation and ifield-set but those are
317 // already moved into the throw block by a combo of partial-LSE and DCE.
318 // Instead all that is actually moved is the LoadClass. Also note the
319 // LoadClass can only be moved since it refers to the 'Main' class itself,
320 // meaning there's no need for any clinit/actual loading.
321 //
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000322 /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (before)
323 /// CHECK: <<Int42:i\d+>> IntConstant 42
324 /// CHECK: <<Int43:i\d+>> IntConstant 43
325 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
Alex Light3a73ffb2021-01-25 14:11:05 +0000326 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
Alex Light3a73ffb2021-01-25 14:11:05 +0000327 /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
328 /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int43>>]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000329 /// CHECK: Throw
Alex Light3a73ffb2021-01-25 14:11:05 +0000330 /// CHECK-NOT: InstanceFieldSet
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000331
332 /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (after)
333 /// CHECK: <<Int42:i\d+>> IntConstant 42
334 /// CHECK: <<Int43:i\d+>> IntConstant 43
335 /// CHECK-NOT: NewInstance
336 /// CHECK: If
337 /// CHECK: begin_block
Nicolas Geoffray18074d22021-09-13 14:07:10 +0100338 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
339 /// CHECK-NOT: begin_block
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000340 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000341 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
342 /// CHECK-NOT: begin_block
Alex Light3a73ffb2021-01-25 14:11:05 +0000343 /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
344 /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int43>>]
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000345 /// CHECK-NOT: begin_block
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000346 /// CHECK: NewInstance [<<Error>>]
347 /// CHECK: Throw
Alex Light3a73ffb2021-01-25 14:11:05 +0000348 /// CHECK-NOT: InstanceFieldSet
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000349 public static void testStoreStore(boolean doThrow) {
350 Main m = new Main();
351 m.intField = 42;
Mingyao Yanga3540532018-01-25 12:17:28 -0800352 m.intField2 = 43;
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000353 if (doThrow) {
354 throw new Error(m.$opt$noinline$toString());
355 }
356 }
357
Artem Serovd6750532018-05-30 20:07:43 +0100358 static native void doStaticNativeCallLiveVreg();
359
360 // Test ensures that 'o' has been moved into the if despite the InvokeStaticOrDirect.
361 //
362 /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (before)
363 /// CHECK: <<Int1:i\d+>> IntConstant 1
364 /// CHECK: <<Int0:i\d+>> IntConstant 0
365 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
366 /// CHECK-NOT: begin_block
367 /// CHECK: NewArray [<<LoadClass>>,<<Int1>>]
368 /// CHECK: If
369 /// CHECK: begin_block
370 /// CHECK: Throw
371
372 /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (after)
373 /// CHECK: <<Int1:i\d+>> IntConstant 1
374 /// CHECK: <<Int0:i\d+>> IntConstant 0
375 /// CHECK: If
376 /// CHECK: begin_block
377 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
378 /// CHECK: NewArray [<<LoadClass>>,<<Int1>>]
379 /// CHECK: Throw
380 static void testSinkingOverInvoke() {
381 Object[] o = new Object[1];
382 o[0] = o;
383 doStaticNativeCallLiveVreg();
384 if (doThrow) {
385 throw new Error(o.toString());
386 }
387 }
388
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000389 public String $opt$noinline$toString() {
390 return "" + intField;
391 }
392
393 volatile int volatileField;
394 int intField;
Mingyao Yanga3540532018-01-25 12:17:28 -0800395 int intField2;
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000396 Object objectField;
397 static boolean doThrow;
398 static boolean doLoop;
399 static Main mainField = new Main();
400 static Object obj = new Object();
401}