blob: 41dcfd1051f0ec5447079872bf8478ea051e9cd3 [file] [log] [blame]
Nicolas Geoffray386db1a2018-10-04 12:57:52 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.lang.reflect.Method;
18import java.util.Arrays;
19import java.util.Comparator;
20import java.util.HashMap;
21
Orion Hodson2731eb42020-07-24 12:10:12 +010022class SampleObject {
Nicolas Geoffray386db1a2018-10-04 12:57:52 +010023 public static boolean sHashCodeInvoked = false;
24 private int i;
25
Orion Hodson2731eb42020-07-24 12:10:12 +010026 public SampleObject(int i) {
Nicolas Geoffray386db1a2018-10-04 12:57:52 +010027 this.i = i;
28 }
29
30 public boolean equals(Object obj) {
Orion Hodson2731eb42020-07-24 12:10:12 +010031 return (obj instanceof SampleObject) && (i == ((SampleObject)obj).i);
Nicolas Geoffray386db1a2018-10-04 12:57:52 +010032 }
33
34 public int hashCode() {
35 sHashCodeInvoked = true;
36 Main.assertIsManaged();
37 Main.deoptimizeAll();
38 Main.assertIsInterpreted();
39 return i % 64;
40 }
41}
42
43public class Main {
44 static boolean sFlag = false;
45
46 public static native void deoptimizeAll();
47 public static native void undeoptimizeAll();
48 public static native void assertIsInterpreted();
49 public static native void assertIsManaged();
50 public static native void assertCallerIsInterpreted();
51 public static native void disableStackFrameAsserts();
52 public static native boolean hasJit();
53 private static native void ensureJitCompiled(Class<?> itf, String method_name);
54
55 public static void execute(Runnable runnable) throws Exception {
56 Thread t = new Thread(runnable);
57 t.start();
58 t.join();
59 }
60
61 public static void ensureAllJitCompiled() {
62 ensureJitCompiled(HashMap.class, "hash");
63 ensureJitCompiled(Main.class, "$noinline$run1");
64 ensureJitCompiled(Main.class, "$noinline$run2");
65 ensureJitCompiled(Main.class, "$noinline$run3A");
66 ensureJitCompiled(Main.class, "$noinline$run3B");
Orion Hodson2731eb42020-07-24 12:10:12 +010067 ensureJitCompiled(SampleObject.class, "hashCode");
Nicolas Geoffray386db1a2018-10-04 12:57:52 +010068 }
69
70 public static void main(String[] args) throws Exception {
71 System.loadLibrary(args[0]);
72 // Only test stack frames in compiled mode.
73 if (!hasJit()) {
74 disableStackFrameAsserts();
75 }
76
77 ensureAllJitCompiled();
78
Orion Hodson2731eb42020-07-24 12:10:12 +010079 final HashMap<SampleObject, Long> map = new HashMap<SampleObject, Long>();
Nicolas Geoffray386db1a2018-10-04 12:57:52 +010080
81 // Single-frame deoptimization that covers partial fragment.
82 execute(new Runnable() {
83 public void run() {
84 ensureJitCompiled(this.getClass(), "runInternal");
85 runInternal();
86 }
87
88 public void runInternal() {
89 int[] arr = new int[3];
90 assertIsManaged();
91 int res = $noinline$run1(arr);
92 assertIsManaged(); // Only single frame is deoptimized.
93 if (res != 79) {
94 System.out.println("Failure 1!");
95 System.exit(0);
96 }
97 }
98 });
99
100 // Single-frame deoptimization that covers a full fragment.
101 execute(new Runnable() {
102 public void run() {
103 ensureJitCompiled(this.getClass(), "runInternal");
104 runInternal();
105 }
106
107 public void runInternal() {
108 try {
109 int[] arr = new int[3];
110 assertIsManaged();
111 // Use reflection to call $noinline$run2 so that it does
112 // full-fragment deoptimization since that is an upcall.
113 Class<?> cls = Class.forName("Main");
114 Method method = cls.getDeclaredMethod("$noinline$run2", int[].class);
115 double res = (double)method.invoke(Main.class, arr);
116 assertIsManaged(); // Only single frame is deoptimized.
117 if (res != 79.3d) {
118 System.out.println("Failure 2!");
119 System.exit(0);
120 }
121 } catch (Exception e) {
122 e.printStackTrace(System.out);
123 }
124 }
125 });
126
127 // Full-fragment deoptimization.
128 execute(new Runnable() {
129 public void run() {
130 ensureJitCompiled(this.getClass(), "runInternal");
131 runInternal();
132 }
133
134 public void runInternal() {
135 assertIsManaged();
136 float res = $noinline$run3B();
137 assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
138 if (res != 0.034f) {
139 System.out.println("Failure 3!");
140 System.exit(0);
141 }
142 }
143 });
144
145 undeoptimizeAll(); // Make compiled code useable again.
146 ensureAllJitCompiled();
147
148 // Partial-fragment deoptimization.
149 execute(new Runnable() {
150 public void run() {
151 ensureJitCompiled(this.getClass(), "runInternal");
152 ensureJitCompiled(HashMap.class, "hash");
153 runInternal();
154 }
155
156 public void runInternal() {
157 try {
158 assertIsManaged();
Orion Hodson2731eb42020-07-24 12:10:12 +0100159 map.put(new SampleObject(10), Long.valueOf(100));
Nicolas Geoffray386db1a2018-10-04 12:57:52 +0100160 assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
161 } catch (Exception e) {
162 e.printStackTrace(System.out);
163 }
164 }
165 });
166
167 undeoptimizeAll(); // Make compiled code useable again.
168 ensureAllJitCompiled();
169
Orion Hodson2731eb42020-07-24 12:10:12 +0100170 if (!SampleObject.sHashCodeInvoked) {
Nicolas Geoffray386db1a2018-10-04 12:57:52 +0100171 System.out.println("hashCode() method not invoked!");
172 }
Orion Hodson2731eb42020-07-24 12:10:12 +0100173 if (map.get(new SampleObject(10)) != 100) {
Nicolas Geoffray386db1a2018-10-04 12:57:52 +0100174 System.out.println("Wrong hashmap value!");
175 }
176 System.out.println("Finishing");
177 }
178
179 public static int $noinline$run1(int[] arr) {
180 assertIsManaged();
181 // Prevent inlining.
182 if (sFlag) {
183 throw new Error();
184 }
185 boolean caught = false;
186 // BCE will use deoptimization for the code below.
187 try {
188 arr[0] = 1;
189 arr[1] = 1;
190 arr[2] = 1;
191 // This causes AIOOBE and triggers deoptimization from compiled code.
192 arr[3] = 1;
193 } catch (ArrayIndexOutOfBoundsException e) {
194 assertIsInterpreted(); // Single-frame deoptimization triggered.
195 caught = true;
196 }
197 if (!caught) {
198 System.out.println("Expected exception");
199 }
200 assertIsInterpreted();
201 return 79;
202 }
203
204 public static double $noinline$run2(int[] arr) {
205 assertIsManaged();
206 // Prevent inlining.
207 if (sFlag) {
208 throw new Error();
209 }
210 boolean caught = false;
211 // BCE will use deoptimization for the code below.
212 try {
213 arr[0] = 1;
214 arr[1] = 1;
215 arr[2] = 1;
216 // This causes AIOOBE and triggers deoptimization from compiled code.
217 arr[3] = 1;
218 } catch (ArrayIndexOutOfBoundsException e) {
219 assertIsInterpreted(); // Single-frame deoptimization triggered.
220 caught = true;
221 }
222 if (!caught) {
223 System.out.println("Expected exception");
224 }
225 assertIsInterpreted();
226 return 79.3d;
227 }
228
229 public static float $noinline$run3A() {
230 assertIsManaged();
231 // Prevent inlining.
232 if (sFlag) {
233 throw new Error();
234 }
235 // Deoptimize callers.
236 deoptimizeAll();
237 assertIsInterpreted();
238 assertCallerIsInterpreted(); // $noinline$run3B is deoptimizeable.
239 return 0.034f;
240 }
241
242 public static float $noinline$run3B() {
243 assertIsManaged();
244 // Prevent inlining.
245 if (sFlag) {
246 throw new Error();
247 }
248 float res = $noinline$run3A();
249 assertIsInterpreted();
250 return res;
251 }
252}