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 17public class Main { 18 public static void main(String[] args) { 19 System.loadLibrary(args[0]); 20 Thread testThread = new Thread() { 21 public void run() { 22 performTest(); 23 } 24 }; 25 testThread.start(); 26 try { 27 testThread.join(20 * 1000); // 20s timeout. 28 } catch (InterruptedException ie) { 29 System.out.println("Interrupted."); 30 System.exit(1); 31 } 32 Thread.State state = testThread.getState(); 33 if (state != Thread.State.TERMINATED) { 34 System.out.println("Test timed out, current state: " + state); 35 System.exit(1); 36 } 37 } 38 39 public static void performTest() { 40 new SubMain(); 41 if ($noinline$returnInt() != 53) { 42 throw new Error("Unexpected return value"); 43 } 44 if ($noinline$returnFloat() != 42.2f) { 45 throw new Error("Unexpected return value"); 46 } 47 if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) { 48 throw new Error("Unexpected return value "); 49 } 50 if ($noinline$returnLong() != 0xFFFF000000001111L) { 51 throw new Error("Unexpected return value"); 52 } 53 54 try { 55 $noinline$deopt(); 56 } catch (Exception e) {} 57 DeoptimizationController.stopDeoptimization(); 58 59 $noinline$inlineCache(new Main(), /* isSecondInvocation */ false); 60 if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) { 61 throw new Error("Unexpected return value"); 62 } 63 64 $noinline$inlineCache2(new Main(), /* isSecondInvocation */ false); 65 if ($noinline$inlineCache2(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) { 66 throw new Error("Unexpected return value"); 67 } 68 69 // Test polymorphic inline cache to the same target (inlineCache3). 70 $noinline$inlineCache3(new Main(), /* isSecondInvocation */ false); 71 $noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ false); 72 if ($noinline$inlineCache3(new SubMain(), /* isSecondInvocation */ true) != null) { 73 throw new Error("Unexpected return value"); 74 } 75 76 $noinline$stackOverflow(new Main(), /* isSecondInvocation */ false); 77 $noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true); 78 79 $opt$noinline$testOsrInlineLoop(null); 80 System.out.println("b28210356 passed."); 81 } 82 83 public static int $noinline$returnInt() { 84 if (doThrow) throw new Error(""); 85 int i = 0; 86 for (; i < 100000; ++i) { 87 } 88 while (!isInOsrCode("$noinline$returnInt")) {} 89 System.out.println(i); 90 return 53; 91 } 92 93 public static float $noinline$returnFloat() { 94 if (doThrow) throw new Error(""); 95 int i = 0; 96 for (; i < 200000; ++i) { 97 } 98 while (!isInOsrCode("$noinline$returnFloat")) {} 99 System.out.println(i); 100 return 42.2f; 101 } 102 103 public static double $noinline$returnDouble() { 104 if (doThrow) throw new Error(""); 105 int i = 0; 106 for (; i < 300000; ++i) { 107 } 108 while (!isInOsrCode("$noinline$returnDouble")) {} 109 System.out.println(i); 110 return Double.longBitsToDouble(0xF000000000001111L); 111 } 112 113 public static long $noinline$returnLong() { 114 if (doThrow) throw new Error(""); 115 int i = 0; 116 for (; i < 400000; ++i) { 117 } 118 while (!isInOsrCode("$noinline$returnLong")) {} 119 System.out.println(i); 120 return 0xFFFF000000001111L; 121 } 122 123 public static void $noinline$deopt() { 124 if (doThrow) throw new Error(""); 125 int i = 0; 126 for (; i < 100000; ++i) { 127 } 128 while (!isInOsrCode("$noinline$deopt")) {} 129 DeoptimizationController.startDeoptimization(); 130 } 131 132 public static Class $noinline$inlineCache(Main m, boolean isSecondInvocation) { 133 // If we are running in non-JIT mode, or were unlucky enough to get this method 134 // already JITted, just return the expected value. 135 if (!isInInterpreter("$noinline$inlineCache")) { 136 return SubMain.class; 137 } 138 139 ensureHasProfilingInfo("$noinline$inlineCache"); 140 141 // Ensure that we have OSR code to jump to. 142 if (isSecondInvocation) { 143 ensureHasOsrCode("$noinline$inlineCache"); 144 } 145 146 // This call will be optimized in the OSR compiled code 147 // to check and deoptimize if m is not of type 'Main'. 148 Main other = m.inlineCache(); 149 150 // Jump to OSR compiled code. The second run 151 // of this method will have 'm' as a SubMain, and the compiled 152 // code we are jumping to will have wrongly optimize other as being a 153 // 'Main'. 154 if (isSecondInvocation) { 155 while (!isInOsrCode("$noinline$inlineCache")) {} 156 } 157 158 // We used to wrongly optimize this call and assume 'other' was a 'Main'. 159 return other.returnClass(); 160 } 161 162 public static Class $noinline$inlineCache2(Main m, boolean isSecondInvocation) { 163 // If we are running in non-JIT mode, or were unlucky enough to get this method 164 // already JITted, just return the expected value. 165 if (!isInInterpreter("$noinline$inlineCache2")) { 166 return SubMain.class; 167 } 168 169 ensureHasProfilingInfo("$noinline$inlineCache2"); 170 171 // Ensure that we have OSR code to jump to. 172 if (isSecondInvocation) { 173 ensureHasOsrCode("$noinline$inlineCache2"); 174 } 175 176 // This call will be optimized in the OSR compiled code 177 // to check and deoptimize if m is not of type 'Main'. 178 Main other = m.inlineCache2(); 179 180 // Jump to OSR compiled code. The second run 181 // of this method will have 'm' as a SubMain, and the compiled 182 // code we are jumping to will have wrongly optimize other as being null. 183 if (isSecondInvocation) { 184 while (!isInOsrCode("$noinline$inlineCache2")) {} 185 } 186 187 // We used to wrongly optimize this code and assume 'other' was always null. 188 return (other == null) ? null : other.returnClass(); 189 } 190 191 public static Class $noinline$inlineCache3(Main m, boolean isSecondInvocation) { 192 // If we are running in non-JIT mode, or were unlucky enough to get this method 193 // already JITted, just return the expected value. 194 if (!isInInterpreter("$noinline$inlineCache3")) { 195 return null; 196 } 197 198 ensureHasProfilingInfo("$noinline$inlineCache3"); 199 200 // Ensure that we have OSR code to jump to. 201 if (isSecondInvocation) { 202 ensureHasOsrCode("$noinline$inlineCache3"); 203 } 204 205 // This call will be optimized in the OSR compiled code 206 // to check and deoptimize if m is not of type 'Main'. 207 Main other = m.inlineCache3(); 208 209 // Jump to OSR compiled code. The second run 210 // of this method will have 'm' as a SubMain, and the compiled 211 // code we are jumping to will have wrongly optimize other as being null. 212 if (isSecondInvocation) { 213 while (!isInOsrCode("$noinline$inlineCache3")) {} 214 } 215 216 // We used to wrongly optimize this code and assume 'other' was always null. 217 return (other == null) ? null : other.returnClass(); 218 } 219 220 public Main inlineCache() { 221 return new Main(); 222 } 223 224 public Main inlineCache2() { 225 return null; 226 } 227 228 public Main inlineCache3() { 229 return null; 230 } 231 232 public Class returnClass() { 233 return Main.class; 234 } 235 236 public void otherInlineCache() { 237 return; 238 } 239 240 public static void $noinline$stackOverflow(Main m, boolean isSecondInvocation) { 241 // If we are running in non-JIT mode, or were unlucky enough to get this method 242 // already JITted, just return the expected value. 243 if (!isInInterpreter("$noinline$stackOverflow")) { 244 return; 245 } 246 247 // We need a ProfilingInfo object to populate the 'otherInlineCache' call. 248 ensureHasProfilingInfo("$noinline$stackOverflow"); 249 250 if (isSecondInvocation) { 251 // Ensure we have an OSR code and we jump to it. 252 while (!isInOsrCode("$noinline$stackOverflow")) {} 253 } 254 255 for (int i = 0; i < (isSecondInvocation ? 10000000 : 1); ++i) { 256 // The first invocation of $noinline$stackOverflow will populate the inline 257 // cache with Main. The second invocation of the method, will see a SubMain 258 // and will therefore trigger deoptimization. 259 m.otherInlineCache(); 260 } 261 } 262 263 public static void $opt$noinline$testOsrInlineLoop(String[] args) { 264 // Regression test for inlining a method with a loop to a method without a loop in OSR mode. 265 if (doThrow) throw new Error(); 266 assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5)); 267 // Since we cannot have a loop directly in this method, we need to force the OSR 268 // compilation from native code. 269 ensureHasProfilingInfo("$opt$noinline$testOsrInlineLoop"); 270 ensureHasOsrCode("$opt$noinline$testOsrInlineLoop"); 271 } 272 273 public static int $opt$inline$testRemoveSuspendCheck(int x, int y) { 274 // For this test we need an inlined loop and have DCE re-run loop analysis 275 // after inlining. 276 while (y > 0) { 277 while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) { 278 x++; 279 } 280 y--; 281 } 282 return x; 283 } 284 285 public static boolean $opt$inline$inlineTrue() { 286 return true; 287 } 288 289 public static boolean $opt$inline$inlineFalse() { 290 return false; 291 } 292 293 public static void assertIntEquals(int expected, int result) { 294 if (expected != result) { 295 throw new Error("Expected: " + expected + ", found: " + result); 296 } 297 } 298 299 public static native boolean isInOsrCode(String methodName); 300 public static native boolean isInInterpreter(String methodName); 301 public static native void ensureHasProfilingInfo(String methodName); 302 public static native void ensureHasOsrCode(String methodName); 303 304 public static boolean doThrow = false; 305} 306 307class SubMain extends Main { 308 public Class returnClass() { 309 return SubMain.class; 310 } 311 312 public Main inlineCache() { 313 return new SubMain(); 314 } 315 316 public Main inlineCache2() { 317 return new SubMain(); 318 } 319 320 public void otherInlineCache() { 321 return; 322 } 323} 324