1 /* 2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package compiler.valhalla.valuetypes; 25 26 import compiler.whitebox.CompilerWhiteBoxTest; 27 import jdk.test.lib.Asserts; 28 import jdk.test.lib.management.InputArguments; 29 import jdk.test.lib.Platform; 30 import jdk.test.lib.process.ProcessTools; 31 import jdk.test.lib.process.OutputAnalyzer; 32 import jdk.test.lib.Utils; 33 import sun.hotspot.WhiteBox; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 import java.lang.annotation.Repeatable; 38 import java.lang.invoke.*; 39 import java.lang.reflect.Method; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.Hashtable; 43 import java.util.LinkedHashMap; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.regex.Matcher; 47 import java.util.regex.Pattern; 48 import java.util.TreeMap; 49 50 // Mark method as test 51 @Retention(RetentionPolicy.RUNTIME) 52 @Repeatable(Tests.class) 53 @interface Test { 54 // Regular expression used to match forbidden IR nodes 55 // in the C2 IR emitted for this test. 56 String failOn() default ""; 57 // Regular expressions used to match and count IR nodes. 58 String[] match() default { }; 59 int[] matchCount() default { }; 60 int compLevel() default ValueTypeTest.COMP_LEVEL_ANY; 61 int valid() default ValueTypeTest.AllFlags; 62 } 63 64 @Retention(RetentionPolicy.RUNTIME) 65 @interface Tests { 66 Test[] value(); 67 } 68 69 // Force method inlining during compilation 70 @Retention(RetentionPolicy.RUNTIME) 71 @interface ForceInline { } 72 73 // Prevent method inlining during compilation 74 @Retention(RetentionPolicy.RUNTIME) 75 @interface DontInline { } 76 77 // Prevent method compilation 78 @Retention(RetentionPolicy.RUNTIME) 79 @interface DontCompile { } 80 81 // Force method compilation 82 @Retention(RetentionPolicy.RUNTIME) 83 @interface ForceCompile { 84 int compLevel() default ValueTypeTest.COMP_LEVEL_ANY; 85 } 86 87 // Number of warmup iterations 88 @Retention(RetentionPolicy.RUNTIME) 89 @interface Warmup { 90 int value(); 91 } 92 93 public abstract class ValueTypeTest { 94 // Run "jtreg -Dtest.c1=true" to enable experimental C1 testing. This forces all 95 // compilable methods to be compiled with C1, regardless of the @Test(compLevel=?) setting. 96 static final boolean TEST_C1 = Boolean.getBoolean("test.c1"); 97 98 // Should we execute tests that assume (ValueType[] <: Object[])? 99 static final boolean ENABLE_VALUE_ARRAY_COVARIANCE = Boolean.getBoolean("ValueArrayCovariance"); 100 101 // Random test values 102 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 103 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 104 105 // User defined settings 106 protected static final boolean XCOMP = Platform.isComp(); 107 private static final boolean PRINT_GRAPH = true; 108 private static final boolean VERBOSE = Boolean.parseBoolean(System.getProperty("Verbose", "false")); 109 private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false")); 110 private static boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")) && !TEST_C1 && !XCOMP; 111 private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false")); 112 private static final String SCENARIOS = System.getProperty("Scenarios", ""); 113 private static final String TESTLIST = System.getProperty("Testlist", ""); 114 private static final String EXCLUDELIST = System.getProperty("Exclude", ""); 115 private static final int WARMUP = Integer.parseInt(System.getProperty("Warmup", "251")); 116 private static final boolean DUMP_REPLAY = Boolean.parseBoolean(System.getProperty("DumpReplay", "false")); 117 118 // Pre-defined settings 119 private static final String[] defaultFlags = { 120 "-XX:-BackgroundCompilation", "-XX:CICompilerCount=1", 121 "-XX:CompileCommand=quiet", 122 "-XX:CompileCommand=compileonly,java.lang.invoke.*::*", 123 "-XX:CompileCommand=compileonly,java.lang.Long::sum", 124 "-XX:CompileCommand=compileonly,java.lang.Object::<init>", 125 "-XX:CompileCommand=inline,compiler.valhalla.valuetypes.MyValue*::<init>", 126 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.*::*"}; 127 private static final String[] printFlags = { 128 "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintOptoAssembly"}; 129 private static final String[] verifyFlags = { 130 "-XX:+VerifyOops", "-XX:+VerifyStack", "-XX:+VerifyLastFrame", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC", 131 "-XX:+VerifyDuringGC", "-XX:+VerifyAdapterSharing"}; 132 133 protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 134 protected static final int ValueTypePassFieldsAsArgsOn = 0x1; 135 protected static final int ValueTypePassFieldsAsArgsOff = 0x2; 136 protected static final int ValueTypeArrayFlattenOn = 0x4; 137 protected static final int ValueTypeArrayFlattenOff = 0x8; 138 protected static final int ValueTypeReturnedAsFieldsOn = 0x10; 139 protected static final int ValueTypeReturnedAsFieldsOff = 0x20; 140 protected static final int AlwaysIncrementalInlineOn = 0x40; 141 protected static final int AlwaysIncrementalInlineOff = 0x80; 142 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn; 143 protected static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 144 protected static final boolean ValueTypeArrayFlatten = (WHITE_BOX.getIntxVMFlag("ValueArrayElemMaxFlatSize") == -1); // FIXME - fix this if default of ValueArrayElemMaxFlatSize is changed 145 protected static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields"); 146 protected static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline"); 147 protected static final long TieredStopAtLevel = (Long)WHITE_BOX.getVMFlag("TieredStopAtLevel"); 148 protected static final int COMP_LEVEL_ANY = -2; 149 protected static final int COMP_LEVEL_ALL = -2; 150 protected static final int COMP_LEVEL_AOT = -1; 151 protected static final int COMP_LEVEL_NONE = 0; 152 protected static final int COMP_LEVEL_SIMPLE = 1; // C1 153 protected static final int COMP_LEVEL_LIMITED_PROFILE = 2; // C1, invocation & backedge counters 154 protected static final int COMP_LEVEL_FULL_PROFILE = 3; // C1, invocation & backedge counters + mdo 155 protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; // C2 or JVMCI 156 157 protected static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 158 protected static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 159 protected static final boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 160 161 // Regular expressions used to match nodes in the PrintIdeal output 162 protected static final String START = "(\\d+\\t(.*"; 163 protected static final String MID = ".*)+\\t===.*"; 164 protected static final String END = ")|"; 165 protected static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END; 166 protected static final String ALLOCA = "(.*precise klass \\[Lcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END; 167 protected static final String LOAD = START + "Load(B|S|I|L|F|D|P|N)" + MID + "@compiler/valhalla/valuetypes/MyValue.*" + END; 168 protected static final String LOADK = START + "LoadK" + MID + END; 169 protected static final String STORE = START + "Store(B|C|S|I|L|F|D|P|N)" + MID + "@compiler/valhalla/valuetypes/MyValue.*" + END; 170 protected static final String LOOP = START + "Loop" + MID + "" + END; 171 protected static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END; 172 protected static final String RETURN = START + "Return" + MID + "returns" + END; 173 protected static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END; 174 protected static final String NPE = START + "CallStaticJava" + MID + "null_check" + END; 175 protected static final String CALL = START + "CallStaticJava" + MID + END; 176 protected static final String STOREVALUETYPEFIELDS = START + "CallStaticJava" + MID + "store_value_type_fields" + END; 177 protected static final String SCOBJ = "(.*# ScObj.*" + END; 178 179 public static String[] concat(String prefix[], String... extra) { 180 ArrayList<String> list = new ArrayList<String>(); 181 if (prefix != null) { 182 for (String s : prefix) { 183 list.add(s); 184 } 185 } 186 if (extra != null) { 187 for (String s : extra) { 188 list.add(s); 189 } 190 } 191 192 return list.toArray(new String[list.size()]); 193 } 194 195 /** 196 * Override getNumScenarios and getVMParameters if you want to run with more than 197 * the 5 built-in scenarios 198 */ 199 public int getNumScenarios() { 200 if (TEST_C1) { 201 return 1; 202 } else { 203 return 6; 204 } 205 } 206 207 /** 208 * VM paramaters for the 5 built-in test scenarios. If your test needs to append 209 * extra parameters for (some of) these scenarios, override getExtraVMParameters(). 210 */ 211 public String[] getVMParameters(int scenario) { 212 if (TEST_C1) { 213 return new String[] { 214 "-XX:+EnableValhallaC1", 215 "-XX:TieredStopAtLevel=1", 216 "-XX:-ValueTypePassFieldsAsArgs", 217 "-XX:-ValueTypeReturnedAsFields" 218 }; 219 } 220 221 switch (scenario) { 222 case 0: return new String[] { 223 "-XX:+AlwaysIncrementalInline", 224 "-XX:ValueArrayElemMaxFlatOops=-1", 225 "-XX:ValueArrayElemMaxFlatSize=-1", 226 "-XX:ValueFieldMaxFlatSize=-1", 227 "-XX:+ValueTypePassFieldsAsArgs", 228 "-XX:+ValueTypeReturnedAsFields"}; 229 case 1: return new String[] { 230 "-XX:-UseCompressedOops", 231 "-XX:ValueArrayElemMaxFlatOops=-1", 232 "-XX:ValueArrayElemMaxFlatSize=-1", 233 "-XX:ValueFieldMaxFlatSize=-1", 234 "-XX:-ValueTypePassFieldsAsArgs", 235 "-XX:-ValueTypeReturnedAsFields"}; 236 case 2: return new String[] { 237 "-DVerifyIR=false", 238 "-XX:-UseCompressedOops", 239 "-XX:ValueArrayElemMaxFlatOops=0", 240 "-XX:ValueArrayElemMaxFlatSize=0", 241 "-XX:ValueFieldMaxFlatSize=0", 242 "-XX:+ValueTypePassFieldsAsArgs", 243 "-XX:+ValueTypeReturnedAsFields", 244 "-XX:+StressValueTypeReturnedAsFields"}; 245 case 3: return new String[] { 246 "-DVerifyIR=false", 247 "-XX:+AlwaysIncrementalInline", 248 "-XX:-ValueTypePassFieldsAsArgs", 249 "-XX:-ValueTypeReturnedAsFields"}; 250 case 4: return new String[] { 251 "-DVerifyIR=false", 252 "-XX:ValueArrayElemMaxFlatOops=-1", 253 "-XX:ValueArrayElemMaxFlatSize=-1", 254 "-XX:ValueFieldMaxFlatSize=0", 255 "-XX:+ValueTypePassFieldsAsArgs", 256 "-XX:-ValueTypeReturnedAsFields"}; 257 case 5: return new String[] { 258 "-XX:+AlwaysIncrementalInline", 259 "-XX:ValueArrayElemMaxFlatOops=-1", 260 "-XX:ValueArrayElemMaxFlatSize=-1", 261 "-XX:ValueFieldMaxFlatSize=-1", 262 "-XX:-ValueTypePassFieldsAsArgs", 263 "-XX:-ValueTypeReturnedAsFields"}; 264 } 265 266 return null; 267 } 268 269 /** 270 * Override this method to provide extra parameters for selected scenarios 271 */ 272 public String[] getExtraVMParameters(int scenario) { 273 return null; 274 } 275 276 public static void main(String[] args) throws Throwable { 277 if (args.length != 1) { 278 throw new RuntimeException("Usage: @run main/othervm/timeout=120 -Xbootclasspath/a:." + 279 " -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions" + 280 " -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla" + 281 " compiler.valhalla.valuetypes.ValueTypeTest <YourTestMainClass>"); 282 } 283 String testMainClassName = args[0]; 284 Class testMainClass = Class.forName(testMainClassName); 285 ValueTypeTest test = (ValueTypeTest)testMainClass.newInstance(); 286 List<String> scenarios = null; 287 if (!SCENARIOS.isEmpty()) { 288 scenarios = Arrays.asList(SCENARIOS.split(",")); 289 } 290 for (int i=0; i<test.getNumScenarios(); i++) { 291 if (scenarios == null || scenarios.contains(Integer.toString(i))) { 292 System.out.println("Scenario #" + i + " -------- "); 293 String[] cmds = InputArguments.getVmInputArgs(); 294 cmds = concat(cmds, test.getVMParameters(i)); 295 cmds = concat(cmds, test.getExtraVMParameters(i)); 296 cmds = concat(cmds, testMainClassName); 297 298 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 299 String output = oa.getOutput(); 300 oa.shouldHaveExitValue(0); 301 System.out.println(output); 302 } else { 303 System.out.println("Scenario #" + i + " is skipped due to -Dscenarios=" + SCENARIOS); 304 } 305 } 306 } 307 308 // To exclude test cases, use -DExclude=<case1>,<case2>,... 309 // Each case can be just the method name, or can be <class>.<method>. The latter form is useful 310 // when you are running several tests at the same time. 311 // 312 // jtreg -DExclude=test12 TestArrays.java 313 // jtreg -DExclude=test34 TestLWorld.java 314 // -- or -- 315 // jtreg -DExclude=TestArrays.test12,TestLWorld.test34 TestArrays.java TestLWorld.java 316 // 317 private List<String> buildExcludeList() { 318 List<String> exclude = null; 319 String classPrefix = getClass().getSimpleName() + "."; 320 if (!EXCLUDELIST.isEmpty()) { 321 exclude = new ArrayList(Arrays.asList(EXCLUDELIST.split(","))); 322 for (int i = exclude.size() - 1; i >= 0; i--) { 323 String ex = exclude.get(i); 324 if (ex.indexOf(".") > 0) { 325 if (ex.startsWith(classPrefix)) { 326 ex = ex.substring(classPrefix.length()); 327 exclude.set(i, ex); 328 } else { 329 exclude.remove(i); 330 } 331 } 332 } 333 } 334 return exclude; 335 } 336 337 protected ValueTypeTest() { 338 List<String> list = null; 339 if (!TESTLIST.isEmpty()) { 340 list = Arrays.asList(TESTLIST.split(",")); 341 } 342 List<String> exclude = buildExcludeList(); 343 344 // Gather all test methods and put them in Hashtable 345 for (Method m : getClass().getDeclaredMethods()) { 346 Test[] annos = m.getAnnotationsByType(Test.class); 347 if (annos.length != 0 && 348 ((list == null || list.contains(m.getName())) && (exclude == null || !exclude.contains(m.getName())))) { 349 tests.put(getClass().getSimpleName() + "::" + m.getName(), m); 350 } 351 } 352 } 353 354 protected void run(String[] args, Class<?>... classes) throws Throwable { 355 if (args.length == 0) { 356 // Spawn a new VM instance 357 execute_vm(); 358 } else { 359 // Execute tests in the VM spawned by the above code. 360 Asserts.assertTrue(args.length == 1 && args[0].equals("run"), "must be"); 361 run(classes); 362 } 363 } 364 365 private void execute_vm() throws Throwable { 366 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 367 String[] vmInputArgs = InputArguments.getVmInputArgs(); 368 for (String arg : vmInputArgs) { 369 if (arg.startsWith("-XX:CompileThreshold")) { 370 // Disable IR verification if non-default CompileThreshold is set 371 VERIFY_IR = false; 372 } 373 if (arg.startsWith("-XX:+EnableValhallaC1")) { 374 // Disable IR verification if C1 is used (FIXME!) 375 VERIFY_IR = false; 376 } 377 } 378 // Each VM is launched with flags in this order, so the later ones can override the earlier one: 379 // defaultFlags 380 // VERIFY_IR/VERIFY_VM flags specified below 381 // vmInputArgs, which consists of: 382 // @run options 383 // getVMParameters() 384 // getExtraVMParameters() 385 String cmds[] = defaultFlags; 386 if (VERIFY_IR) { 387 // Add print flags for IR verification 388 cmds = concat(cmds, printFlags); 389 // Always trap for exception throwing to not confuse IR verification 390 cmds = concat(cmds, "-XX:-OmitStackTraceInFastThrow"); 391 } 392 if (VERIFY_VM) { 393 cmds = concat(cmds, verifyFlags); 394 } 395 cmds = concat(cmds, vmInputArgs); 396 397 // Run tests in own process and verify output 398 cmds = concat(cmds, getClass().getName(), "run"); 399 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 400 // If ideal graph printing is enabled/supported, verify output 401 String output = oa.getOutput(); 402 oa.shouldHaveExitValue(0); 403 if (VERIFY_IR) { 404 if (output.contains("PrintIdeal enabled")) { 405 parseOutput(output); 406 } else { 407 System.out.println(output); 408 System.out.println("WARNING: IR verification failed! Running with -Xint, -Xcomp or release build?"); 409 } 410 } 411 } 412 413 private void parseOutput(String output) throws Exception { 414 Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]\\n"); 415 Matcher m = comp_re.matcher(output); 416 Map<String,String> compilations = new LinkedHashMap<>(); 417 int prev = 0; 418 String methodName = null; 419 while (m.find()) { 420 if (prev == 0) { 421 // Print header 422 System.out.print(output.substring(0, m.start()+1)); 423 } else if (methodName != null) { 424 compilations.put(methodName, output.substring(prev, m.start()+1)); 425 } 426 if (m.group("osr") != null) { 427 methodName = null; 428 } else { 429 methodName = m.group("name"); 430 } 431 prev = m.end(); 432 } 433 if (prev == 0) { 434 // Print header 435 System.out.print(output); 436 } else if (methodName != null) { 437 compilations.put(methodName, output.substring(prev)); 438 } 439 // Iterate over compilation output 440 for (String testName : compilations.keySet()) { 441 Method test = tests.get(testName); 442 if (test == null) { 443 // Skip helper methods 444 continue; 445 } 446 String graph = compilations.get(testName); 447 if (PRINT_GRAPH) { 448 System.out.println("\nGraph for " + testName + "\n" + graph); 449 } 450 // Parse graph using regular expressions to determine if it contains forbidden nodes 451 Test[] annos = test.getAnnotationsByType(Test.class); 452 Test anno = null; 453 for (Test a : annos) { 454 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 455 assert anno == null; 456 anno = a; 457 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 458 assert anno == null; 459 anno = a; 460 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 461 assert anno == null; 462 anno = a; 463 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 464 assert anno == null; 465 anno = a; 466 } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) { 467 assert anno == null; 468 anno = a; 469 } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) { 470 assert anno == null; 471 anno = a; 472 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) { 473 assert anno == null; 474 anno = a; 475 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) { 476 assert anno == null; 477 anno = a; 478 } 479 } 480 assert anno != null; 481 String regexFail = anno.failOn(); 482 if (!regexFail.isEmpty()) { 483 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 484 Matcher matcher = pattern.matcher(graph); 485 boolean found = matcher.find(); 486 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 487 } 488 String[] regexMatch = anno.match(); 489 int[] matchCount = anno.matchCount(); 490 for (int i = 0; i < regexMatch.length; ++i) { 491 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 492 Matcher matcher = pattern.matcher(graph); 493 int count = 0; 494 String nodes = ""; 495 while (matcher.find()) { 496 count++; 497 nodes += matcher.group() + "\n"; 498 } 499 if (matchCount[i] < 0) { 500 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 501 } else { 502 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 503 } 504 } 505 tests.remove(testName); 506 System.out.println(testName + " passed"); 507 } 508 // Check if all tests were compiled 509 if (tests.size() != 0) { 510 for (String name : tests.keySet()) { 511 System.out.println("Test '" + name + "' not compiled!"); 512 } 513 throw new RuntimeException("Not all tests were compiled"); 514 } 515 } 516 517 private void setup(Class<?> clazz) { 518 if (XCOMP) { 519 // Don't control compilation if -Xcomp is enabled 520 return; 521 } 522 if (DUMP_REPLAY) { 523 // Generate replay compilation files 524 String directive = "[{ match: \"*.*\", DumpReplay: true }]"; 525 if (WHITE_BOX.addCompilerDirective(directive) != 1) { 526 throw new RuntimeException("Failed to add compiler directive"); 527 } 528 } 529 530 Method[] methods = clazz.getDeclaredMethods(); 531 for (Method m : methods) { 532 if (m.isAnnotationPresent(Test.class)) { 533 // Don't inline tests 534 WHITE_BOX.testSetDontInlineMethod(m, true); 535 } 536 if (m.isAnnotationPresent(DontCompile.class)) { 537 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 538 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 539 WHITE_BOX.testSetDontInlineMethod(m, true); 540 } else if (m.isAnnotationPresent(ForceCompile.class)) { 541 int compLevel = getCompLevel(m.getAnnotation(ForceCompile.class)); 542 WHITE_BOX.enqueueMethodForCompilation(m, compLevel); 543 } 544 if (m.isAnnotationPresent(ForceInline.class)) { 545 WHITE_BOX.testSetForceInlineMethod(m, true); 546 } else if (m.isAnnotationPresent(DontInline.class)) { 547 WHITE_BOX.testSetDontInlineMethod(m, true); 548 } 549 } 550 551 // Compile class initializers 552 int compLevel = getCompLevel(null); 553 WHITE_BOX.enqueueInitializerForCompilation(clazz, compLevel); 554 } 555 556 private void run(Class<?>... classes) throws Exception { 557 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 558 System.out.println("PrintIdeal enabled"); 559 } 560 System.out.format("rI = %d, rL = %d\n", rI, rL); 561 562 setup(getClass()); 563 for (Class<?> clazz : classes) { 564 setup(clazz); 565 } 566 567 // Execute tests 568 TreeMap<Long, String> durations = PRINT_TIMES ? new TreeMap<Long, String>() : null; 569 for (Method test : tests.values()) { 570 if (VERBOSE) { 571 System.out.println("Starting " + test.getName()); 572 } 573 long startTime = System.nanoTime(); 574 Method verifier = getClass().getMethod(test.getName() + "_verifier", boolean.class); 575 // Warmup using verifier method 576 Warmup anno = test.getAnnotation(Warmup.class); 577 int warmup = anno == null ? WARMUP : anno.value(); 578 for (int i = 0; i < warmup; ++i) { 579 verifier.invoke(this, true); 580 } 581 int compLevel = getCompLevel(test.getAnnotation(Test.class)); 582 // Trigger compilation 583 WHITE_BOX.enqueueMethodForCompilation(test, compLevel); 584 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 585 // Check result 586 verifier.invoke(this, false); 587 if (PRINT_TIMES || VERBOSE) { 588 long endTime = System.nanoTime(); 589 long duration = (endTime - startTime); 590 durations.put(duration, test.getName()); 591 if (VERBOSE) { 592 System.out.println("Done " + test.getName() + ": " + duration + "ms"); 593 } 594 } 595 } 596 597 // Print execution times 598 if (PRINT_TIMES) { 599 System.out.println("\n\nTest execution times:"); 600 for (Map.Entry<Long, String> entry : durations.entrySet()) { 601 System.out.format("%-10s%15d ns\n", entry.getValue() + ":", entry.getKey()); 602 } 603 } 604 } 605 606 // Choose the appropriate compilation level for a method, according to the given annotation. 607 // 608 // Currently, if TEST_C1 is true, we always use COMP_LEVEL_SIMPLE. Otherwise, if the 609 // compLevel is unspecified, the default is COMP_LEVEL_FULL_OPTIMIZATION. 610 int getCompLevel(Object annotation) { 611 if (TEST_C1) { 612 return COMP_LEVEL_SIMPLE; 613 } 614 int compLevel; 615 if (annotation == null) { 616 compLevel = COMP_LEVEL_ANY; 617 } else if (annotation instanceof Test) { 618 compLevel = ((Test)annotation).compLevel(); 619 } else { 620 compLevel = ((ForceCompile)annotation).compLevel(); 621 } 622 if (compLevel == COMP_LEVEL_ANY) { 623 compLevel = COMP_LEVEL_FULL_OPTIMIZATION; 624 } 625 if (compLevel > (int)TieredStopAtLevel) { 626 compLevel = (int)TieredStopAtLevel; 627 } 628 return compLevel; 629 } 630 }