blob: 8efac92c34a244217a5657b14207649757c8fd5a [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
103 /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (before)
104 /// CHECK: <<Int42:i\d+>> IntConstant 42
105 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
106 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
107 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
108 /// CHECK: If
109 /// CHECK: begin_block
110 /// CHECK: Throw
111
112 /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (after)
113 /// CHECK: <<Int42:i\d+>> IntConstant 42
114 /// CHECK-NOT: NewInstance
115 /// CHECK: If
116 /// CHECK: begin_block
117 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
118 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
119 /// CHECK-NOT: begin_block
120 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
121 /// CHECK-NOT: begin_block
122 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
123 /// CHECK-NOT: begin_block
124 /// CHECK: NewInstance [<<Error>>]
125 /// CHECK: Throw
126 public static void testFieldStores(boolean doThrow) {
127 Main m = new Main();
128 m.intField = 42;
129 if (doThrow) {
130 throw new Error(m.toString());
131 }
132 }
133
134 /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (before)
135 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
136 /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
137 /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
138 /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
139 /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
140 /// CHECK: If
141 /// CHECK: begin_block
142 /// CHECK: Throw
143
144 // TODO(ngeoffray): Handle allocation/store cycles.
145 /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (after)
146 /// CHECK: begin_block
147 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
148 /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
149 /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
150 /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
151 /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
152 /// CHECK: If
153 /// CHECK: begin_block
154 /// CHECK: Throw
155 public static void testFieldStoreCycle() {
156 Main m1 = new Main();
157 Main m2 = new Main();
158 m1.objectField = m2;
159 m2.objectField = m1;
160 if (doThrow) {
161 throw new Error(m1.toString() + m2.toString());
162 }
163 }
164
165 /// CHECK-START: void Main.testArrayStores() code_sinking (before)
166 /// CHECK: <<Int1:i\d+>> IntConstant 1
167 /// CHECK: <<Int0:i\d+>> IntConstant 0
168 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
169 /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>]
170 /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
171 /// CHECK: If
172 /// CHECK: begin_block
173 /// CHECK: Throw
174
175 /// CHECK-START: void Main.testArrayStores() code_sinking (after)
176 /// CHECK: <<Int1:i\d+>> IntConstant 1
177 /// CHECK: <<Int0:i\d+>> IntConstant 0
178 /// CHECK-NOT: NewArray
179 /// CHECK: If
180 /// CHECK: begin_block
181 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
182 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
183 /// CHECK-NOT: begin_block
184 /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>]
185 /// CHECK-NOT: begin_block
186 /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
187 /// CHECK-NOT: begin_block
188 /// CHECK: NewInstance [<<Error>>]
189 /// CHECK: Throw
190 public static void testArrayStores() {
191 Object[] o = new Object[1];
192 o[0] = o;
193 if (doThrow) {
194 throw new Error(o.toString());
195 }
196 }
197
198 // Make sure code sinking does not crash on dead allocations.
199 public static void testOnlyStoreUses() {
200 Main m = new Main();
201 Object[] o = new Object[1]; // dead allocation, should eventually be removed b/35634932.
202 o[0] = m;
203 o = null; // Avoid environment uses for the array allocation.
204 if (doThrow) {
205 throw new Error(m.toString());
206 }
207 }
208
209 // Make sure code sinking does not crash on dead code.
210 public static void testNoUse() {
211 Main m = new Main();
212 boolean load = Main.doLoop; // dead code, not removed because of environment use.
213 // Ensure one environment use for the static field
214 $opt$noinline$foo();
215 load = false;
216 if (doThrow) {
217 throw new Error(m.toString());
218 }
219 }
220
221 // Make sure we can move code only used by a phi.
222 /// CHECK-START: void Main.testPhiInput() code_sinking (before)
223 /// CHECK: <<Null:l\d+>> NullConstant
224 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
225 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
226 /// CHECK: If
227 /// CHECK: begin_block
228 /// CHECK: Phi [<<Null>>,<<NewInstance>>]
229 /// CHECK: Throw
230
231 /// CHECK-START: void Main.testPhiInput() code_sinking (after)
232 /// CHECK: <<Null:l\d+>> NullConstant
233 /// CHECK-NOT: NewInstance
234 /// CHECK: If
235 /// CHECK: begin_block
236 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
237 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
238 /// CHECK: begin_block
239 /// CHECK: Phi [<<Null>>,<<NewInstance>>]
240 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
241 /// CHECK: NewInstance [<<Error>>]
242 /// CHECK: Throw
243 public static void testPhiInput() {
244 Object f = new Object();
245 if (doThrow) {
246 Object o = null;
247 int i = 2;
248 if (doLoop) {
249 o = f;
250 i = 42;
251 }
252 throw new Error(o.toString() + i);
253 }
254 }
255
256 static void $opt$noinline$foo() {}
257
258 // Check that we do not move volatile stores.
259 /// CHECK-START: void Main.testVolatileStore() code_sinking (before)
260 /// CHECK: <<Int42:i\d+>> IntConstant 42
261 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
262 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
263 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
264 /// CHECK: If
265 /// CHECK: begin_block
266 /// CHECK: Throw
267
268 /// CHECK-START: void Main.testVolatileStore() code_sinking (after)
269 /// CHECK: <<Int42:i\d+>> IntConstant 42
270 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
271 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
272 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
273 /// CHECK: If
274 /// CHECK: begin_block
275 /// CHECK: Throw
276 public static void testVolatileStore() {
277 Main m = new Main();
278 m.volatileField = 42;
279 if (doThrow) {
280 throw new Error(m.toString());
281 }
282 }
283
284 public static void testInstanceSideEffects() {
285 int a = mainField.intField;
286 $noinline$changeIntField();
287 if (doThrow) {
288 throw new Error("" + a);
289 }
290 }
291
292 static void $noinline$changeIntField() {
293 mainField.intField = 42;
294 }
295
296 public static void testStaticSideEffects() {
297 Object o = obj;
298 $noinline$changeStaticObjectField();
299 if (doThrow) {
300 throw new Error(o.getClass().toString());
301 }
302 }
303
304 static void $noinline$changeStaticObjectField() {
305 obj = new Main();
306 }
307
308 // Test that we preserve the order of stores.
309 /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (before)
310 /// CHECK: <<Int42:i\d+>> IntConstant 42
311 /// CHECK: <<Int43:i\d+>> IntConstant 43
312 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
313 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
314 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
315 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int43>>]
316 /// CHECK: If
317 /// CHECK: begin_block
318 /// CHECK: Throw
319
320 /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (after)
321 /// CHECK: <<Int42:i\d+>> IntConstant 42
322 /// CHECK: <<Int43:i\d+>> IntConstant 43
323 /// CHECK-NOT: NewInstance
324 /// CHECK: If
325 /// CHECK: begin_block
326 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
327 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
328 /// CHECK-NOT: begin_block
329 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
330 /// CHECK-NOT: begin_block
331 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
332 /// CHECK-NOT: begin_block
333 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int43>>]
334 /// CHECK-NOT: begin_block
335 /// CHECK: NewInstance [<<Error>>]
336 /// CHECK: Throw
337 public static void testStoreStore(boolean doThrow) {
338 Main m = new Main();
339 m.intField = 42;
Mingyao Yanga3540532018-01-25 12:17:28 -0800340 m.intField2 = 43;
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000341 if (doThrow) {
342 throw new Error(m.$opt$noinline$toString());
343 }
344 }
345
Artem Serovd6750532018-05-30 20:07:43 +0100346 static native void doStaticNativeCallLiveVreg();
347
348 // Test ensures that 'o' has been moved into the if despite the InvokeStaticOrDirect.
349 //
350 /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (before)
351 /// CHECK: <<Int1:i\d+>> IntConstant 1
352 /// CHECK: <<Int0:i\d+>> IntConstant 0
353 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
354 /// CHECK-NOT: begin_block
355 /// CHECK: NewArray [<<LoadClass>>,<<Int1>>]
356 /// CHECK: If
357 /// CHECK: begin_block
358 /// CHECK: Throw
359
360 /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (after)
361 /// CHECK: <<Int1:i\d+>> IntConstant 1
362 /// CHECK: <<Int0:i\d+>> IntConstant 0
363 /// CHECK: If
364 /// CHECK: begin_block
365 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
366 /// CHECK: NewArray [<<LoadClass>>,<<Int1>>]
367 /// CHECK: Throw
368 static void testSinkingOverInvoke() {
369 Object[] o = new Object[1];
370 o[0] = o;
371 doStaticNativeCallLiveVreg();
372 if (doThrow) {
373 throw new Error(o.toString());
374 }
375 }
376
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000377 public String $opt$noinline$toString() {
378 return "" + intField;
379 }
380
381 volatile int volatileField;
382 int intField;
Mingyao Yanga3540532018-01-25 12:17:28 -0800383 int intField2;
Nicolas Geoffrayb813ca12017-02-16 22:08:29 +0000384 Object objectField;
385 static boolean doThrow;
386 static boolean doLoop;
387 static Main mainField = new Main();
388 static Object obj = new Object();
389}