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