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 // Do not enqueue the test method for compilation immediately after warmup loops have finished. Instead 94 // let the test method be compiled with on-stack-replacement. 95 @Retention(RetentionPolicy.RUNTIME) 96 @interface OSRCompileOnly {} 97 98 // Skip this test temporarily for C1 testing 99 @Retention(RetentionPolicy.RUNTIME) 100 @interface TempSkipForC1 { 101 String reason() default ""; 102 } 103 104 public abstract class ValueTypeTest { 105 protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 106 107 protected static final int COMP_LEVEL_ANY = -2; 108 protected static final int COMP_LEVEL_ALL = -2; 109 protected static final int COMP_LEVEL_AOT = -1; 110 protected static final int COMP_LEVEL_NONE = 0; 111 protected static final int COMP_LEVEL_SIMPLE = 1; // C1 112 protected static final int COMP_LEVEL_LIMITED_PROFILE = 2; // C1, invocation & backedge counters 113 protected static final int COMP_LEVEL_FULL_PROFILE = 3; // C1, invocation & backedge counters + mdo 114 protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; // C2 or JVMCI 115 116 protected static final boolean TieredCompilation = (Boolean)WHITE_BOX.getVMFlag("TieredCompilation"); 117 protected static final long TieredStopAtLevel = (Long)WHITE_BOX.getVMFlag("TieredStopAtLevel"); 118 static final boolean TEST_C1 = TieredStopAtLevel < COMP_LEVEL_FULL_OPTIMIZATION; 119 120 // Should we execute tests that assume (ValueType[] <: Object[])? 121 static final boolean ENABLE_VALUE_ARRAY_COVARIANCE = Boolean.getBoolean("ValueArrayCovariance"); 122 123 // Random test values 124 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 125 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 126 127 // User defined settings 128 protected static final boolean XCOMP = Platform.isComp(); 129 private static final boolean PRINT_GRAPH = true; 130 protected static final boolean VERBOSE = Boolean.parseBoolean(System.getProperty("Verbose", "false")); 131 private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false")); 132 private static boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")) && !XCOMP; 133 private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false")); 134 private static final String SCENARIOS = System.getProperty("Scenarios", ""); 135 private static final String TESTLIST = System.getProperty("Testlist", ""); 136 private static final String EXCLUDELIST = System.getProperty("Exclude", ""); 137 private static final int WARMUP = Integer.parseInt(System.getProperty("Warmup", "251")); 138 private static final boolean DUMP_REPLAY = Boolean.parseBoolean(System.getProperty("DumpReplay", "false")); 139 protected static final boolean FLIP_C1_C2 = Boolean.parseBoolean(System.getProperty("FlipC1C2", "false")); 140 protected static final boolean GCAfter = Boolean.parseBoolean(System.getProperty("GCAfter", "false")); 141 private static final int OSRTestTimeOut = Integer.parseInt(System.getProperty("OSRTestTimeOut", "-1")); 142 143 // "jtreg -DXcomp=true" runs all the scenarios with -Xcomp. This is faster than "jtreg -javaoptions:-Xcomp". 144 protected static final boolean RUN_SCENARIOS_WITH_XCOMP = Boolean.parseBoolean(System.getProperty("Xcomp", "false")); 145 146 // Pre-defined settings 147 private static final String[] defaultFlags = { 148 "-XX:-BackgroundCompilation", 149 "-XX:CompileCommand=quiet", 150 "-XX:CompileCommand=compileonly,java.lang.invoke.*::*", 151 "-XX:CompileCommand=compileonly,java.lang.Long::sum", 152 "-XX:CompileCommand=compileonly,java.lang.Object::<init>", 153 "-XX:CompileCommand=inline,compiler.valhalla.valuetypes.MyValue*::<init>", 154 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.*::*"}; 155 private static final String[] printFlags = { 156 "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintOptoAssembly"}; 157 private static final String[] verifyFlags = { 158 "-XX:+VerifyOops", "-XX:+VerifyStack", "-XX:+VerifyLastFrame", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC", 159 "-XX:+VerifyDuringGC", "-XX:+VerifyAdapterSharing"}; 160 161 protected static final int ValueTypePassFieldsAsArgsOn = 0x1; 162 protected static final int ValueTypePassFieldsAsArgsOff = 0x2; 163 protected static final int ValueTypeArrayFlattenOn = 0x4; 164 protected static final int ValueTypeArrayFlattenOff = 0x8; 165 protected static final int ValueTypeReturnedAsFieldsOn = 0x10; 166 protected static final int ValueTypeReturnedAsFieldsOff = 0x20; 167 protected static final int AlwaysIncrementalInlineOn = 0x40; 168 protected static final int AlwaysIncrementalInlineOff = 0x80; 169 protected static final int G1GCOn = 0x100; 170 protected static final int G1GCOff = 0x200; 171 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn; 172 protected static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 173 protected static final boolean ValueTypeArrayFlatten = (WHITE_BOX.getIntxVMFlag("ValueArrayElemMaxFlatSize") == -1); // FIXME - fix this if default of ValueArrayElemMaxFlatSize is changed 174 protected static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields"); 175 protected static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline"); 176 protected static final boolean G1GC = (Boolean)WHITE_BOX.getVMFlag("UseG1GC"); 177 protected static final boolean VerifyOops = (Boolean)WHITE_BOX.getVMFlag("VerifyOops"); 178 179 protected static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 180 protected static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 181 protected static final boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 182 183 // Regular expressions used to match nodes in the PrintIdeal output 184 protected static final String START = "(\\d+\\t(.*"; 185 protected static final String MID = ".*)+\\t===.*"; 186 protected static final String END = ")|"; 187 // Generic allocation 188 protected static final String ALLOC_G = "(.*call,static wrapper for: _new_instance_Java" + END; 189 protected static final String ALLOCA_G = "(.*call,static wrapper for: _new_array_Java" + END; 190 // Value type allocation 191 protected static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END; 192 protected static final String ALLOCA = "(.*precise klass \\[Lcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END; 193 protected static final String LOAD = START + "Load(B|S|I|L|F|D|P|N)" + MID + "@compiler/valhalla/valuetypes/MyValue.*" + END; 194 protected static final String LOADK = START + "LoadK" + MID + END; 195 protected static final String STORE = START + "Store(B|C|S|I|L|F|D|P|N)" + MID + "@compiler/valhalla/valuetypes/MyValue.*" + END; 196 protected static final String LOOP = START + "Loop" + MID + "" + END; 197 protected static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + "" + END; 198 protected static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END; 199 protected static final String RETURN = START + "Return" + MID + "returns" + END; 200 protected static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END; 201 protected static final String NPE = START + "CallStaticJava" + MID + "null_check" + END; 202 protected static final String CALL = START + "CallStaticJava" + MID + END; 203 protected static final String STOREVALUETYPEFIELDS = START + "CallStaticJava" + MID + "store_value_type_fields" + END; 204 protected static final String SCOBJ = "(.*# ScObj.*" + END; 205 protected static final String LOAD_UNKNOWN_VALUE = "(.*call_leaf,runtime load_unknown_value.*" + END; 206 protected static final String STORE_UNKNOWN_VALUE = "(.*call_leaf,runtime store_unknown_value.*" + END; 207 protected static final String VALUE_ARRAY_NULL_GUARD = "(.*call,static wrapper for: uncommon_trap.*reason='null_check' action='none'.*" + END; 208 protected static final String STORAGE_PROPERTY_CLEARING = "(.*((int:536870911)|(salq.*3\\R.*sarq.*3)).*" + END; 209 210 public static String[] concat(String prefix[], String... extra) { 211 ArrayList<String> list = new ArrayList<String>(); 212 if (prefix != null) { 213 for (String s : prefix) { 214 list.add(s); 215 } 216 } 217 if (extra != null) { 218 for (String s : extra) { 219 list.add(s); 220 } 221 } 222 223 return list.toArray(new String[list.size()]); 224 } 225 226 /** 227 * Override getNumScenarios and getVMParameters if you want to run with more than 228 * the 6 built-in scenarios 229 */ 230 public int getNumScenarios() { 231 return 6; 232 } 233 234 /** 235 * VM paramaters for the 5 built-in test scenarios. If your test needs to append 236 * extra parameters for (some of) these scenarios, override getExtraVMParameters(). 237 */ 238 public String[] getVMParameters(int scenario) { 239 switch (scenario) { 240 case 0: return new String[] { 241 "-XX:+AlwaysIncrementalInline", 242 "-XX:ValueArrayElemMaxFlatOops=5", 243 "-XX:ValueArrayElemMaxFlatSize=-1", 244 "-XX:ValueFieldMaxFlatSize=-1", 245 "-XX:+ValueTypePassFieldsAsArgs", 246 "-XX:+ValueTypeReturnedAsFields"}; 247 case 1: return new String[] { 248 "-XX:-UseCompressedOops", 249 "-XX:ValueArrayElemMaxFlatOops=5", 250 "-XX:ValueArrayElemMaxFlatSize=-1", 251 "-XX:ValueFieldMaxFlatSize=-1", 252 "-XX:-ValueTypePassFieldsAsArgs", 253 "-XX:-ValueTypeReturnedAsFields"}; 254 case 2: return new String[] { 255 "-XX:-UseCompressedOops", 256 "-XX:ValueArrayElemMaxFlatOops=0", 257 "-XX:ValueArrayElemMaxFlatSize=0", 258 "-XX:ValueFieldMaxFlatSize=-1", 259 "-XX:+ValueTypePassFieldsAsArgs", 260 "-XX:+ValueTypeReturnedAsFields", 261 "-XX:+StressValueTypeReturnedAsFields"}; 262 case 3: return new String[] { 263 "-DVerifyIR=false", 264 "-XX:+AlwaysIncrementalInline", 265 "-XX:ValueArrayElemMaxFlatOops=0", 266 "-XX:ValueArrayElemMaxFlatSize=0", 267 "-XX:ValueFieldMaxFlatSize=0", 268 "-XX:+ValueTypePassFieldsAsArgs", 269 "-XX:+ValueTypeReturnedAsFields"}; 270 case 4: return new String[] { 271 "-DVerifyIR=false", 272 "-XX:ValueArrayElemMaxFlatOops=-1", 273 "-XX:ValueArrayElemMaxFlatSize=-1", 274 "-XX:ValueFieldMaxFlatSize=0", 275 "-XX:+ValueTypePassFieldsAsArgs", 276 "-XX:-ValueTypeReturnedAsFields", 277 "-XX:-ReduceInitialCardMarks"}; 278 case 5: return new String[] { 279 "-XX:+AlwaysIncrementalInline", 280 "-XX:ValueArrayElemMaxFlatOops=5", 281 "-XX:ValueArrayElemMaxFlatSize=-1", 282 "-XX:ValueFieldMaxFlatSize=-1", 283 "-XX:-ValueTypePassFieldsAsArgs", 284 "-XX:-ValueTypeReturnedAsFields"}; 285 } 286 return null; 287 } 288 289 /** 290 * Override this method and return a non-null reason if the given scenario should be 291 * ignored (due to an existing bug, etc). 292 */ 293 String isScenarioIgnored(int scenario) { 294 return null; 295 } 296 297 /** 298 * Override this method to provide extra parameters for selected scenarios 299 */ 300 public String[] getExtraVMParameters(int scenario) { 301 return null; 302 } 303 304 public static void main(String[] args) throws Throwable { 305 if (args.length != 1) { 306 throw new RuntimeException("Usage: @run main/othervm/timeout=120 -Xbootclasspath/a:." + 307 " -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions" + 308 " -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI" + 309 " compiler.valhalla.valuetypes.ValueTypeTest <YourTestMainClass>"); 310 } 311 String testMainClassName = args[0]; 312 Class testMainClass = Class.forName(testMainClassName); 313 ValueTypeTest test = (ValueTypeTest)testMainClass.newInstance(); 314 List<String> scenarios = null; 315 if (!SCENARIOS.isEmpty()) { 316 scenarios = Arrays.asList(SCENARIOS.split(",")); 317 } 318 for (int i=0; i<test.getNumScenarios(); i++) { 319 String reason; 320 if ((reason = test.isScenarioIgnored(i)) != null) { 321 System.out.println("Scenario #" + i + " is ignored: " + reason); 322 } else if (scenarios != null && !scenarios.contains(Integer.toString(i))) { 323 System.out.println("Scenario #" + i + " is skipped due to -Dscenarios=" + SCENARIOS); 324 } else { 325 System.out.println("Scenario #" + i + " -------- "); 326 String[] cmds = InputArguments.getVmInputArgs(); 327 if (RUN_SCENARIOS_WITH_XCOMP) { 328 cmds = concat(cmds, "-Xcomp"); 329 } 330 cmds = concat(cmds, test.getVMParameters(i)); 331 cmds = concat(cmds, test.getExtraVMParameters(i)); 332 cmds = concat(cmds, testMainClassName); 333 334 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 335 String output = oa.getOutput(); 336 oa.shouldHaveExitValue(0); 337 System.out.println(output); 338 } 339 } 340 } 341 342 // To exclude test cases, use -DExclude=<case1>,<case2>,... 343 // Each case can be just the method name, or can be <class>.<method>. The latter form is useful 344 // when you are running several tests at the same time. 345 // 346 // jtreg -DExclude=test12 TestArrays.java 347 // jtreg -DExclude=test34 TestLWorld.java 348 // -- or -- 349 // jtreg -DExclude=TestArrays.test12,TestLWorld.test34 TestArrays.java TestLWorld.java 350 // 351 private List<String> buildExcludeList() { 352 List<String> exclude = null; 353 String classPrefix = getClass().getSimpleName() + "."; 354 if (!EXCLUDELIST.isEmpty()) { 355 exclude = new ArrayList(Arrays.asList(EXCLUDELIST.split(","))); 356 for (int i = exclude.size() - 1; i >= 0; i--) { 357 String ex = exclude.get(i); 358 if (ex.indexOf(".") > 0) { 359 if (ex.startsWith(classPrefix)) { 360 ex = ex.substring(classPrefix.length()); 361 exclude.set(i, ex); 362 } else { 363 exclude.remove(i); 364 } 365 } 366 } 367 } 368 return exclude; 369 } 370 371 protected ValueTypeTest() { 372 List<String> list = null; 373 if (!TESTLIST.isEmpty()) { 374 list = Arrays.asList(TESTLIST.split(",")); 375 } 376 List<String> exclude = buildExcludeList(); 377 378 // Gather all test methods and put them in Hashtable 379 for (Method m : getClass().getDeclaredMethods()) { 380 Test[] annos = m.getAnnotationsByType(Test.class); 381 if (annos.length != 0 && 382 ((list == null || list.contains(m.getName())) && (exclude == null || !exclude.contains(m.getName())))) { 383 tests.put(getClass().getSimpleName() + "::" + m.getName(), m); 384 } 385 } 386 } 387 388 protected void run(String[] args, Class<?>... classes) throws Throwable { 389 if (args.length == 0) { 390 // Spawn a new VM instance 391 execute_vm(); 392 } else { 393 // Execute tests in the VM spawned by the above code. 394 Asserts.assertTrue(args.length == 1 && args[0].equals("run"), "must be"); 395 run(classes); 396 } 397 } 398 399 private void execute_vm() throws Throwable { 400 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 401 String[] vmInputArgs = InputArguments.getVmInputArgs(); 402 for (String arg : vmInputArgs) { 403 if (arg.startsWith("-XX:CompileThreshold")) { 404 // Disable IR verification if non-default CompileThreshold is set 405 VERIFY_IR = false; 406 } 407 } 408 // Each VM is launched with flags in this order, so the later ones can override the earlier one: 409 // VERIFY_IR/VERIFY_VM flags specified below 410 // vmInputArgs, which consists of: 411 // @run options 412 // getVMParameters() 413 // getExtraVMParameters() 414 // defaultFlags 415 String cmds[] = null; 416 if (VERIFY_IR) { 417 // Add print flags for IR verification 418 cmds = concat(cmds, printFlags); 419 // Always trap for exception throwing to not confuse IR verification 420 cmds = concat(cmds, "-XX:-OmitStackTraceInFastThrow"); 421 } 422 if (VERIFY_VM) { 423 cmds = concat(cmds, verifyFlags); 424 } 425 cmds = concat(cmds, vmInputArgs); 426 cmds = concat(cmds, defaultFlags); 427 428 // Run tests in own process and verify output 429 cmds = concat(cmds, getClass().getName(), "run"); 430 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 431 // If ideal graph printing is enabled/supported, verify output 432 String output = oa.getOutput(); 433 oa.shouldHaveExitValue(0); 434 if (VERIFY_IR) { 435 if (output.contains("PrintIdeal enabled")) { 436 parseOutput(output); 437 } else { 438 System.out.println(output); 439 System.out.println("WARNING: IR verification failed! Running with -Xint, -Xcomp or release build?"); 440 } 441 } 442 } 443 444 private void parseOutput(String output) throws Exception { 445 Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\d?\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]"); 446 Matcher m = comp_re.matcher(output); 447 Map<String,String> compilations = new LinkedHashMap<>(); 448 int prev = 0; 449 String methodName = null; 450 while (m.find()) { 451 if (prev == 0) { 452 // Print header 453 System.out.print(output.substring(0, m.start()+1)); 454 } else if (methodName != null) { 455 compilations.put(methodName, output.substring(prev, m.start()+1)); 456 } 457 if (m.group("osr") != null) { 458 methodName = null; 459 } else { 460 methodName = m.group("name"); 461 } 462 prev = m.end(); 463 } 464 if (prev == 0) { 465 // Print header 466 System.out.print(output); 467 } else if (methodName != null) { 468 compilations.put(methodName, output.substring(prev)); 469 } 470 // Iterate over compilation output 471 for (String testName : compilations.keySet()) { 472 Method test = tests.get(testName); 473 if (test == null) { 474 // Skip helper methods 475 continue; 476 } 477 String graph = compilations.get(testName); 478 if (PRINT_GRAPH) { 479 System.out.println("\nGraph for " + testName + "\n" + graph); 480 } 481 // Parse graph using regular expressions to determine if it contains forbidden nodes 482 Test[] annos = test.getAnnotationsByType(Test.class); 483 Test anno = null; 484 for (Test a : annos) { 485 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 486 assert anno == null; 487 anno = a; 488 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 489 assert anno == null; 490 anno = a; 491 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 492 assert anno == null; 493 anno = a; 494 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 495 assert anno == null; 496 anno = a; 497 } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) { 498 assert anno == null; 499 anno = a; 500 } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) { 501 assert anno == null; 502 anno = a; 503 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) { 504 assert anno == null; 505 anno = a; 506 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) { 507 assert anno == null; 508 anno = a; 509 } else if ((a.valid() & G1GCOn) != 0 && G1GC) { 510 assert anno == null; 511 anno = a; 512 } else if ((a.valid() & G1GCOff) != 0 && !G1GC) { 513 assert anno == null; 514 anno = a; 515 } 516 } 517 assert anno != null; 518 String regexFail = anno.failOn(); 519 if (!regexFail.isEmpty()) { 520 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 521 Matcher matcher = pattern.matcher(graph); 522 boolean found = matcher.find(); 523 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 524 } 525 String[] regexMatch = anno.match(); 526 int[] matchCount = anno.matchCount(); 527 for (int i = 0; i < regexMatch.length; ++i) { 528 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 529 Matcher matcher = pattern.matcher(graph); 530 int count = 0; 531 String nodes = ""; 532 while (matcher.find()) { 533 count++; 534 nodes += matcher.group() + "\n"; 535 } 536 537 if (TieredCompilation) { 538 // FIXME: TestLWorld.test88 fails with "expected 4 to equal 2". See JDK-8230925 539 continue; 540 } 541 542 if (matchCount[i] < 0) { 543 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 544 } else { 545 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 546 } 547 } 548 tests.remove(testName); 549 System.out.println(testName + " passed"); 550 } 551 // Check if all tests were compiled 552 if (tests.size() != 0) { 553 for (String name : tests.keySet()) { 554 System.out.println("Test '" + name + "' not compiled!"); 555 } 556 throw new RuntimeException("Not all tests were compiled"); 557 } 558 } 559 560 private void setup(Class<?> clazz) { 561 if (XCOMP) { 562 // Don't control compilation if -Xcomp is enabled 563 return; 564 } 565 if (DUMP_REPLAY) { 566 // Generate replay compilation files 567 String directive = "[{ match: \"*.*\", DumpReplay: true }]"; 568 if (WHITE_BOX.addCompilerDirective(directive) != 1) { 569 throw new RuntimeException("Failed to add compiler directive"); 570 } 571 } 572 573 Method[] methods = clazz.getDeclaredMethods(); 574 for (Method m : methods) { 575 if (m.isAnnotationPresent(Test.class)) { 576 // Don't inline tests 577 WHITE_BOX.testSetDontInlineMethod(m, true); 578 } 579 if (m.isAnnotationPresent(DontCompile.class)) { 580 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 581 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 582 WHITE_BOX.testSetDontInlineMethod(m, true); 583 } else if (m.isAnnotationPresent(ForceCompile.class)) { 584 int compLevel = getCompLevel(m.getAnnotation(ForceCompile.class)); 585 enqueueMethodForCompilation(m, compLevel); 586 } 587 if (m.isAnnotationPresent(ForceInline.class)) { 588 WHITE_BOX.testSetForceInlineMethod(m, true); 589 } else if (m.isAnnotationPresent(DontInline.class)) { 590 WHITE_BOX.testSetDontInlineMethod(m, true); 591 } 592 } 593 594 // Compile class initializers 595 int compLevel = getCompLevel(null); 596 WHITE_BOX.enqueueInitializerForCompilation(clazz, compLevel); 597 } 598 599 private void run(Class<?>... classes) throws Exception { 600 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 601 System.out.println("PrintIdeal enabled"); 602 } 603 System.out.format("rI = %d, rL = %d\n", rI, rL); 604 605 setup(getClass()); 606 for (Class<?> clazz : classes) { 607 setup(clazz); 608 } 609 610 // Execute tests 611 TreeMap<Long, String> durations = (PRINT_TIMES || VERBOSE) ? new TreeMap<Long, String>() : null; 612 for (Method test : tests.values()) { 613 if (VERBOSE) { 614 System.out.println("Starting " + test.getName()); 615 } 616 TempSkipForC1 c1skip = test.getAnnotation(TempSkipForC1.class); 617 if (TEST_C1 && c1skip != null) { 618 System.out.println("Skipped " + test.getName() + " for C1 testing: " + c1skip.reason()); 619 continue; 620 } 621 long startTime = System.nanoTime(); 622 Method verifier = getClass().getMethod(test.getName() + "_verifier", boolean.class); 623 // Warmup using verifier method 624 Warmup anno = test.getAnnotation(Warmup.class); 625 int warmup = anno == null ? WARMUP : anno.value(); 626 for (int i = 0; i < warmup; ++i) { 627 verifier.invoke(this, true); 628 } 629 boolean osrOnly = (test.getAnnotation(OSRCompileOnly.class) != null); 630 631 // C1 generates a lot of code when VerifyOops is enabled and may run out of space (for a small 632 // number of test cases). 633 boolean maybeCodeBufferOverflow = (TEST_C1 && VerifyOops); 634 635 if (osrOnly) { 636 long started = System.currentTimeMillis(); 637 boolean stateCleared = false; 638 for (;;) { 639 long elapsed = System.currentTimeMillis() - started; 640 if (maybeCodeBufferOverflow && elapsed > 5000 && !WHITE_BOX.isMethodCompiled(test, false)) { 641 System.out.println("Temporarily disabling VerifyOops"); 642 try { 643 WHITE_BOX.setBooleanVMFlag("VerifyOops", false); 644 if (!stateCleared) { 645 WHITE_BOX.clearMethodState(test); 646 stateCleared = true; 647 } 648 verifier.invoke(this, false); 649 } finally { 650 WHITE_BOX.setBooleanVMFlag("VerifyOops", true); 651 System.out.println("Re-enabled VerifyOops"); 652 } 653 } else { 654 verifier.invoke(this, false); 655 } 656 657 boolean b = WHITE_BOX.isMethodCompiled(test, false); 658 if (VERBOSE) { 659 System.out.println("Is " + test.getName() + " compiled? " + b); 660 } 661 if (b || XCOMP || !USE_COMPILER) { 662 // Don't control compilation if -Xcomp is enabled, or if compiler is disabled 663 break; 664 } 665 if (OSRTestTimeOut > 0 && elapsed > OSRTestTimeOut) { 666 break; 667 } 668 } 669 if (!XCOMP) { 670 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 671 } 672 } else { 673 int compLevel = getCompLevel(test.getAnnotation(Test.class)); 674 // Trigger compilation 675 enqueueMethodForCompilation(test, compLevel); 676 if (maybeCodeBufferOverflow && !WHITE_BOX.isMethodCompiled(test, false)) { 677 // Let's disable VerifyOops temporarily and retry. 678 WHITE_BOX.setBooleanVMFlag("VerifyOops", false); 679 WHITE_BOX.clearMethodState(test); 680 enqueueMethodForCompilation(test, compLevel); 681 WHITE_BOX.setBooleanVMFlag("VerifyOops", true); 682 } 683 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 684 // Check result 685 verifier.invoke(this, false); 686 } 687 if (PRINT_TIMES || VERBOSE) { 688 long endTime = System.nanoTime(); 689 long duration = (endTime - startTime); 690 durations.put(duration, test.getName()); 691 if (VERBOSE) { 692 System.out.println("Done " + test.getName() + ": " + duration + " ns = " + (duration / 1000000) + " ms"); 693 } 694 } 695 if (GCAfter) { 696 System.out.println("doing GC"); 697 System.gc(); 698 } 699 } 700 701 // Print execution times 702 if (PRINT_TIMES) { 703 System.out.println("\n\nTest execution times:"); 704 for (Map.Entry<Long, String> entry : durations.entrySet()) { 705 System.out.format("%-10s%15d ns\n", entry.getValue() + ":", entry.getKey()); 706 } 707 } 708 } 709 710 // Get the appropriate compilation level for a method, according to the 711 // given annotation, as well as the current test scenario and VM options. 712 // 713 private int getCompLevel(Object annotation) { 714 int compLevel; 715 if (annotation == null) { 716 compLevel = COMP_LEVEL_ANY; 717 } else if (annotation instanceof Test) { 718 compLevel = ((Test)annotation).compLevel(); 719 } else { 720 compLevel = ((ForceCompile)annotation).compLevel(); 721 } 722 723 return restrictCompLevel(compLevel); 724 } 725 726 // Get the appropriate level as permitted by the test scenario and VM options. 727 private static int restrictCompLevel(int compLevel) { 728 if (compLevel == COMP_LEVEL_ANY) { 729 compLevel = COMP_LEVEL_FULL_OPTIMIZATION; 730 } 731 if (FLIP_C1_C2) { 732 // Effectively treat all (compLevel = C1) as (compLevel = C2), and 733 // (compLevel = C2) as (compLevel = C1). 734 if (compLevel == COMP_LEVEL_SIMPLE) { 735 compLevel = COMP_LEVEL_FULL_OPTIMIZATION; 736 } else if (compLevel == COMP_LEVEL_FULL_OPTIMIZATION) { 737 compLevel = COMP_LEVEL_SIMPLE; 738 } 739 } 740 if (!TEST_C1 && compLevel < COMP_LEVEL_FULL_OPTIMIZATION) { 741 compLevel = COMP_LEVEL_FULL_OPTIMIZATION; 742 } 743 if (compLevel > (int)TieredStopAtLevel) { 744 compLevel = (int)TieredStopAtLevel; 745 } 746 return compLevel; 747 } 748 749 public static void enqueueMethodForCompilation(Method m, int level) { 750 level = restrictCompLevel(level); 751 if (VERBOSE) { 752 System.out.println("enqueueMethodForCompilation " + m + ", level = " + level); 753 } 754 WHITE_BOX.enqueueMethodForCompilation(m, level); 755 } 756 757 // Unlike C2, C1 intrinsics never deoptimize System.arraycopy. Instead, we fall back to 758 // a normal method invocation when encountering flattened arrays. 759 static boolean isCompiledByC2(Method m) { 760 int CompLevel_none = 0, // Interpreter 761 CompLevel_simple = 1, // C1 762 CompLevel_limited_profile = 2, // C1, invocation & backedge counters 763 CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo 764 CompLevel_full_optimization = 4; // C2 or JVMCI 765 766 return USE_COMPILER && !XCOMP && WHITE_BOX.isMethodCompiled(m, false) && 767 WHITE_BOX.getMethodCompilationLevel(m, false) >= CompLevel_full_optimization; 768 } 769 }