1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker public class Main { 18*795d594fSAndroid Build Coastguard Worker static class ValueHolder { getValue()19*795d594fSAndroid Build Coastguard Worker int getValue() { 20*795d594fSAndroid Build Coastguard Worker // Prevent inliner from matching the code pattern when calling this method to test 21*795d594fSAndroid Build Coastguard Worker // the normal inlining path that does not inline in blocks that end with a `throw`. 22*795d594fSAndroid Build Coastguard Worker $inline$nop(); 23*795d594fSAndroid Build Coastguard Worker 24*795d594fSAndroid Build Coastguard Worker return 1; 25*795d594fSAndroid Build Coastguard Worker } 26*795d594fSAndroid Build Coastguard Worker $inline$nop()27*795d594fSAndroid Build Coastguard Worker private void $inline$nop() {} 28*795d594fSAndroid Build Coastguard Worker } 29*795d594fSAndroid Build Coastguard Worker main(String[] args)30*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 31*795d594fSAndroid Build Coastguard Worker testSimpleUse(); 32*795d594fSAndroid Build Coastguard Worker testTwoUses(); 33*795d594fSAndroid Build Coastguard Worker testFieldStores(doThrow); 34*795d594fSAndroid Build Coastguard Worker testFieldStoreCycle(); 35*795d594fSAndroid Build Coastguard Worker testArrayStores(); 36*795d594fSAndroid Build Coastguard Worker testOnlyStoreUses(); 37*795d594fSAndroid Build Coastguard Worker testNoUse(); 38*795d594fSAndroid Build Coastguard Worker testPhiInput(); 39*795d594fSAndroid Build Coastguard Worker testVolatileStore(); 40*795d594fSAndroid Build Coastguard Worker testCatchBlock(); 41*795d594fSAndroid Build Coastguard Worker $noinline$testTwoThrowingPathsAndStringBuilderAppend(); 42*795d594fSAndroid Build Coastguard Worker try { 43*795d594fSAndroid Build Coastguard Worker $noinline$testSinkNewInstanceWithClinitCheck(); 44*795d594fSAndroid Build Coastguard Worker throw new Exception("Unreachable"); 45*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 46*795d594fSAndroid Build Coastguard Worker // expected 47*795d594fSAndroid Build Coastguard Worker } 48*795d594fSAndroid Build Coastguard Worker $noinline$testMethodEndsWithTryBoundary(); 49*795d594fSAndroid Build Coastguard Worker doThrow = true; 50*795d594fSAndroid Build Coastguard Worker try { 51*795d594fSAndroid Build Coastguard Worker testInstanceSideEffects(); 52*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 53*795d594fSAndroid Build Coastguard Worker // expected 54*795d594fSAndroid Build Coastguard Worker System.out.println(e.getMessage()); 55*795d594fSAndroid Build Coastguard Worker } 56*795d594fSAndroid Build Coastguard Worker try { 57*795d594fSAndroid Build Coastguard Worker testStaticSideEffects(); 58*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 59*795d594fSAndroid Build Coastguard Worker // expected 60*795d594fSAndroid Build Coastguard Worker System.out.println(e.getMessage()); 61*795d594fSAndroid Build Coastguard Worker } 62*795d594fSAndroid Build Coastguard Worker 63*795d594fSAndroid Build Coastguard Worker try { 64*795d594fSAndroid Build Coastguard Worker testStoreStore(doThrow); 65*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 66*795d594fSAndroid Build Coastguard Worker // expected 67*795d594fSAndroid Build Coastguard Worker System.out.println(e.getMessage()); 68*795d594fSAndroid Build Coastguard Worker } 69*795d594fSAndroid Build Coastguard Worker } 70*795d594fSAndroid Build Coastguard Worker 71*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testSimpleUse() code_sinking (before) 72*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object 73*795d594fSAndroid Build Coastguard Worker /// CHECK: <<New:l\d+>> NewInstance [<<LoadClass>>] 74*795d594fSAndroid Build Coastguard Worker /// CHECK: ConstructorFence [<<New>>] 75*795d594fSAndroid Build Coastguard Worker /// CHECK: If 76*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 77*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 78*795d594fSAndroid Build Coastguard Worker 79*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testSimpleUse() code_sinking (after) 80*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: NewInstance 81*795d594fSAndroid Build Coastguard Worker /// CHECK: If 82*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 83*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error 84*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object 85*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 86*795d594fSAndroid Build Coastguard Worker /// CHECK: <<New:l\d+>> NewInstance [<<LoadClass>>] 87*795d594fSAndroid Build Coastguard Worker /// CHECK: ConstructorFence [<<New>>] 88*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 89*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Error>>] 90*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testSimpleUse()91*795d594fSAndroid Build Coastguard Worker public static void testSimpleUse() { 92*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 93*795d594fSAndroid Build Coastguard Worker if (doThrow) { 94*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 95*795d594fSAndroid Build Coastguard Worker } 96*795d594fSAndroid Build Coastguard Worker } 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testTwoUses() code_sinking (before) 99*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object 100*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<LoadClass>>] 101*795d594fSAndroid Build Coastguard Worker /// CHECK: If 102*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 103*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 104*795d594fSAndroid Build Coastguard Worker 105*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testTwoUses() code_sinking (after) 106*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: NewInstance 107*795d594fSAndroid Build Coastguard Worker /// CHECK: If 108*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 109*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error 110*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object 111*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 112*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<LoadClass>>] 113*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 114*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Error>>] 115*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testTwoUses()116*795d594fSAndroid Build Coastguard Worker public static void testTwoUses() { 117*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 118*795d594fSAndroid Build Coastguard Worker if (doThrow) { 119*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString() + o.toString()); 120*795d594fSAndroid Build Coastguard Worker } 121*795d594fSAndroid Build Coastguard Worker } 122*795d594fSAndroid Build Coastguard Worker 123*795d594fSAndroid Build Coastguard Worker // NB It might seem that we'd move the allocation and ifield-set but those are 124*795d594fSAndroid Build Coastguard Worker // already moved into the throw block by a combo of partial-LSE and DCE. 125*795d594fSAndroid Build Coastguard Worker // Instead all that is actually moved is the LoadClass. Also note the 126*795d594fSAndroid Build Coastguard Worker // LoadClass can only be moved since it refers to the 'Main' class itself, 127*795d594fSAndroid Build Coastguard Worker // meaning there's no need for any clinit/actual loading. 128*795d594fSAndroid Build Coastguard Worker // 129*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (before) 130*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int42:i\d+>> IntConstant 42 131*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 132*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 133*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 134*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>] 135*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 136*795d594fSAndroid Build Coastguard Worker 137*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (after) 138*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int42:i\d+>> IntConstant 42 139*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: NewInstance 140*795d594fSAndroid Build Coastguard Worker /// CHECK: If 141*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 142*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error 143*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 144*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 145*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 146*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 147*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 148*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>] 149*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 150*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Throw:l\d+>> NewInstance [<<Error>>] 151*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 152*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw [<<Throw>>] testFieldStores(boolean doThrow)153*795d594fSAndroid Build Coastguard Worker public static void testFieldStores(boolean doThrow) { 154*795d594fSAndroid Build Coastguard Worker Main m = new Main(); 155*795d594fSAndroid Build Coastguard Worker m.intField = 42; 156*795d594fSAndroid Build Coastguard Worker if (doThrow) { 157*795d594fSAndroid Build Coastguard Worker throw new Error(m.toString()); 158*795d594fSAndroid Build Coastguard Worker } 159*795d594fSAndroid Build Coastguard Worker } 160*795d594fSAndroid Build Coastguard Worker 161*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (before) 162*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 163*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>] 164*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>] 165*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>] 166*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>] 167*795d594fSAndroid Build Coastguard Worker /// CHECK: If 168*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 169*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 170*795d594fSAndroid Build Coastguard Worker 171*795d594fSAndroid Build Coastguard Worker // TODO(ngeoffray): Handle allocation/store cycles. 172*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (after) 173*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 174*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 175*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>] 176*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>] 177*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>] 178*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>] 179*795d594fSAndroid Build Coastguard Worker /// CHECK: If 180*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 181*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testFieldStoreCycle()182*795d594fSAndroid Build Coastguard Worker public static void testFieldStoreCycle() { 183*795d594fSAndroid Build Coastguard Worker Main m1 = new Main(); 184*795d594fSAndroid Build Coastguard Worker Main m2 = new Main(); 185*795d594fSAndroid Build Coastguard Worker m1.objectField = m2; 186*795d594fSAndroid Build Coastguard Worker m2.objectField = m1; 187*795d594fSAndroid Build Coastguard Worker if (doThrow) { 188*795d594fSAndroid Build Coastguard Worker throw new Error(m1.toString() + m2.toString()); 189*795d594fSAndroid Build Coastguard Worker } 190*795d594fSAndroid Build Coastguard Worker } 191*795d594fSAndroid Build Coastguard Worker 192*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testArrayStores() code_sinking (before) 193*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int1:i\d+>> IntConstant 1 194*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int0:i\d+>> IntConstant 0 195*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[] 196*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>] 197*795d594fSAndroid Build Coastguard Worker /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>] 198*795d594fSAndroid Build Coastguard Worker /// CHECK: If 199*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 200*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 201*795d594fSAndroid Build Coastguard Worker 202*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testArrayStores() code_sinking (after) 203*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int1:i\d+>> IntConstant 1 204*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int0:i\d+>> IntConstant 0 205*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: NewArray 206*795d594fSAndroid Build Coastguard Worker /// CHECK: If 207*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 208*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error 209*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[] 210*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 211*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewArray:l\d+>> NewArray [<<LoadClass>>,<<Int1>>] 212*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 213*795d594fSAndroid Build Coastguard Worker /// CHECK: ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>] 214*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 215*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Error>>] 216*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testArrayStores()217*795d594fSAndroid Build Coastguard Worker public static void testArrayStores() { 218*795d594fSAndroid Build Coastguard Worker Object[] o = new Object[1]; 219*795d594fSAndroid Build Coastguard Worker o[0] = o; 220*795d594fSAndroid Build Coastguard Worker if (doThrow) { 221*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 222*795d594fSAndroid Build Coastguard Worker } 223*795d594fSAndroid Build Coastguard Worker } 224*795d594fSAndroid Build Coastguard Worker 225*795d594fSAndroid Build Coastguard Worker // Make sure code sinking does not crash on dead allocations. testOnlyStoreUses()226*795d594fSAndroid Build Coastguard Worker public static void testOnlyStoreUses() { 227*795d594fSAndroid Build Coastguard Worker Main m = new Main(); 228*795d594fSAndroid Build Coastguard Worker Object[] o = new Object[1]; // dead allocation, should eventually be removed b/35634932. 229*795d594fSAndroid Build Coastguard Worker o[0] = m; 230*795d594fSAndroid Build Coastguard Worker o = null; // Avoid environment uses for the array allocation. 231*795d594fSAndroid Build Coastguard Worker if (doThrow) { 232*795d594fSAndroid Build Coastguard Worker throw new Error(m.toString()); 233*795d594fSAndroid Build Coastguard Worker } 234*795d594fSAndroid Build Coastguard Worker } 235*795d594fSAndroid Build Coastguard Worker 236*795d594fSAndroid Build Coastguard Worker // Make sure code sinking does not crash on dead code. testNoUse()237*795d594fSAndroid Build Coastguard Worker public static void testNoUse() { 238*795d594fSAndroid Build Coastguard Worker Main m = new Main(); 239*795d594fSAndroid Build Coastguard Worker boolean load = Main.doLoop; // dead code, not removed because of environment use. 240*795d594fSAndroid Build Coastguard Worker // Ensure one environment use for the static field 241*795d594fSAndroid Build Coastguard Worker $opt$noinline$foo(); 242*795d594fSAndroid Build Coastguard Worker load = false; 243*795d594fSAndroid Build Coastguard Worker if (doThrow) { 244*795d594fSAndroid Build Coastguard Worker throw new Error(m.toString()); 245*795d594fSAndroid Build Coastguard Worker } 246*795d594fSAndroid Build Coastguard Worker } 247*795d594fSAndroid Build Coastguard Worker 248*795d594fSAndroid Build Coastguard Worker // Make sure we can move code only used by a phi. 249*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testPhiInput() code_sinking (before) 250*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Null:l\d+>> NullConstant 251*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object 252*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 253*795d594fSAndroid Build Coastguard Worker /// CHECK: If 254*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 255*795d594fSAndroid Build Coastguard Worker /// CHECK: Phi [<<Null>>,<<NewInstance>>] 256*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 257*795d594fSAndroid Build Coastguard Worker 258*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testPhiInput() code_sinking (after) 259*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Null:l\d+>> NullConstant 260*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: NewInstance 261*795d594fSAndroid Build Coastguard Worker /// CHECK: If 262*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 263*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object 264*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 265*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 266*795d594fSAndroid Build Coastguard Worker /// CHECK: Phi [<<Null>>,<<NewInstance>>] 267*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error 268*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Error>>] 269*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testPhiInput()270*795d594fSAndroid Build Coastguard Worker public static void testPhiInput() { 271*795d594fSAndroid Build Coastguard Worker Object f = new Object(); 272*795d594fSAndroid Build Coastguard Worker if (doThrow) { 273*795d594fSAndroid Build Coastguard Worker Object o = null; 274*795d594fSAndroid Build Coastguard Worker int i = 2; 275*795d594fSAndroid Build Coastguard Worker if (doLoop) { 276*795d594fSAndroid Build Coastguard Worker o = f; 277*795d594fSAndroid Build Coastguard Worker i = 42; 278*795d594fSAndroid Build Coastguard Worker } 279*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString() + i); 280*795d594fSAndroid Build Coastguard Worker } 281*795d594fSAndroid Build Coastguard Worker } 282*795d594fSAndroid Build Coastguard Worker $opt$noinline$foo()283*795d594fSAndroid Build Coastguard Worker static void $opt$noinline$foo() {} 284*795d594fSAndroid Build Coastguard Worker 285*795d594fSAndroid Build Coastguard Worker // Check that we do not move volatile stores. 286*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testVolatileStore() code_sinking (before) 287*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int42:i\d+>> IntConstant 42 288*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 289*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 290*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>] 291*795d594fSAndroid Build Coastguard Worker /// CHECK: If 292*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 293*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 294*795d594fSAndroid Build Coastguard Worker 295*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testVolatileStore() code_sinking (after) 296*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int42:i\d+>> IntConstant 42 297*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 298*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 299*795d594fSAndroid Build Coastguard Worker /// CHECK: InstanceFieldSet [<<NewInstance>>,<<Int42>>] 300*795d594fSAndroid Build Coastguard Worker /// CHECK: If 301*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 302*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testVolatileStore()303*795d594fSAndroid Build Coastguard Worker public static void testVolatileStore() { 304*795d594fSAndroid Build Coastguard Worker Main m = new Main(); 305*795d594fSAndroid Build Coastguard Worker m.volatileField = 42; 306*795d594fSAndroid Build Coastguard Worker if (doThrow) { 307*795d594fSAndroid Build Coastguard Worker throw new Error(m.toString()); 308*795d594fSAndroid Build Coastguard Worker } 309*795d594fSAndroid Build Coastguard Worker } 310*795d594fSAndroid Build Coastguard Worker $noinline$testMethodEndsWithTryBoundary()311*795d594fSAndroid Build Coastguard Worker private static void $noinline$testMethodEndsWithTryBoundary() throws Exception { 312*795d594fSAndroid Build Coastguard Worker assertEquals(0, $noinline$testDontSinkToReturnBranch(0, 0, false, new Object())); 313*795d594fSAndroid Build Coastguard Worker assertEquals(1, $noinline$testSinkToThrowBranch(0, 0, true, new Object())); 314*795d594fSAndroid Build Coastguard Worker try { 315*795d594fSAndroid Build Coastguard Worker $noinline$testSinkToThrowBranch(0, 0, false, new Object()); 316*795d594fSAndroid Build Coastguard Worker throw new Exception("Unreachable"); 317*795d594fSAndroid Build Coastguard Worker } catch (Error expected) { 318*795d594fSAndroid Build Coastguard Worker } 319*795d594fSAndroid Build Coastguard Worker } 320*795d594fSAndroid Build Coastguard Worker 321*795d594fSAndroid Build Coastguard Worker // Consistency check: only one add 322*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.$noinline$testDontSinkToReturnBranch(int, int, boolean, java.lang.Object) code_sinking (before) 323*795d594fSAndroid Build Coastguard Worker /// CHECK: Add 324*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: Add 325*795d594fSAndroid Build Coastguard Worker 326*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.$noinline$testDontSinkToReturnBranch(int, int, boolean, java.lang.Object) code_sinking (before) 327*795d594fSAndroid Build Coastguard Worker /// CHECK: Add 328*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: If 329*795d594fSAndroid Build Coastguard Worker 330*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.$noinline$testDontSinkToReturnBranch(int, int, boolean, java.lang.Object) code_sinking (after) 331*795d594fSAndroid Build Coastguard Worker /// CHECK: Add 332*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: If $noinline$testDontSinkToReturnBranch(int a, int b, boolean flag, Object obj)333*795d594fSAndroid Build Coastguard Worker private static int $noinline$testDontSinkToReturnBranch(int a, int b, boolean flag, Object obj) { 334*795d594fSAndroid Build Coastguard Worker int c = a + b; 335*795d594fSAndroid Build Coastguard Worker if (flag) { 336*795d594fSAndroid Build Coastguard Worker return 1; 337*795d594fSAndroid Build Coastguard Worker } 338*795d594fSAndroid Build Coastguard Worker 339*795d594fSAndroid Build Coastguard Worker synchronized (obj) { 340*795d594fSAndroid Build Coastguard Worker return $noinline$returnSameValue(c); 341*795d594fSAndroid Build Coastguard Worker } 342*795d594fSAndroid Build Coastguard Worker } 343*795d594fSAndroid Build Coastguard Worker $noinline$returnSameValue(int value)344*795d594fSAndroid Build Coastguard Worker private static int $noinline$returnSameValue(int value) { 345*795d594fSAndroid Build Coastguard Worker return value; 346*795d594fSAndroid Build Coastguard Worker } 347*795d594fSAndroid Build Coastguard Worker 348*795d594fSAndroid Build Coastguard Worker // Consistency check: only one add 349*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.$noinline$testSinkToThrowBranch(int, int, boolean, java.lang.Object) code_sinking (before) 350*795d594fSAndroid Build Coastguard Worker /// CHECK: Add 351*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: Add 352*795d594fSAndroid Build Coastguard Worker 353*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.$noinline$testSinkToThrowBranch(int, int, boolean, java.lang.Object) code_sinking (before) 354*795d594fSAndroid Build Coastguard Worker /// CHECK: Add 355*795d594fSAndroid Build Coastguard Worker /// CHECK: If 356*795d594fSAndroid Build Coastguard Worker 357*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.$noinline$testSinkToThrowBranch(int, int, boolean, java.lang.Object) code_sinking (after) 358*795d594fSAndroid Build Coastguard Worker /// CHECK: If 359*795d594fSAndroid Build Coastguard Worker /// CHECK: Add $noinline$testSinkToThrowBranch(int a, int b, boolean flag, Object obj)360*795d594fSAndroid Build Coastguard Worker private static int $noinline$testSinkToThrowBranch(int a, int b, boolean flag, Object obj) { 361*795d594fSAndroid Build Coastguard Worker int c = a + b; 362*795d594fSAndroid Build Coastguard Worker if (flag) { 363*795d594fSAndroid Build Coastguard Worker return 1; 364*795d594fSAndroid Build Coastguard Worker } 365*795d594fSAndroid Build Coastguard Worker 366*795d594fSAndroid Build Coastguard Worker synchronized (obj) { 367*795d594fSAndroid Build Coastguard Worker throw new Error(Integer.toString(c)); 368*795d594fSAndroid Build Coastguard Worker } 369*795d594fSAndroid Build Coastguard Worker } 370*795d594fSAndroid Build Coastguard Worker testInstanceSideEffects()371*795d594fSAndroid Build Coastguard Worker public static void testInstanceSideEffects() { 372*795d594fSAndroid Build Coastguard Worker int a = mainField.intField; 373*795d594fSAndroid Build Coastguard Worker $noinline$changeIntField(); 374*795d594fSAndroid Build Coastguard Worker if (doThrow) { 375*795d594fSAndroid Build Coastguard Worker throw new Error("" + a); 376*795d594fSAndroid Build Coastguard Worker } 377*795d594fSAndroid Build Coastguard Worker } 378*795d594fSAndroid Build Coastguard Worker $noinline$changeIntField()379*795d594fSAndroid Build Coastguard Worker static void $noinline$changeIntField() { 380*795d594fSAndroid Build Coastguard Worker mainField.intField = 42; 381*795d594fSAndroid Build Coastguard Worker } 382*795d594fSAndroid Build Coastguard Worker testStaticSideEffects()383*795d594fSAndroid Build Coastguard Worker public static void testStaticSideEffects() { 384*795d594fSAndroid Build Coastguard Worker Object o = obj; 385*795d594fSAndroid Build Coastguard Worker $noinline$changeStaticObjectField(); 386*795d594fSAndroid Build Coastguard Worker if (doThrow) { 387*795d594fSAndroid Build Coastguard Worker throw new Error(o.getClass().toString()); 388*795d594fSAndroid Build Coastguard Worker } 389*795d594fSAndroid Build Coastguard Worker } 390*795d594fSAndroid Build Coastguard Worker $noinline$changeStaticObjectField()391*795d594fSAndroid Build Coastguard Worker static void $noinline$changeStaticObjectField() { 392*795d594fSAndroid Build Coastguard Worker obj = new Main(); 393*795d594fSAndroid Build Coastguard Worker } 394*795d594fSAndroid Build Coastguard Worker 395*795d594fSAndroid Build Coastguard Worker // Test that we preserve the order of stores. 396*795d594fSAndroid Build Coastguard Worker // NB It might seem that we'd move the allocation and ifield-set but those are 397*795d594fSAndroid Build Coastguard Worker // already moved into the throw block by a combo of partial-LSE and DCE. 398*795d594fSAndroid Build Coastguard Worker // Instead all that is actually moved is the LoadClass. Also note the 399*795d594fSAndroid Build Coastguard Worker // LoadClass can only be moved since it refers to the 'Main' class itself, 400*795d594fSAndroid Build Coastguard Worker // meaning there's no need for any clinit/actual loading. 401*795d594fSAndroid Build Coastguard Worker // 402*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (before) 403*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int42:i\d+>> IntConstant 42 404*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int43:i\d+>> IntConstant 43 405*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 406*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 407*795d594fSAndroid Build Coastguard Worker /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int42>>] 408*795d594fSAndroid Build Coastguard Worker /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int43>>] 409*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 410*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: InstanceFieldSet 411*795d594fSAndroid Build Coastguard Worker 412*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (after) 413*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int42:i\d+>> IntConstant 42 414*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int43:i\d+>> IntConstant 43 415*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: NewInstance 416*795d594fSAndroid Build Coastguard Worker /// CHECK: If 417*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 418*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Error:l\d+>> LoadClass class_name:java.lang.Error 419*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 420*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main 421*795d594fSAndroid Build Coastguard Worker /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>] 422*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 423*795d594fSAndroid Build Coastguard Worker /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int42>>] 424*795d594fSAndroid Build Coastguard Worker /// CHECK-DAG: InstanceFieldSet [<<NewInstance>>,<<Int43>>] 425*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 426*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Error>>] 427*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 428*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: InstanceFieldSet testStoreStore(boolean doThrow)429*795d594fSAndroid Build Coastguard Worker public static void testStoreStore(boolean doThrow) { 430*795d594fSAndroid Build Coastguard Worker Main m = new Main(); 431*795d594fSAndroid Build Coastguard Worker m.intField = 42; 432*795d594fSAndroid Build Coastguard Worker m.intField2 = 43; 433*795d594fSAndroid Build Coastguard Worker if (doThrow) { 434*795d594fSAndroid Build Coastguard Worker throw new Error(m.$opt$noinline$toString()); 435*795d594fSAndroid Build Coastguard Worker } 436*795d594fSAndroid Build Coastguard Worker } 437*795d594fSAndroid Build Coastguard Worker doStaticNativeCallLiveVreg()438*795d594fSAndroid Build Coastguard Worker static native void doStaticNativeCallLiveVreg(); 439*795d594fSAndroid Build Coastguard Worker 440*795d594fSAndroid Build Coastguard Worker // Test ensures that 'o' has been moved into the if despite the InvokeStaticOrDirect. 441*795d594fSAndroid Build Coastguard Worker // 442*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (before) 443*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int1:i\d+>> IntConstant 1 444*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int0:i\d+>> IntConstant 0 445*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[] 446*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: begin_block 447*795d594fSAndroid Build Coastguard Worker /// CHECK: NewArray [<<LoadClass>>,<<Int1>>] 448*795d594fSAndroid Build Coastguard Worker /// CHECK: If 449*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 450*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw 451*795d594fSAndroid Build Coastguard Worker 452*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.testSinkingOverInvoke() code_sinking (after) 453*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int1:i\d+>> IntConstant 1 454*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Int0:i\d+>> IntConstant 0 455*795d594fSAndroid Build Coastguard Worker /// CHECK: If 456*795d594fSAndroid Build Coastguard Worker /// CHECK: begin_block 457*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object[] 458*795d594fSAndroid Build Coastguard Worker /// CHECK: NewArray [<<LoadClass>>,<<Int1>>] 459*795d594fSAndroid Build Coastguard Worker /// CHECK: Throw testSinkingOverInvoke()460*795d594fSAndroid Build Coastguard Worker static void testSinkingOverInvoke() { 461*795d594fSAndroid Build Coastguard Worker Object[] o = new Object[1]; 462*795d594fSAndroid Build Coastguard Worker o[0] = o; 463*795d594fSAndroid Build Coastguard Worker doStaticNativeCallLiveVreg(); 464*795d594fSAndroid Build Coastguard Worker if (doThrow) { 465*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 466*795d594fSAndroid Build Coastguard Worker } 467*795d594fSAndroid Build Coastguard Worker } 468*795d594fSAndroid Build Coastguard Worker $opt$noinline$toString()469*795d594fSAndroid Build Coastguard Worker public String $opt$noinline$toString() { 470*795d594fSAndroid Build Coastguard Worker return "" + intField; 471*795d594fSAndroid Build Coastguard Worker } 472*795d594fSAndroid Build Coastguard Worker testCatchBlock()473*795d594fSAndroid Build Coastguard Worker private static void testCatchBlock() { 474*795d594fSAndroid Build Coastguard Worker assertEquals(456, testDoNotSinkToTry()); 475*795d594fSAndroid Build Coastguard Worker assertEquals(456, testSinkWithinTryBlock()); 476*795d594fSAndroid Build Coastguard Worker assertEquals(456, testSinkRightBeforeTryBlock()); 477*795d594fSAndroid Build Coastguard Worker assertEquals(456, testDoNotSinkToCatchInsideTryWithMoreThings(false, false)); 478*795d594fSAndroid Build Coastguard Worker assertEquals(456, DoNotSinkWithOOMThrow()); 479*795d594fSAndroid Build Coastguard Worker } 480*795d594fSAndroid Build Coastguard Worker 481*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testDoNotSinkToTry() code_sinking (before) 482*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 483*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 484*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 485*795d594fSAndroid Build Coastguard Worker 486*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testDoNotSinkToTry() code_sinking (after) 487*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 488*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 489*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 490*795d594fSAndroid Build Coastguard Worker 491*795d594fSAndroid Build Coastguard Worker // Consistency check to make sure there's only one entry TryBoundary. 492*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testDoNotSinkToTry() code_sinking (after) 493*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 494*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: TryBoundary kind:entry 495*795d594fSAndroid Build Coastguard Worker 496*795d594fSAndroid Build Coastguard Worker // Tests that we don't sink the Object creation into the try. testDoNotSinkToTry()497*795d594fSAndroid Build Coastguard Worker private static int testDoNotSinkToTry() { 498*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 499*795d594fSAndroid Build Coastguard Worker try { 500*795d594fSAndroid Build Coastguard Worker if (doEarlyReturn) { 501*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 502*795d594fSAndroid Build Coastguard Worker } 503*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 504*795d594fSAndroid Build Coastguard Worker throw new Error(); 505*795d594fSAndroid Build Coastguard Worker } 506*795d594fSAndroid Build Coastguard Worker return 456; 507*795d594fSAndroid Build Coastguard Worker } 508*795d594fSAndroid Build Coastguard Worker 509*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testSinkWithinTryBlock() code_sinking (before) 510*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 511*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 512*795d594fSAndroid Build Coastguard Worker /// CHECK: If 513*795d594fSAndroid Build Coastguard Worker 514*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testSinkWithinTryBlock() code_sinking (after) 515*795d594fSAndroid Build Coastguard Worker /// CHECK: If 516*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 517*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] testSinkWithinTryBlock()518*795d594fSAndroid Build Coastguard Worker private static int testSinkWithinTryBlock() { 519*795d594fSAndroid Build Coastguard Worker try { 520*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 521*795d594fSAndroid Build Coastguard Worker if (doEarlyReturn) { 522*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 523*795d594fSAndroid Build Coastguard Worker } 524*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 525*795d594fSAndroid Build Coastguard Worker return 123; 526*795d594fSAndroid Build Coastguard Worker } 527*795d594fSAndroid Build Coastguard Worker return 456; 528*795d594fSAndroid Build Coastguard Worker } 529*795d594fSAndroid Build Coastguard Worker 530*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testSinkRightBeforeTryBlock() code_sinking (before) 531*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 532*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 533*795d594fSAndroid Build Coastguard Worker /// CHECK: If 534*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 535*795d594fSAndroid Build Coastguard Worker 536*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testSinkRightBeforeTryBlock() code_sinking (after) 537*795d594fSAndroid Build Coastguard Worker /// CHECK: If 538*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 539*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 540*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry testSinkRightBeforeTryBlock()541*795d594fSAndroid Build Coastguard Worker private static int testSinkRightBeforeTryBlock() { 542*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 543*795d594fSAndroid Build Coastguard Worker if (doEarlyReturn) { 544*795d594fSAndroid Build Coastguard Worker try { 545*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 546*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 547*795d594fSAndroid Build Coastguard Worker return 123; 548*795d594fSAndroid Build Coastguard Worker } 549*795d594fSAndroid Build Coastguard Worker } 550*795d594fSAndroid Build Coastguard Worker return 456; 551*795d594fSAndroid Build Coastguard Worker } 552*795d594fSAndroid Build Coastguard Worker 553*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testDoNotSinkToCatchInsideTryWithMoreThings(boolean, boolean) code_sinking (before) 554*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: TryBoundary kind:entry 555*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 556*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 557*795d594fSAndroid Build Coastguard Worker 558*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.testDoNotSinkToCatchInsideTryWithMoreThings(boolean, boolean) code_sinking (after) 559*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: TryBoundary kind:entry 560*795d594fSAndroid Build Coastguard Worker /// CHECK: <<ObjLoadClass:l\d+>> LoadClass class_name:java.lang.Object 561*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<ObjLoadClass>>] 562*795d594fSAndroid Build Coastguard Worker 563*795d594fSAndroid Build Coastguard Worker // Tests that we don't sink the Object creation into a catch handler surrounded by try/catch, even 564*795d594fSAndroid Build Coastguard Worker // when that inner catch is not at the boundary of the outer try catch. testDoNotSinkToCatchInsideTryWithMoreThings(boolean a, boolean b)565*795d594fSAndroid Build Coastguard Worker private static int testDoNotSinkToCatchInsideTryWithMoreThings(boolean a, boolean b) { 566*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 567*795d594fSAndroid Build Coastguard Worker try { 568*795d594fSAndroid Build Coastguard Worker if (a) { 569*795d594fSAndroid Build Coastguard Worker System.out.println(a); 570*795d594fSAndroid Build Coastguard Worker } 571*795d594fSAndroid Build Coastguard Worker try { 572*795d594fSAndroid Build Coastguard Worker if (doEarlyReturn) { 573*795d594fSAndroid Build Coastguard Worker return 123; 574*795d594fSAndroid Build Coastguard Worker } 575*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 576*795d594fSAndroid Build Coastguard Worker throw new Error(o.toString()); 577*795d594fSAndroid Build Coastguard Worker } 578*795d594fSAndroid Build Coastguard Worker if (b) { 579*795d594fSAndroid Build Coastguard Worker System.out.println(b); 580*795d594fSAndroid Build Coastguard Worker } 581*795d594fSAndroid Build Coastguard Worker } catch (Error e) { 582*795d594fSAndroid Build Coastguard Worker throw new Error(); 583*795d594fSAndroid Build Coastguard Worker } 584*795d594fSAndroid Build Coastguard Worker return 456; 585*795d594fSAndroid Build Coastguard Worker } 586*795d594fSAndroid Build Coastguard Worker 587*795d594fSAndroid Build Coastguard Worker private static class ObjectWithInt { 588*795d594fSAndroid Build Coastguard Worker int x; 589*795d594fSAndroid Build Coastguard Worker } 590*795d594fSAndroid Build Coastguard Worker 591*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.DoNotSinkWithOOMThrow() code_sinking (before) 592*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main$ObjectWithInt 593*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Clinit:l\d+>> ClinitCheck [<<LoadClass>>] 594*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Clinit>>] 595*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 596*795d594fSAndroid Build Coastguard Worker 597*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.DoNotSinkWithOOMThrow() code_sinking (after) 598*795d594fSAndroid Build Coastguard Worker /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:Main$ObjectWithInt 599*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Clinit:l\d+>> ClinitCheck [<<LoadClass>>] 600*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Clinit>>] 601*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 602*795d594fSAndroid Build Coastguard Worker 603*795d594fSAndroid Build Coastguard Worker // Consistency check to make sure there's only one entry TryBoundary. 604*795d594fSAndroid Build Coastguard Worker /// CHECK-START: int Main.DoNotSinkWithOOMThrow() code_sinking (after) 605*795d594fSAndroid Build Coastguard Worker /// CHECK: TryBoundary kind:entry 606*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: TryBoundary kind:entry DoNotSinkWithOOMThrow()607*795d594fSAndroid Build Coastguard Worker private static int DoNotSinkWithOOMThrow() throws OutOfMemoryError { 608*795d594fSAndroid Build Coastguard Worker int x = 0; 609*795d594fSAndroid Build Coastguard Worker ObjectWithInt obj = new ObjectWithInt(); 610*795d594fSAndroid Build Coastguard Worker try { 611*795d594fSAndroid Build Coastguard Worker // We want an if/else here so that the catch block will have a catch phi. 612*795d594fSAndroid Build Coastguard Worker if (doThrow) { 613*795d594fSAndroid Build Coastguard Worker x = 1; 614*795d594fSAndroid Build Coastguard Worker // Doesn't really matter what we throw we just want it to not be caught by the 615*795d594fSAndroid Build Coastguard Worker // NullPointerException below. 616*795d594fSAndroid Build Coastguard Worker throw new OutOfMemoryError(Integer.toString(obj.x)); 617*795d594fSAndroid Build Coastguard Worker } else { 618*795d594fSAndroid Build Coastguard Worker x = 456; 619*795d594fSAndroid Build Coastguard Worker } 620*795d594fSAndroid Build Coastguard Worker } catch (NullPointerException e) { 621*795d594fSAndroid Build Coastguard Worker } 622*795d594fSAndroid Build Coastguard Worker 623*795d594fSAndroid Build Coastguard Worker // We want to use obj over here so that it doesn't get deleted by LSE. 624*795d594fSAndroid Build Coastguard Worker if (obj.x == 123) { 625*795d594fSAndroid Build Coastguard Worker return 123; 626*795d594fSAndroid Build Coastguard Worker } 627*795d594fSAndroid Build Coastguard Worker return x; 628*795d594fSAndroid Build Coastguard Worker } 629*795d594fSAndroid Build Coastguard Worker $noinline$testTwoThrowingPathsAndStringBuilderAppend()630*795d594fSAndroid Build Coastguard Worker private static void $noinline$testTwoThrowingPathsAndStringBuilderAppend() { 631*795d594fSAndroid Build Coastguard Worker try { 632*795d594fSAndroid Build Coastguard Worker $noinline$twoThrowingPathsAndStringBuilderAppend(null); 633*795d594fSAndroid Build Coastguard Worker throw new Error("Unreachable"); 634*795d594fSAndroid Build Coastguard Worker } catch (Error expected) { 635*795d594fSAndroid Build Coastguard Worker assertEquals("Object is null", expected.getMessage()); 636*795d594fSAndroid Build Coastguard Worker } 637*795d594fSAndroid Build Coastguard Worker try { 638*795d594fSAndroid Build Coastguard Worker $noinline$twoThrowingPathsAndStringBuilderAppend(new Object()); 639*795d594fSAndroid Build Coastguard Worker throw new Error("Unreachable"); 640*795d594fSAndroid Build Coastguard Worker } catch (Error expected) { 641*795d594fSAndroid Build Coastguard Worker assertEquals("s1s2", expected.getMessage()); 642*795d594fSAndroid Build Coastguard Worker } 643*795d594fSAndroid Build Coastguard Worker } 644*795d594fSAndroid Build Coastguard Worker 645*795d594fSAndroid Build Coastguard Worker // Consistency check: only one ClinitCheck 646*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() code_sinking (before) 647*795d594fSAndroid Build Coastguard Worker /// CHECK: ClinitCheck 648*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: ClinitCheck 649*795d594fSAndroid Build Coastguard Worker 650*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() code_sinking (before) 651*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Check:l\d+>> ClinitCheck 652*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Check>>] 653*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance 654*795d594fSAndroid Build Coastguard Worker /// CHECK: If 655*795d594fSAndroid Build Coastguard Worker 656*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() code_sinking (after) 657*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Check:l\d+>> ClinitCheck 658*795d594fSAndroid Build Coastguard Worker /// CHECK: If 659*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance 660*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Check>>] 661*795d594fSAndroid Build Coastguard Worker 662*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() prepare_for_register_allocation (before) 663*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: If 664*795d594fSAndroid Build Coastguard Worker 665*795d594fSAndroid Build Coastguard Worker // We have an instruction that can throw between the ClinitCheck and its NewInstance. 666*795d594fSAndroid Build Coastguard Worker 667*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() prepare_for_register_allocation (before) 668*795d594fSAndroid Build Coastguard Worker /// CHECK: <<Check:l\d+>> ClinitCheck 669*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance 670*795d594fSAndroid Build Coastguard Worker /// CHECK: NewInstance [<<Check>>] 671*795d594fSAndroid Build Coastguard Worker 672*795d594fSAndroid Build Coastguard Worker // We can remove the ClinitCheck by merging it with the LoadClass right before. 673*795d594fSAndroid Build Coastguard Worker 674*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$testSinkNewInstanceWithClinitCheck() prepare_for_register_allocation (after) 675*795d594fSAndroid Build Coastguard Worker /// CHECK-NOT: ClinitCheck $noinline$testSinkNewInstanceWithClinitCheck()676*795d594fSAndroid Build Coastguard Worker private static void $noinline$testSinkNewInstanceWithClinitCheck() { 677*795d594fSAndroid Build Coastguard Worker ValueHolder vh = new ValueHolder(); 678*795d594fSAndroid Build Coastguard Worker Object o = new Object(); 679*795d594fSAndroid Build Coastguard Worker 680*795d594fSAndroid Build Coastguard Worker // The if will always be true but we don't know this after LSE. Code sinking will sink code 681*795d594fSAndroid Build Coastguard Worker // since this is an uncommon branch, but then we will have everything in one block before 682*795d594fSAndroid Build Coastguard Worker // prepare_for_register_allocation for the crash to appear. 683*795d594fSAndroid Build Coastguard Worker staticIntField = 1; 684*795d594fSAndroid Build Coastguard Worker int value = staticIntField; 685*795d594fSAndroid Build Coastguard Worker if (value == 1) { 686*795d594fSAndroid Build Coastguard Worker throw new Error(Integer.toString(vh.getValue()) + o.toString()); 687*795d594fSAndroid Build Coastguard Worker } 688*795d594fSAndroid Build Coastguard Worker } 689*795d594fSAndroid Build Coastguard Worker 690*795d594fSAndroid Build Coastguard Worker // We currently do not inline the `StringBuilder` constructor. 691*795d594fSAndroid Build Coastguard Worker // When we did, the `StringBuilderAppend` pattern recognition was looking for 692*795d594fSAndroid Build Coastguard Worker // the inlined `NewArray` (and its associated `LoadClass`) and checked in 693*795d594fSAndroid Build Coastguard Worker // debug build that the `StringBuilder` has an environment use from this 694*795d594fSAndroid Build Coastguard Worker // `NewArray` (and maybe from `LoadClass`). However, code sinking was pruning 695*795d594fSAndroid Build Coastguard Worker // the environment of the `NewArray`, leading to a crash when compiling the 696*795d594fSAndroid Build Coastguard Worker // code below on the device (we do not inline `core-oj` on host). b/252799691 697*795d594fSAndroid Build Coastguard Worker 698*795d594fSAndroid Build Coastguard Worker // We currently have a heuristic that disallows inlining methods if their basic blocks end with a 699*795d594fSAndroid Build Coastguard Worker // throw. We could add code so that `requireNonNull`'s block doesn't end with a throw but that 700*795d594fSAndroid Build Coastguard Worker // would mean that the string builder optimization wouldn't fire as it requires all uses to be in 701*795d594fSAndroid Build Coastguard Worker // the same block. If `requireNonNull` is inlined at some point, we need to re-mark it as $inline$ 702*795d594fSAndroid Build Coastguard Worker // so that the test is operational again. 703*795d594fSAndroid Build Coastguard Worker 704*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$twoThrowingPathsAndStringBuilderAppend(java.lang.Object) inliner (before) 705*795d594fSAndroid Build Coastguard Worker /// CHECK: InvokeStaticOrDirect method_name:Main.requireNonNull 706*795d594fSAndroid Build Coastguard Worker 707*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void Main.$noinline$twoThrowingPathsAndStringBuilderAppend(java.lang.Object) inliner (after) 708*795d594fSAndroid Build Coastguard Worker /// CHECK: InvokeStaticOrDirect method_name:Main.requireNonNull $noinline$twoThrowingPathsAndStringBuilderAppend(Object o)709*795d594fSAndroid Build Coastguard Worker private static void $noinline$twoThrowingPathsAndStringBuilderAppend(Object o) { 710*795d594fSAndroid Build Coastguard Worker String s1 = "s1"; 711*795d594fSAndroid Build Coastguard Worker String s2 = "s2"; 712*795d594fSAndroid Build Coastguard Worker StringBuilder sb = new StringBuilder(); 713*795d594fSAndroid Build Coastguard Worker 714*795d594fSAndroid Build Coastguard Worker // Before inlining, the environment use from this invoke prevents the 715*795d594fSAndroid Build Coastguard Worker // `StringBuilderAppend` pattern recognition. After inlining, we end up 716*795d594fSAndroid Build Coastguard Worker // with two paths ending with a `Throw` and we could sink the `sb` 717*795d594fSAndroid Build Coastguard Worker // instructions from above down to those below, enabling the 718*795d594fSAndroid Build Coastguard Worker // `StringBuilderAppend` pattern recognition. 719*795d594fSAndroid Build Coastguard Worker // (But that does not happen when the `StringBuilder` constructor is 720*795d594fSAndroid Build Coastguard Worker // not inlined, see above.) 721*795d594fSAndroid Build Coastguard Worker requireNonNull(o); 722*795d594fSAndroid Build Coastguard Worker 723*795d594fSAndroid Build Coastguard Worker String s1s2 = sb.append(s1).append(s2).toString(); 724*795d594fSAndroid Build Coastguard Worker sb = null; 725*795d594fSAndroid Build Coastguard Worker throw new Error(s1s2); 726*795d594fSAndroid Build Coastguard Worker } 727*795d594fSAndroid Build Coastguard Worker requireNonNull(Object o)728*795d594fSAndroid Build Coastguard Worker private static void requireNonNull(Object o) { 729*795d594fSAndroid Build Coastguard Worker if (o == null) { 730*795d594fSAndroid Build Coastguard Worker throw new Error("Object is null"); 731*795d594fSAndroid Build Coastguard Worker } 732*795d594fSAndroid Build Coastguard Worker } 733*795d594fSAndroid Build Coastguard Worker assertEquals(int expected, int actual)734*795d594fSAndroid Build Coastguard Worker private static void assertEquals(int expected, int actual) { 735*795d594fSAndroid Build Coastguard Worker if (expected != actual) { 736*795d594fSAndroid Build Coastguard Worker throw new AssertionError("Expected: " + expected + ", Actual: " + actual); 737*795d594fSAndroid Build Coastguard Worker } 738*795d594fSAndroid Build Coastguard Worker } 739*795d594fSAndroid Build Coastguard Worker assertEquals(String expected, String actual)740*795d594fSAndroid Build Coastguard Worker private static void assertEquals(String expected, String actual) { 741*795d594fSAndroid Build Coastguard Worker if (!expected.equals(actual)) { 742*795d594fSAndroid Build Coastguard Worker throw new AssertionError("Expected: " + expected + ", Actual: " + actual); 743*795d594fSAndroid Build Coastguard Worker } 744*795d594fSAndroid Build Coastguard Worker } 745*795d594fSAndroid Build Coastguard Worker 746*795d594fSAndroid Build Coastguard Worker volatile int volatileField; 747*795d594fSAndroid Build Coastguard Worker int intField; 748*795d594fSAndroid Build Coastguard Worker int intField2; 749*795d594fSAndroid Build Coastguard Worker Object objectField; 750*795d594fSAndroid Build Coastguard Worker static boolean doThrow; 751*795d594fSAndroid Build Coastguard Worker static boolean doLoop; 752*795d594fSAndroid Build Coastguard Worker static boolean doEarlyReturn; 753*795d594fSAndroid Build Coastguard Worker static boolean doOtherEarlyReturn; 754*795d594fSAndroid Build Coastguard Worker static int staticIntField; 755*795d594fSAndroid Build Coastguard Worker static Main mainField = new Main(); 756*795d594fSAndroid Build Coastguard Worker static Object obj = new Object(); 757*795d594fSAndroid Build Coastguard Worker } 758