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 we are running in non-JIT mode, or were unlucky enough to get this method 65 // already JITted, skip the wait for OSR code. 66 boolean interpreting = isInInterpreter("$noinline$returnInt"); 67 int i = 0; 68 for (; i < 100000; ++i) { 69 } 70 if (interpreting) { 71 while (!isInOsrCode("$noinline$returnInt")) {} 72 } 73 System.out.println(i); 74 return 53; 75 } 76 $noinline$returnFloat()77 public static float $noinline$returnFloat() { 78 // If we are running in non-JIT mode, or were unlucky enough to get this method 79 // already JITted, skip the wait for OSR code. 80 boolean interpreting = isInInterpreter("$noinline$returnFloat"); 81 int i = 0; 82 for (; i < 200000; ++i) { 83 } 84 if (interpreting) { 85 while (!isInOsrCode("$noinline$returnFloat")) {} 86 } 87 System.out.println(i); 88 return 42.2f; 89 } 90 $noinline$returnDouble()91 public static double $noinline$returnDouble() { 92 // If we are running in non-JIT mode, or were unlucky enough to get this method 93 // already JITted, skip the wait for OSR code. 94 boolean interpreting = isInInterpreter("$noinline$returnDouble"); 95 int i = 0; 96 for (; i < 300000; ++i) { 97 } 98 if (interpreting) { 99 while (!isInOsrCode("$noinline$returnDouble")) {} 100 } 101 System.out.println(i); 102 return Double.longBitsToDouble(0xF000000000001111L); 103 } 104 $noinline$returnLong()105 public static long $noinline$returnLong() { 106 // If we are running in non-JIT mode, or were unlucky enough to get this method 107 // already JITted, skip the wait for OSR code. 108 boolean interpreting = isInInterpreter("$noinline$returnLong"); 109 int i = 0; 110 for (; i < 400000; ++i) { 111 } 112 if (interpreting) { 113 while (!isInOsrCode("$noinline$returnLong")) {} 114 } 115 System.out.println(i); 116 return 0xFFFF000000001111L; 117 } 118 $noinline$deopt()119 public static void $noinline$deopt() { 120 // If we are running in non-JIT mode, or were unlucky enough to get this method 121 // already JITted, skip the wait for OSR code. 122 boolean interpreting = isInInterpreter("$noinline$deopt"); 123 int i = 0; 124 for (; i < 100000; ++i) { 125 } 126 if (interpreting) { 127 while (!isInOsrCode("$noinline$deopt")) {} 128 } 129 DeoptimizationController.startDeoptimization(); 130 } 131 $noinline$inlineCache(Main m, boolean isSecondInvocation)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 $noinline$inlineCache2(Main m, boolean isSecondInvocation)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 $noinline$inlineCache3(Main m, boolean isSecondInvocation)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 inlineCache()220 public Main inlineCache() { 221 return new Main(); 222 } 223 inlineCache2()224 public Main inlineCache2() { 225 return null; 226 } 227 inlineCache3()228 public Main inlineCache3() { 229 return null; 230 } 231 returnClass()232 public Class<?> returnClass() { 233 return Main.class; 234 } 235 otherInlineCache()236 public void otherInlineCache() { 237 return; 238 } 239 $noinline$stackOverflow(Main m, boolean isSecondInvocation)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 $opt$noinline$testOsrInlineLoop(String[] args)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 assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5)); 266 // Since we cannot have a loop directly in this method, we need to force the OSR 267 // compilation from native code. 268 ensureHasProfilingInfo("$opt$noinline$testOsrInlineLoop"); 269 ensureHasOsrCode("$opt$noinline$testOsrInlineLoop"); 270 } 271 $opt$inline$testRemoveSuspendCheck(int x, int y)272 public static int $opt$inline$testRemoveSuspendCheck(int x, int y) { 273 // For this test we need an inlined loop and have DCE re-run loop analysis 274 // after inlining. 275 while (y > 0) { 276 while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) { 277 x++; 278 } 279 y--; 280 } 281 return x; 282 } 283 $opt$inline$inlineTrue()284 public static boolean $opt$inline$inlineTrue() { 285 return true; 286 } 287 $opt$inline$inlineFalse()288 public static boolean $opt$inline$inlineFalse() { 289 return false; 290 } 291 assertIntEquals(int expected, int result)292 public static void assertIntEquals(int expected, int result) { 293 if (expected != result) { 294 throw new Error("Expected: " + expected + ", found: " + result); 295 } 296 } 297 isInOsrCode(String methodName)298 public static native boolean isInOsrCode(String methodName); isInInterpreter(String methodName)299 public static native boolean isInInterpreter(String methodName); ensureHasProfilingInfo(String methodName)300 public static native void ensureHasProfilingInfo(String methodName); ensureHasOsrCode(String methodName)301 public static native void ensureHasOsrCode(String methodName); 302 } 303 304 class SubMain extends Main { returnClass()305 public Class<?> returnClass() { 306 return SubMain.class; 307 } 308 inlineCache()309 public Main inlineCache() { 310 return new SubMain(); 311 } 312 inlineCache2()313 public Main inlineCache2() { 314 return new SubMain(); 315 } 316 otherInlineCache()317 public void otherInlineCache() { 318 return; 319 } 320 } 321