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