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: <<New:l\d+>> NewInstance [<<LoadClass>>] 54 /// CHECK: ConstructorFence [<<New>>] 55 /// 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 66 /// CHECK: <<New:l\d+>> NewInstance [<<LoadClass>>] 67 /// CHECK: ConstructorFence [<<New>>] 68 /// CHECK-NOT: begin_block 69 /// CHECK: NewInstance [<<Error>>] 70 /// CHECK: Throw testSimpleUse()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 testTwoUses()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 testFieldStores(boolean doThrow)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 testFieldStoreCycle()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 testArrayStores()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. testOnlyStoreUses()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. testNoUse()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 testPhiInput()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 $opt$noinline$foo()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 testVolatileStore()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 testInstanceSideEffects()284 public static void testInstanceSideEffects() { 285 int a = mainField.intField; 286 $noinline$changeIntField(); 287 if (doThrow) { 288 throw new Error("" + a); 289 } 290 } 291 $noinline$changeIntField()292 static void $noinline$changeIntField() { 293 mainField.intField = 42; 294 } 295 testStaticSideEffects()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 $noinline$changeStaticObjectField()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 testStoreStore(boolean doThrow)337 public static void testStoreStore(boolean doThrow) { 338 Main m = new Main(); 339 m.intField = 42; 340 m.intField2 = 43; 341 if (doThrow) { 342 throw new Error(m.$opt$noinline$toString()); 343 } 344 } 345 $opt$noinline$toString()346 public String $opt$noinline$toString() { 347 return "" + intField; 348 } 349 350 volatile int volatileField; 351 int intField; 352 int intField2; 353 Object objectField; 354 static boolean doThrow; 355 static boolean doLoop; 356 static Main mainField = new Main(); 357 static Object obj = new Object(); 358 } 359