xref: /aosp_15_r20/art/test/685-deoptimizeable/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2016 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 import java.lang.reflect.Method;
18*795d594fSAndroid Build Coastguard Worker import java.util.Arrays;
19*795d594fSAndroid Build Coastguard Worker import java.util.Comparator;
20*795d594fSAndroid Build Coastguard Worker import java.util.HashMap;
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker class SampleObject {
23*795d594fSAndroid Build Coastguard Worker     public static boolean sHashCodeInvoked = false;
24*795d594fSAndroid Build Coastguard Worker     private int i;
25*795d594fSAndroid Build Coastguard Worker 
SampleObject(int i)26*795d594fSAndroid Build Coastguard Worker     public SampleObject(int i) {
27*795d594fSAndroid Build Coastguard Worker         this.i = i;
28*795d594fSAndroid Build Coastguard Worker     }
29*795d594fSAndroid Build Coastguard Worker 
equals(Object obj)30*795d594fSAndroid Build Coastguard Worker     public boolean equals(Object obj) {
31*795d594fSAndroid Build Coastguard Worker         return (obj instanceof SampleObject) && (i == ((SampleObject)obj).i);
32*795d594fSAndroid Build Coastguard Worker     }
33*795d594fSAndroid Build Coastguard Worker 
hashCode()34*795d594fSAndroid Build Coastguard Worker     public int hashCode() {
35*795d594fSAndroid Build Coastguard Worker         sHashCodeInvoked = true;
36*795d594fSAndroid Build Coastguard Worker         Main.assertIsManaged();
37*795d594fSAndroid Build Coastguard Worker         Main.deoptimizeAll();
38*795d594fSAndroid Build Coastguard Worker         Main.assertIsInterpreted();
39*795d594fSAndroid Build Coastguard Worker         return i % 64;
40*795d594fSAndroid Build Coastguard Worker     }
41*795d594fSAndroid Build Coastguard Worker }
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker public class Main {
44*795d594fSAndroid Build Coastguard Worker     static boolean sFlag = false;
45*795d594fSAndroid Build Coastguard Worker 
deoptimizeAll()46*795d594fSAndroid Build Coastguard Worker     public static native void deoptimizeAll();
undeoptimizeAll()47*795d594fSAndroid Build Coastguard Worker     public static native void undeoptimizeAll();
assertIsInterpreted()48*795d594fSAndroid Build Coastguard Worker     public static native void assertIsInterpreted();
assertIsManaged()49*795d594fSAndroid Build Coastguard Worker     public static native void assertIsManaged();
assertCallerIsInterpreted()50*795d594fSAndroid Build Coastguard Worker     public static native void assertCallerIsInterpreted();
disableStackFrameAsserts()51*795d594fSAndroid Build Coastguard Worker     public static native void disableStackFrameAsserts();
hasJit()52*795d594fSAndroid Build Coastguard Worker     public static native boolean hasJit();
ensureJitCompiled(Class<?> itf, String method_name)53*795d594fSAndroid Build Coastguard Worker     private static native void ensureJitCompiled(Class<?> itf, String method_name);
54*795d594fSAndroid Build Coastguard Worker 
execute(Runnable runnable)55*795d594fSAndroid Build Coastguard Worker     public static void execute(Runnable runnable) throws Exception {
56*795d594fSAndroid Build Coastguard Worker       Thread t = new Thread(runnable);
57*795d594fSAndroid Build Coastguard Worker       t.start();
58*795d594fSAndroid Build Coastguard Worker       t.join();
59*795d594fSAndroid Build Coastguard Worker     }
60*795d594fSAndroid Build Coastguard Worker 
ensureAllJitCompiled()61*795d594fSAndroid Build Coastguard Worker     public static void ensureAllJitCompiled() {
62*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(HashMap.class, "hash");
63*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(Main.class, "$noinline$run1");
64*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(Main.class, "$noinline$run2");
65*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(Main.class, "$noinline$run3A");
66*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(Main.class, "$noinline$run3B");
67*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(SampleObject.class, "hashCode");
68*795d594fSAndroid Build Coastguard Worker     }
69*795d594fSAndroid Build Coastguard Worker 
main(String[] args)70*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
71*795d594fSAndroid Build Coastguard Worker         System.loadLibrary(args[0]);
72*795d594fSAndroid Build Coastguard Worker         // Only test stack frames in compiled mode.
73*795d594fSAndroid Build Coastguard Worker         if (!hasJit()) {
74*795d594fSAndroid Build Coastguard Worker           disableStackFrameAsserts();
75*795d594fSAndroid Build Coastguard Worker         }
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker         // Just declare a new int array so that the int arrays are resolved properly when JITing.
78*795d594fSAndroid Build Coastguard Worker         int[] tmp = new int[3];
79*795d594fSAndroid Build Coastguard Worker         ensureAllJitCompiled();
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker         final HashMap<SampleObject, Long> map = new HashMap<SampleObject, Long>();
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker         // Single-frame deoptimization that covers partial fragment.
84*795d594fSAndroid Build Coastguard Worker         execute(new Runnable() {
85*795d594fSAndroid Build Coastguard Worker             public void run() {
86*795d594fSAndroid Build Coastguard Worker                 ensureJitCompiled(this.getClass(), "runInternal");
87*795d594fSAndroid Build Coastguard Worker                 runInternal();
88*795d594fSAndroid Build Coastguard Worker             }
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker             public void runInternal() {
91*795d594fSAndroid Build Coastguard Worker                 int[] arr = new int[3];
92*795d594fSAndroid Build Coastguard Worker                 assertIsManaged();
93*795d594fSAndroid Build Coastguard Worker                 int res = $noinline$run1(arr);
94*795d594fSAndroid Build Coastguard Worker                 assertIsManaged();  // Only single frame is deoptimized.
95*795d594fSAndroid Build Coastguard Worker                 if (res != 79) {
96*795d594fSAndroid Build Coastguard Worker                     System.out.println("Failure 1!");
97*795d594fSAndroid Build Coastguard Worker                     System.exit(0);
98*795d594fSAndroid Build Coastguard Worker                 }
99*795d594fSAndroid Build Coastguard Worker             }
100*795d594fSAndroid Build Coastguard Worker         });
101*795d594fSAndroid Build Coastguard Worker 
102*795d594fSAndroid Build Coastguard Worker         // Single-frame deoptimization that covers a full fragment.
103*795d594fSAndroid Build Coastguard Worker         execute(new Runnable() {
104*795d594fSAndroid Build Coastguard Worker             public void run() {
105*795d594fSAndroid Build Coastguard Worker                 ensureJitCompiled(this.getClass(), "runInternal");
106*795d594fSAndroid Build Coastguard Worker                 runInternal();
107*795d594fSAndroid Build Coastguard Worker             }
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker             public void runInternal() {
110*795d594fSAndroid Build Coastguard Worker                 try {
111*795d594fSAndroid Build Coastguard Worker                     int[] arr = new int[3];
112*795d594fSAndroid Build Coastguard Worker                     assertIsManaged();
113*795d594fSAndroid Build Coastguard Worker                     // Use reflection to call $noinline$run2 so that it does
114*795d594fSAndroid Build Coastguard Worker                     // full-fragment deoptimization since that is an upcall.
115*795d594fSAndroid Build Coastguard Worker                     Class<?> cls = Class.forName("Main");
116*795d594fSAndroid Build Coastguard Worker                     Method method = cls.getDeclaredMethod("$noinline$run2", int[].class);
117*795d594fSAndroid Build Coastguard Worker                     double res = (double)method.invoke(Main.class, arr);
118*795d594fSAndroid Build Coastguard Worker                     assertIsManaged();  // Only single frame is deoptimized.
119*795d594fSAndroid Build Coastguard Worker                     if (res != 79.3d) {
120*795d594fSAndroid Build Coastguard Worker                         System.out.println("Failure 2!");
121*795d594fSAndroid Build Coastguard Worker                         System.exit(0);
122*795d594fSAndroid Build Coastguard Worker                     }
123*795d594fSAndroid Build Coastguard Worker                 } catch (Exception e) {
124*795d594fSAndroid Build Coastguard Worker                     e.printStackTrace(System.out);
125*795d594fSAndroid Build Coastguard Worker                 }
126*795d594fSAndroid Build Coastguard Worker             }
127*795d594fSAndroid Build Coastguard Worker         });
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker         // Full-fragment deoptimization.
130*795d594fSAndroid Build Coastguard Worker         execute(new Runnable() {
131*795d594fSAndroid Build Coastguard Worker             public void run() {
132*795d594fSAndroid Build Coastguard Worker                 ensureJitCompiled(this.getClass(), "runInternal");
133*795d594fSAndroid Build Coastguard Worker                 runInternal();
134*795d594fSAndroid Build Coastguard Worker             }
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker             public void runInternal() {
137*795d594fSAndroid Build Coastguard Worker                 assertIsManaged();
138*795d594fSAndroid Build Coastguard Worker                 float res = $noinline$run3B();
139*795d594fSAndroid Build Coastguard Worker                 assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
140*795d594fSAndroid Build Coastguard Worker                 if (res != 0.034f) {
141*795d594fSAndroid Build Coastguard Worker                     System.out.println("Failure 3!");
142*795d594fSAndroid Build Coastguard Worker                     System.exit(0);
143*795d594fSAndroid Build Coastguard Worker                 }
144*795d594fSAndroid Build Coastguard Worker             }
145*795d594fSAndroid Build Coastguard Worker         });
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker         undeoptimizeAll();  // Make compiled code useable again.
148*795d594fSAndroid Build Coastguard Worker         ensureAllJitCompiled();
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker         // Partial-fragment deoptimization.
151*795d594fSAndroid Build Coastguard Worker         execute(new Runnable() {
152*795d594fSAndroid Build Coastguard Worker             public void run() {
153*795d594fSAndroid Build Coastguard Worker                 ensureJitCompiled(this.getClass(), "runInternal");
154*795d594fSAndroid Build Coastguard Worker                 ensureJitCompiled(HashMap.class, "hash");
155*795d594fSAndroid Build Coastguard Worker                 runInternal();
156*795d594fSAndroid Build Coastguard Worker             }
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker             public void runInternal() {
159*795d594fSAndroid Build Coastguard Worker                 try {
160*795d594fSAndroid Build Coastguard Worker                     assertIsManaged();
161*795d594fSAndroid Build Coastguard Worker                     map.put(new SampleObject(10), Long.valueOf(100));
162*795d594fSAndroid Build Coastguard Worker                     assertIsInterpreted();  // Every deoptimizeable method is deoptimized.
163*795d594fSAndroid Build Coastguard Worker                 } catch (Exception e) {
164*795d594fSAndroid Build Coastguard Worker                     e.printStackTrace(System.out);
165*795d594fSAndroid Build Coastguard Worker                 }
166*795d594fSAndroid Build Coastguard Worker             }
167*795d594fSAndroid Build Coastguard Worker         });
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker         undeoptimizeAll();  // Make compiled code useable again.
170*795d594fSAndroid Build Coastguard Worker         ensureAllJitCompiled();
171*795d594fSAndroid Build Coastguard Worker 
172*795d594fSAndroid Build Coastguard Worker         if (!SampleObject.sHashCodeInvoked) {
173*795d594fSAndroid Build Coastguard Worker             System.out.println("hashCode() method not invoked!");
174*795d594fSAndroid Build Coastguard Worker         }
175*795d594fSAndroid Build Coastguard Worker         if (map.get(new SampleObject(10)) != 100) {
176*795d594fSAndroid Build Coastguard Worker             System.out.println("Wrong hashmap value!");
177*795d594fSAndroid Build Coastguard Worker         }
178*795d594fSAndroid Build Coastguard Worker         System.out.println("Finishing");
179*795d594fSAndroid Build Coastguard Worker     }
180*795d594fSAndroid Build Coastguard Worker 
$noinline$run1(int[] arr)181*795d594fSAndroid Build Coastguard Worker     public static int $noinline$run1(int[] arr) {
182*795d594fSAndroid Build Coastguard Worker         assertIsManaged();
183*795d594fSAndroid Build Coastguard Worker         // Prevent inlining.
184*795d594fSAndroid Build Coastguard Worker         if (sFlag) {
185*795d594fSAndroid Build Coastguard Worker             throw new Error();
186*795d594fSAndroid Build Coastguard Worker         }
187*795d594fSAndroid Build Coastguard Worker         boolean caught = false;
188*795d594fSAndroid Build Coastguard Worker         // BCE will use deoptimization for the code below.
189*795d594fSAndroid Build Coastguard Worker         try {
190*795d594fSAndroid Build Coastguard Worker             arr[0] = 1;
191*795d594fSAndroid Build Coastguard Worker             arr[1] = 1;
192*795d594fSAndroid Build Coastguard Worker             arr[2] = 1;
193*795d594fSAndroid Build Coastguard Worker             // This causes AIOOBE and triggers deoptimization from compiled code.
194*795d594fSAndroid Build Coastguard Worker             arr[3] = 1;
195*795d594fSAndroid Build Coastguard Worker         } catch (ArrayIndexOutOfBoundsException e) {
196*795d594fSAndroid Build Coastguard Worker             assertIsInterpreted(); // Single-frame deoptimization triggered.
197*795d594fSAndroid Build Coastguard Worker             caught = true;
198*795d594fSAndroid Build Coastguard Worker         }
199*795d594fSAndroid Build Coastguard Worker         if (!caught) {
200*795d594fSAndroid Build Coastguard Worker             System.out.println("Expected exception");
201*795d594fSAndroid Build Coastguard Worker         }
202*795d594fSAndroid Build Coastguard Worker         assertIsInterpreted();
203*795d594fSAndroid Build Coastguard Worker         return 79;
204*795d594fSAndroid Build Coastguard Worker     }
205*795d594fSAndroid Build Coastguard Worker 
$noinline$run2(int[] arr)206*795d594fSAndroid Build Coastguard Worker     public static double $noinline$run2(int[] arr) {
207*795d594fSAndroid Build Coastguard Worker         assertIsManaged();
208*795d594fSAndroid Build Coastguard Worker         // Prevent inlining.
209*795d594fSAndroid Build Coastguard Worker         if (sFlag) {
210*795d594fSAndroid Build Coastguard Worker             throw new Error();
211*795d594fSAndroid Build Coastguard Worker         }
212*795d594fSAndroid Build Coastguard Worker         boolean caught = false;
213*795d594fSAndroid Build Coastguard Worker         // BCE will use deoptimization for the code below.
214*795d594fSAndroid Build Coastguard Worker         try {
215*795d594fSAndroid Build Coastguard Worker             arr[0] = 1;
216*795d594fSAndroid Build Coastguard Worker             arr[1] = 1;
217*795d594fSAndroid Build Coastguard Worker             arr[2] = 1;
218*795d594fSAndroid Build Coastguard Worker             // This causes AIOOBE and triggers deoptimization from compiled code.
219*795d594fSAndroid Build Coastguard Worker             arr[3] = 1;
220*795d594fSAndroid Build Coastguard Worker         } catch (ArrayIndexOutOfBoundsException e) {
221*795d594fSAndroid Build Coastguard Worker             assertIsInterpreted();  // Single-frame deoptimization triggered.
222*795d594fSAndroid Build Coastguard Worker             caught = true;
223*795d594fSAndroid Build Coastguard Worker         }
224*795d594fSAndroid Build Coastguard Worker         if (!caught) {
225*795d594fSAndroid Build Coastguard Worker             System.out.println("Expected exception");
226*795d594fSAndroid Build Coastguard Worker         }
227*795d594fSAndroid Build Coastguard Worker         assertIsInterpreted();
228*795d594fSAndroid Build Coastguard Worker         return 79.3d;
229*795d594fSAndroid Build Coastguard Worker     }
230*795d594fSAndroid Build Coastguard Worker 
$noinline$run3A()231*795d594fSAndroid Build Coastguard Worker     public static float $noinline$run3A() {
232*795d594fSAndroid Build Coastguard Worker         assertIsManaged();
233*795d594fSAndroid Build Coastguard Worker         // Prevent inlining.
234*795d594fSAndroid Build Coastguard Worker         if (sFlag) {
235*795d594fSAndroid Build Coastguard Worker             throw new Error();
236*795d594fSAndroid Build Coastguard Worker         }
237*795d594fSAndroid Build Coastguard Worker         // Deoptimize callers.
238*795d594fSAndroid Build Coastguard Worker         deoptimizeAll();
239*795d594fSAndroid Build Coastguard Worker         assertIsInterpreted();
240*795d594fSAndroid Build Coastguard Worker         assertCallerIsInterpreted();  // $noinline$run3B is deoptimizeable.
241*795d594fSAndroid Build Coastguard Worker         return 0.034f;
242*795d594fSAndroid Build Coastguard Worker     }
243*795d594fSAndroid Build Coastguard Worker 
$noinline$run3B()244*795d594fSAndroid Build Coastguard Worker     public static float $noinline$run3B() {
245*795d594fSAndroid Build Coastguard Worker         assertIsManaged();
246*795d594fSAndroid Build Coastguard Worker         // Prevent inlining.
247*795d594fSAndroid Build Coastguard Worker         if (sFlag) {
248*795d594fSAndroid Build Coastguard Worker             throw new Error();
249*795d594fSAndroid Build Coastguard Worker         }
250*795d594fSAndroid Build Coastguard Worker         float res = $noinline$run3A();
251*795d594fSAndroid Build Coastguard Worker         assertIsInterpreted();
252*795d594fSAndroid Build Coastguard Worker         return res;
253*795d594fSAndroid Build Coastguard Worker     }
254*795d594fSAndroid Build Coastguard Worker }
255