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