• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 public class Main {
18 
main(String[] args)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
testSimpleUse()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
testTwoUses()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
testFieldStores(boolean doThrow)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
testFieldStoreCycle()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
testArrayStores()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.
testOnlyStoreUses()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.
testNoUse()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
testPhiInput()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 
$opt$noinline$foo()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
testVolatileStore()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 
testInstanceSideEffects()282   public static void testInstanceSideEffects() {
283     int a = mainField.intField;
284     $noinline$changeIntField();
285     if (doThrow) {
286       throw new Error("" + a);
287     }
288   }
289 
$noinline$changeIntField()290   static void $noinline$changeIntField() {
291     mainField.intField = 42;
292   }
293 
testStaticSideEffects()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 
$noinline$changeStaticObjectField()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
testStoreStore(boolean doThrow)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 
$opt$noinline$toString()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 }
356