xref: /aosp_15_r20/art/test/639-checker-code-sinking/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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