blob: 1da19b687c7aa0f4683ee2fdef317aedf54309d7 [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
53 /// CHECK: NewInstance [<<LoadClass>>]
54 /// CHECK: If
55 /// CHECK: begin_block
56 /// CHECK: Throw
57
58 /// CHECK-START: void Main.testSimpleUse() code_sinking (after)
59 /// CHECK-NOT: NewInstance
60 /// CHECK: If
61 /// CHECK: begin_block
62 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
63 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
64 /// CHECK-NOT: begin_block
65 /// CHECK: NewInstance [<<LoadClass>>]
66 /// CHECK-NOT: begin_block
67 /// CHECK: NewInstance [<<Error>>]
68 /// CHECK: Throw
69 public static void testSimpleUse() {
70 Object o = new Object();
71 if (doThrow) {
72 throw new Error(o.toString());
73 }
74 }
75
76 /// CHECK-START: void Main.testTwoUses() code_sinking (before)
77 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
78 /// CHECK: NewInstance [<<LoadClass>>]
79 /// CHECK: If
80 /// CHECK: begin_block
81 /// CHECK: Throw
82
83 /// CHECK-START: void Main.testTwoUses() code_sinking (after)
84 /// CHECK-NOT: NewInstance
85 /// CHECK: If
86 /// CHECK: begin_block
87 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
88 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
89 /// CHECK-NOT: begin_block
90 /// CHECK: NewInstance [<<LoadClass>>]
91 /// CHECK-NOT: begin_block
92 /// CHECK: NewInstance [<<Error>>]
93 /// CHECK: Throw
94 public static void testTwoUses() {
95 Object o = new Object();
96 if (doThrow) {
97 throw new Error(o.toString() + o.toString());
98 }
99 }
100
101 /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (before)
102 /// CHECK: <<Int42:i\d+>> IntConstant 42
103 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
104 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
105 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
106 /// CHECK: If
107 /// CHECK: begin_block
108 /// CHECK: Throw
109
110 /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (after)
111 /// CHECK: <<Int42:i\d+>> IntConstant 42
112 /// CHECK-NOT: NewInstance
113 /// CHECK: If
114 /// CHECK: begin_block
115 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
116 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
117 /// CHECK-NOT: begin_block
118 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
119 /// CHECK-NOT: begin_block
120 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
121 /// CHECK-NOT: begin_block
122 /// CHECK: NewInstance [<<Error>>]
123 /// CHECK: Throw
124 public static void testFieldStores(boolean doThrow) {
125 Main m = new Main();
126 m.intField = 42;
127 if (doThrow) {
128 throw new Error(m.toString());
129 }
130 }
131
132 /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (before)
133 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
134 /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
135 /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
136 /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
137 /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
138 /// CHECK: If
139 /// CHECK: begin_block
140 /// CHECK: Throw
141
142 // TODO(ngeoffray): Handle allocation/store cycles.
143 /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (after)
144 /// CHECK: begin_block
145 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
146 /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
147 /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
148 /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
149 /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
150 /// CHECK: If
151 /// CHECK: begin_block
152 /// CHECK: Throw
153 public static void testFieldStoreCycle() {
154 Main m1 = new Main();
155 Main m2 = new Main();
156 m1.objectField = m2;
157 m2.objectField = m1;
158 if (doThrow) {
159 throw new Error(m1.toString() + m2.toString());
160 }
161 }
162
163 /// CHECK-START: void Main.testArrayStores() code_sinking (before)
164 /// CHECK: <<Int1:i\d+>> IntConstant 1
165 /// CHECK: <<Int0:i\d+>> IntConstant 0
166 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
167 /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>]
168 /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
169 /// CHECK: If
170 /// CHECK: begin_block
171 /// CHECK: Throw
172
173 /// CHECK-START: void Main.testArrayStores() code_sinking (after)
174 /// CHECK: <<Int1:i\d+>> IntConstant 1
175 /// CHECK: <<Int0:i\d+>> IntConstant 0
176 /// CHECK-NOT: NewArray
177 /// CHECK: If
178 /// CHECK: begin_block
179 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
180 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[]
181 /// CHECK-NOT: begin_block
182 /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>]
183 /// CHECK-NOT: begin_block
184 /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
185 /// CHECK-NOT: begin_block
186 /// CHECK: NewInstance [<<Error>>]
187 /// CHECK: Throw
188 public static void testArrayStores() {
189 Object[] o = new Object[1];
190 o[0] = o;
191 if (doThrow) {
192 throw new Error(o.toString());
193 }
194 }
195
196 // Make sure code sinking does not crash on dead allocations.
197 public static void testOnlyStoreUses() {
198 Main m = new Main();
199 Object[] o = new Object[1]; // dead allocation, should eventually be removed b/35634932.
200 o[0] = m;
201 o = null; // Avoid environment uses for the array allocation.
202 if (doThrow) {
203 throw new Error(m.toString());
204 }
205 }
206
207 // Make sure code sinking does not crash on dead code.
208 public static void testNoUse() {
209 Main m = new Main();
210 boolean load = Main.doLoop; // dead code, not removed because of environment use.
211 // Ensure one environment use for the static field
212 $opt$noinline$foo();
213 load = false;
214 if (doThrow) {
215 throw new Error(m.toString());
216 }
217 }
218
219 // Make sure we can move code only used by a phi.
220 /// CHECK-START: void Main.testPhiInput() code_sinking (before)
221 /// CHECK: <<Null:l\d+>> NullConstant
222 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
223 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
224 /// CHECK: If
225 /// CHECK: begin_block
226 /// CHECK: Phi [<<Null>>,<<NewInstance>>]
227 /// CHECK: Throw
228
229 /// CHECK-START: void Main.testPhiInput() code_sinking (after)
230 /// CHECK: <<Null:l\d+>> NullConstant
231 /// CHECK-NOT: NewInstance
232 /// CHECK: If
233 /// CHECK: begin_block
234 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
235 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
236 /// CHECK: begin_block
237 /// CHECK: Phi [<<Null>>,<<NewInstance>>]
238 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
239 /// CHECK: NewInstance [<<Error>>]
240 /// CHECK: Throw
241 public static void testPhiInput() {
242 Object f = new Object();
243 if (doThrow) {
244 Object o = null;
245 int i = 2;
246 if (doLoop) {
247 o = f;
248 i = 42;
249 }
250 throw new Error(o.toString() + i);
251 }
252 }
253
254 static void $opt$noinline$foo() {}
255
256 // Check that we do not move volatile stores.
257 /// CHECK-START: void Main.testVolatileStore() code_sinking (before)
258 /// CHECK: <<Int42:i\d+>> IntConstant 42
259 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
260 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
261 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
262 /// CHECK: If
263 /// CHECK: begin_block
264 /// CHECK: Throw
265
266 /// CHECK-START: void Main.testVolatileStore() code_sinking (after)
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 public static void testVolatileStore() {
275 Main m = new Main();
276 m.volatileField = 42;
277 if (doThrow) {
278 throw new Error(m.toString());
279 }
280 }
281
282 public static void testInstanceSideEffects() {
283 int a = mainField.intField;
284 $noinline$changeIntField();
285 if (doThrow) {
286 throw new Error("" + a);
287 }
288 }
289
290 static void $noinline$changeIntField() {
291 mainField.intField = 42;
292 }
293
294 public static void testStaticSideEffects() {
295 Object o = obj;
296 $noinline$changeStaticObjectField();
297 if (doThrow) {
298 throw new Error(o.getClass().toString());
299 }
300 }
301
302 static void $noinline$changeStaticObjectField() {
303 obj = new Main();
304 }
305
306 // Test that we preserve the order of stores.
307 /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (before)
308 /// CHECK: <<Int42:i\d+>> IntConstant 42
309 /// CHECK: <<Int43:i\d+>> IntConstant 43
310 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
311 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
312 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
313 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int43>>]
314 /// CHECK: If
315 /// CHECK: begin_block
316 /// CHECK: Throw
317
318 /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (after)
319 /// CHECK: <<Int42:i\d+>> IntConstant 42
320 /// CHECK: <<Int43:i\d+>> IntConstant 43
321 /// CHECK-NOT: NewInstance
322 /// CHECK: If
323 /// CHECK: begin_block
324 /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error
325 /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main
326 /// CHECK-NOT: begin_block
327 /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
328 /// CHECK-NOT: begin_block
329 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>]
330 /// CHECK-NOT: begin_block
331 /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int43>>]
332 /// CHECK-NOT: begin_block
333 /// CHECK: NewInstance [<<Error>>]
334 /// CHECK: Throw
335 public static void testStoreStore(boolean doThrow) {
336 Main m = new Main();
337 m.intField = 42;
338 m.intField = 43;
339 if (doThrow) {
340 throw new Error(m.$opt$noinline$toString());
341 }
342 }
343
344 public String $opt$noinline$toString() {
345 return "" + intField;
346 }
347
348 volatile int volatileField;
349 int intField;
350 Object objectField;
351 static boolean doThrow;
352 static boolean doLoop;
353 static Main mainField = new Main();
354 static Object obj = new Object();
355}