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 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 } 356