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