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 26 public DummyObject(int i) { 27 this.i = i; 28 } 29 30 public boolean equals(Object obj) { 31 return (obj instanceof DummyObject) && (i == ((DummyObject)obj).i); 32 } 33 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 47 public static native void deoptimizeAll(); 48 public static native void undeoptimizeAll(); 49 public static native void assertIsInterpreted(); 50 public static native void assertIsManaged(); 51 public static native void assertCallerIsInterpreted(); 52 public static native void assertCallerIsManaged(); 53 public static native void disableStackFrameAsserts(); 54 public static native boolean hasOatFile(); 55 public static native boolean isInterpreted(); 56 57 public static void execute(Runnable runnable) throws Exception { 58 Thread t = new Thread(runnable); 59 t.start(); 60 t.join(); 61 } 62 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 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 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 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 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