From fb210e3a7174bca1da112216158b2c1dede6dc34 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 20 Mar 2025 06:14:07 +0000 Subject: [PATCH] 8351952: [IR Framework]: allow ignoring methods that are not compilable Co-authored-by: Christian Hagedorn Reviewed-by: chagedorn, thartmann --- .../jtreg/compiler/lib/ir_framework/Test.java | 10 +- .../lib/ir_framework/TestFramework.java | 18 +- .../ir_framework/driver/TestVMProcess.java | 14 +- .../irmethod/NotCompilableIRMethod.java | 61 ++++++ .../NotCompilableIRMethodMatchResult.java | 60 +++++ .../irmatching/parser/IRMethodBuilder.java | 17 +- .../irmatching/parser/TestClassParser.java | 8 +- .../report/CompilationOutputBuilder.java | 8 +- .../irmatching/report/FailCountVisitor.java | 7 +- .../report/FailureMessageBuilder.java | 7 +- .../visitor/MatchResultVisitor.java | 3 +- .../shared/TestFrameworkSocket.java | 1 + .../lib/ir_framework/test/AbstractTest.java | 25 ++- .../lib/ir_framework/test/DeclaredTest.java | 10 +- .../lib/ir_framework/test/TestVM.java | 4 +- .../ir_framework/tests/TestNotCompilable.java | 205 ++++++++++++++++++ .../tests/TestPhaseIRMatching.java | 11 +- 17 files changed, 442 insertions(+), 27 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java b/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java index 49b297f6b93..43569cb589e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,4 +84,12 @@ public @interface Test { * available level which is usually {@link CompLevel#C2}. */ CompLevel compLevel() default CompLevel.ANY; + + /** + * In rare cases, methods may not be compilable because of a compilation bailout. By default, this leads to a + * test failure. However, if such cases are expected in a specific test, this flag can be set to true, which + * allows the test to pass even if there is no compilation. Any associated {@link IR} rule is only executed + * if the test method was compiled, and else it is ignored silently. + */ + boolean allowNotCompilable() default false; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 919380cd91c..79c99352a32 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -175,6 +175,7 @@ public class TestFramework { private List flags; private int defaultWarmup = -1; private boolean testClassesOnBootClassPath; + private boolean isAllowNotCompilable = false; /* * Public interface methods @@ -409,6 +410,19 @@ public class TestFramework { return this; } + /** + * In rare cases, methods may not be compilable because of a compilation bailout. By default, this leads to a + * test failure. However, if such cases are expected in multiple methods in a test class, this flag can be set to + * true, which allows any test to pass even if there is a compilation bailout. If only selected methods are prone + * to bail out, it is preferred to use {@link Test#allowNotCompilable()} instead for more fine-grained control. + * By setting this flag, any associated {@link IR} rule of a test is only executed if the test method was compiled, + * and else it is ignored silently. + */ + public TestFramework allowNotCompilable() { + this.isAllowNotCompilable = true; + return this; + } + /** * Get the VM output of the test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios * were run, use {@link Scenario#getTestVMOutput()}. @@ -773,10 +787,10 @@ public class TestFramework { private void runTestVM(List additionalFlags) { TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup, - testClassesOnBootClassPath); + isAllowNotCompilable, testClassesOnBootClassPath); if (shouldVerifyIR) { try { - TestClassParser testClassParser = new TestClassParser(testClass); + TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), testVMProcess.getIrEncoding()); IRMatcher matcher = new IRMatcher(testClassMatchable); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index feb8fe9e530..fcdafc9618e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,11 +65,12 @@ public class TestVMProcess { private String irEncoding; public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup, - boolean testClassesOnBootClassPath) { + boolean allowNotCompilable, boolean testClassesOnBootClassPath) { this.cmds = new ArrayList<>(); TestFrameworkSocket socket = new TestFrameworkSocket(); try (socket) { - prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup, testClassesOnBootClassPath); + prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup, + allowNotCompilable, testClassesOnBootClassPath); start(); } processSocketOutput(socket); @@ -93,7 +94,8 @@ public class TestVMProcess { } private void prepareTestVMFlags(List additionalFlags, TestFrameworkSocket socket, Class testClass, - Set> helperClasses, int defaultWarmup, boolean testClassesOnBootClassPath) { + Set> helperClasses, int defaultWarmup, boolean allowNotCompilable, + boolean testClassesOnBootClassPath) { // Set java.library.path so JNI tests which rely on jtreg nativepath setting work cmds.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH); // Need White Box access in test VM. @@ -128,6 +130,10 @@ public class TestVMProcess { cmds.add("-DWarmup=" + defaultWarmup); } + if (allowNotCompilable) { + cmds.add("-DAllowNotCompilable=true"); + } + cmds.add(TestVM.class.getName()); cmds.add(testClass.getName()); if (helperClasses != null) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java new file mode 100644 index 00000000000..d74825c8d4f --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethod.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.RunMode; + +import java.lang.reflect.Method; + +/** + * This class represents a special IR method which was not compiled by the IR framework, but this was explicitly allowed + * by "allowNotCompilable". This happens when the compiler bails out of a compilation (i.e. no compilation) but we treat + * this as valid case. Any associated IR rules pass silently. + * + * @see IR + * @see Test + */ +public class NotCompilableIRMethod implements IRMethodMatchable { + private final Method method; + private final int ruleCount; + + public NotCompilableIRMethod(Method method, int ruleCount) { + this.method = method; + this.ruleCount = ruleCount; + } + + @Override + public String name() { + return method.getName(); + } + + /** + * Directly return a {@link NotCompilableIRMethodMatchResult} as we do not need to match IR rules individually. + */ + @Override + public NotCompilableIRMethodMatchResult match() { + return new NotCompilableIRMethodMatchResult(method, ruleCount); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java new file mode 100644 index 00000000000..011b596cc9e --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/NotCompilableIRMethodMatchResult.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.lib.ir_framework.driver.irmatching.irmethod; + +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.RunMode; +import compiler.lib.ir_framework.driver.irmatching.MatchResult; +import compiler.lib.ir_framework.driver.irmatching.visitor.MatchResultVisitor; + +import java.lang.reflect.Method; + +/** + * This class represents a special matching result of an IR method where the compilation output was completely empty, + * but this was exlicitly allowed by "allowNotCompilable". This happens when the compiler bails out of a compilation + * (i.e. no compilation) but we treat this as valid case. Any associated IR rules pass silently. + * + * @see NotCompilableIRMethod + * @see Test + */ +public class NotCompilableIRMethodMatchResult implements MatchResult { + private final Method method; + private final int failedIRRules; + + public NotCompilableIRMethodMatchResult(Method method, int failedIRRules) { + this.method = method; + this.failedIRRules = failedIRRules; + } + + @Override + public boolean fail() { + return false; + } + + @Override + public void accept(MatchResultVisitor visitor) { + visitor.visitMethodNotCompilable(method, failedIRRules); + } +} + diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java index beed44a01c5..538680496e7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/IRMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,13 @@ package compiler.lib.ir_framework.driver.irmatching.parser; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.driver.irmatching.Compilation; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod; import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchable; import compiler.lib.ir_framework.driver.irmatching.irmethod.NotCompiledIRMethod; +import compiler.lib.ir_framework.driver.irmatching.irmethod.NotCompilableIRMethod; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFileParser; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.LoggedMethod; import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.LoggedMethods; @@ -41,10 +44,12 @@ import java.util.TreeSet; class IRMethodBuilder { private final Map loggedMethods; private final TestMethods testMethods; + private final boolean allowNotCompilable; - public IRMethodBuilder(TestMethods testMethods, LoggedMethods loggedMethods) { + public IRMethodBuilder(TestMethods testMethods, LoggedMethods loggedMethods, boolean allowNotCompilable) { this.testMethods = testMethods; this.loggedMethods = loggedMethods.loggedMethods(); + this.allowNotCompilable = allowNotCompilable; } /** @@ -64,7 +69,13 @@ class IRMethodBuilder { return new IRMethod(testMethod.method(), testMethod.irRuleIds(), testMethod.irAnnos(), new Compilation(loggedMethod.compilationOutput()), vmInfo); } else { - return new NotCompiledIRMethod(testMethod.method(), testMethod.irRuleIds().length); + Test[] testAnnos = testMethod.method().getAnnotationsByType(Test.class); + boolean allowMethodNotCompilable = allowNotCompilable || testAnnos[0].allowNotCompilable(); + if (allowMethodNotCompilable) { + return new NotCompilableIRMethod(testMethod.method(), testMethod.irRuleIds().length); + } else { + return new NotCompiledIRMethod(testMethod.method(), testMethod.irRuleIds().length); + } } } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java index 776642d460c..b6c9920c2d1 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,9 +42,11 @@ import java.util.SortedSet; */ public class TestClassParser { private final Class testClass; + private final boolean allowNotCompilable; - public TestClassParser(Class testClass) { + public TestClassParser(Class testClass, boolean allowNotCompilable) { this.testClass = testClass; + this.allowNotCompilable = allowNotCompilable; } /** @@ -68,7 +70,7 @@ public class TestClassParser { * with the parsed compilation output from {@link HotSpotPidFileParser}. */ private Matchable createTestClass(TestMethods testMethods, LoggedMethods loggedMethods, VMInfo vmInfo) { - IRMethodBuilder irMethodBuilder = new IRMethodBuilder(testMethods, loggedMethods); + IRMethodBuilder irMethodBuilder = new IRMethodBuilder(testMethods, loggedMethods, allowNotCompilable); SortedSet irMethods = irMethodBuilder.build(vmInfo); TestFormat.throwIfAnyFailures(); return new TestClass(irMethods); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/CompilationOutputBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/CompilationOutputBuilder.java index e1c31a45ebb..037da604f4c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/CompilationOutputBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/CompilationOutputBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package compiler.lib.ir_framework.driver.irmatching.report; import compiler.lib.ir_framework.CompilePhase; import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.shared.TestFrameworkException; import compiler.lib.ir_framework.driver.irmatching.MatchResult; import compiler.lib.ir_framework.driver.irmatching.irrule.checkattribute.CheckAttributeType; import compiler.lib.ir_framework.driver.irmatching.irrule.constraint.CountsConstraintFailure; @@ -121,6 +122,11 @@ public class CompilationOutputBuilder implements MatchResultVisitor { output.append("").append(System.lineSeparator()); } + @Override + public void visitMethodNotCompilable(Method method, int failedIRRules) { + throw new TestFrameworkException("Sould not reach here"); + } + @Override public void visitIRRule(AcceptChildren acceptChildren, int irRuleId, IR irAnno) { acceptChildren.accept(this); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailCountVisitor.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailCountVisitor.java index 7fe2f5467af..9d1ea6fc408 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailCountVisitor.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailCountVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,11 @@ class FailCountVisitor implements MatchResultVisitor { irRuleCount += failedIRRules; } + @Override + public void visitMethodNotCompilable(Method method, int failedIRRules) { + irMethodCount++; + } + public int getIrRuleCount() { return irRuleCount; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java index 3fcb152b699..9cbba83e90b 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/report/FailureMessageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package compiler.lib.ir_framework.driver.irmatching.report; import compiler.lib.ir_framework.CompilePhase; import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.shared.TestFrameworkException; import compiler.lib.ir_framework.driver.irmatching.MatchResult; import compiler.lib.ir_framework.driver.irmatching.irrule.checkattribute.CheckAttributeType; import compiler.lib.ir_framework.driver.irmatching.irrule.constraint.CountsConstraintFailure; @@ -97,6 +98,10 @@ public class FailureMessageBuilder implements MatchResultVisitor { indentation.sub(); } + public void visitMethodNotCompilable(Method method, int failedIRRules) { + throw new TestFrameworkException("Sould not reach here"); + } + @Override public void visitIRRule(AcceptChildren acceptChildren, int irRuleId, IR irAnno) { indentation.add(); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/visitor/MatchResultVisitor.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/visitor/MatchResultVisitor.java index 6dd0234baae..8191cfd55c0 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/visitor/MatchResultVisitor.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/visitor/MatchResultVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ public interface MatchResultVisitor { void visitTestClass(AcceptChildren acceptChildren); void visitIRMethod(AcceptChildren acceptChildren, Method method, int failedIRRules); void visitMethodNotCompiled(Method method, int failedIRRules); + void visitMethodNotCompilable(Method method, int failedIRRules); void visitIRRule(AcceptChildren acceptChildren, int irRuleId, IR irAnno); void visitCompilePhaseIRRule(AcceptChildren acceptChildren, CompilePhase compilePhase, String compilationOutput); void visitNoCompilePhaseCompilation(CompilePhase compilePhase); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java index 7f7aa3f5b32..a3a5f9ece8f 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java @@ -44,6 +44,7 @@ public class TestFrameworkSocket implements AutoCloseable { public static final String TESTLIST_TAG = "[TESTLIST]"; public static final String DEFAULT_REGEX_TAG = "[DEFAULT_REGEX]"; public static final String PRINT_TIMES_TAG = "[PRINT_TIMES]"; + public static final String NOT_COMPILABLE_TAG = "[NOT_COMPILABLE]"; // Static fields used for test VM only. private static final String SERVER_PORT_PROPERTY = "ir.framework.server.port"; diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java index 9d1bf62746f..4d227900e2e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/AbstractTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import compiler.lib.ir_framework.shared.TestFrameworkSocket; + /** * Abstract super class for base, checked and custom run tests. */ @@ -109,7 +111,21 @@ abstract class AbstractTest { abstract protected void compileTest(); + private class MethodNotCompilableException extends Exception {} + protected void compileMethod(DeclaredTest test) { + try { + tryCompileMethod(test); + } catch (MethodNotCompilableException e) { + final Method testMethod = test.getTestMethod(); + TestFrameworkSocket.write("Method not compilable: " + testMethod, TestFrameworkSocket.NOT_COMPILABLE_TAG, true); + TestRun.check(test.isAllowNotCompilable(), + "Method " + testMethod + " not compilable (anymore) at level " + test.getCompLevel() + + ". Most likely, this is not expected, but if it is, you can use 'allowNotCompilable'."); + } + } + + private void tryCompileMethod(DeclaredTest test) throws MethodNotCompilableException { final Method testMethod = test.getTestMethod(); if (TestFramework.VERBOSE) { System.out.println("Compile method " + testMethod + " after warm-up..."); @@ -151,10 +167,11 @@ abstract class AbstractTest { checkCompilationLevel(test); } - private void enqueueMethodForCompilation(DeclaredTest test) { + private void enqueueMethodForCompilation(DeclaredTest test) throws MethodNotCompilableException { final Method testMethod = test.getTestMethod(); - TestRun.check(WHITE_BOX.isMethodCompilable(testMethod, test.getCompLevel().getValue(), false), - "Method " + testMethod + " not compilable (anymore) at level " + test.getCompLevel()); + if (!WHITE_BOX.isMethodCompilable(testMethod, test.getCompLevel().getValue(), false)) { + throw new MethodNotCompilableException(); + } TestVM.enqueueForCompilation(testMethod, test.getCompLevel()); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java index d065a04b026..15cd68bd0e3 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/DeclaredTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,13 +36,15 @@ public class DeclaredTest { private final ArgumentsProvider argumentsProvider; private final int warmupIterations; private final CompLevel compLevel; + private final boolean allowNotCompilable; private Method attachedMethod; - public DeclaredTest(Method testMethod, ArgumentsProvider argumentsProvider, CompLevel compLevel, int warmupIterations) { + public DeclaredTest(Method testMethod, ArgumentsProvider argumentsProvider, CompLevel compLevel, int warmupIterations, boolean allowNotCompilable) { // Make sure we can also call non-public or public methods in package private classes testMethod.setAccessible(true); this.testMethod = testMethod; this.compLevel = compLevel; + this.allowNotCompilable = allowNotCompilable; this.argumentsProvider = argumentsProvider; this.warmupIterations = warmupIterations; this.attachedMethod = null; @@ -60,6 +62,10 @@ public class DeclaredTest { return warmupIterations; } + public boolean isAllowNotCompilable() { + return allowNotCompilable; + } + public Object[] getArguments(Object invocationTarget, int invocationCounter) { return argumentsProvider.getArguments(invocationTarget, invocationCounter); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index e4f49d494d2..8ccd0faa013 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -75,6 +75,7 @@ public class TestVM { */ public static final int WARMUP_ITERATIONS = Integer.parseInt(System.getProperty("Warmup", "2000")); + private static final boolean ALLOW_METHOD_NOT_COMPILABLE = Boolean.getBoolean("AllowNotCompilable"); private static final boolean TIERED_COMPILATION = (Boolean)WHITE_BOX.getVMFlag("TieredCompilation"); private static final CompLevel TIERED_COMPILATION_STOP_AT_LEVEL; private static final boolean CLIENT_VM = Platform.isClient(); @@ -579,8 +580,9 @@ public class TestVM { if (EXCLUDE_RANDOM) { compLevel = compLevel.excludeCompilationRandomly(m); } + boolean allowNotCompilable = testAnno.allowNotCompilable() || ALLOW_METHOD_NOT_COMPILABLE; ArgumentsProvider argumentsProvider = ArgumentsProviderBuilder.build(m, setupMethodMap); - DeclaredTest test = new DeclaredTest(m, argumentsProvider, compLevel, warmupIterations); + DeclaredTest test = new DeclaredTest(m, argumentsProvider, compLevel, warmupIterations, allowNotCompilable); declaredTests.put(m, test); testMethodMap.put(m.getName(), m); } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java new file mode 100644 index 00000000000..760fc579910 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestNotCompilable.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package ir_framework.tests; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.shared.TestRunException; +import compiler.lib.ir_framework.driver.TestVMException; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; + +/* + * @test + * @requires vm.compiler2.enabled & vm.flagless + * @summary Test the functionality of allowNotCompilable. + * @library /test/lib / + * @run driver ir_framework.tests.TestNotCompilable + */ + +public class TestNotCompilable { + public static void main(String[] args) throws Exception { + runTests(false); + runTests(true); + } + + private static void runTests(boolean noWarmup) { + // Run without any flags -> should pass. + runNormal(TestClassA.class, noWarmup); + runNormal(TestClassB.class, noWarmup); + runNormal(TestClassC.class, noWarmup); + runNormal(TestClassD.class, noWarmup); + runNormal(TestClassE.class, noWarmup); + runNormal(TestClassF.class, noWarmup); + + // Forbid compilation -> should throw exception, because "not compilable". + runWithExcludeExpectFailure(TestClassA.class, noWarmup); + runWithExcludeExpectFailure(TestClassB.class, noWarmup); + // Note: @Run does not fail, but the @IR detects that there is no compilation, and fails. + runWithExcludeExpectFailure(TestClassE.class, noWarmup); + runOptoNoExecuteExpectFailure(TestClassA.class, noWarmup); + runOptoNoExecuteExpectFailure(TestClassB.class, noWarmup); + + // Forbid compilation -> annotation allows not compilable -> should pass. + runWithExcludeExpectSuccess(TestClassC.class, noWarmup); + runWithExcludeExpectSuccess(TestClassD.class, noWarmup); + runWithExcludeExpectSuccess(TestClassF.class, noWarmup); + runOptoNoExecuteExpectSuccess(TestClassC.class, noWarmup); + runOptoNoExecuteExpectSuccess(TestClassD.class, noWarmup); + // Note: @Run does not fail because of missing compilation. And OptoNoExecute does still + // print IR before it bails out, and we can successfully match it. + runOptoNoExecuteExpectSuccess(TestClassE.class, noWarmup); + runOptoNoExecuteExpectSuccess(TestClassF.class, noWarmup); + + // Forbid compilation, but allow methods not to compile -> should pass. + runWithExcludeAndGlobalAllowNotCompilable(TestClassA.class, noWarmup); + runWithExcludeAndGlobalAllowNotCompilable(TestClassB.class, noWarmup); + runWithExcludeAndGlobalAllowNotCompilable(TestClassC.class, noWarmup); + runWithExcludeAndGlobalAllowNotCompilable(TestClassD.class, noWarmup); + runWithExcludeAndGlobalAllowNotCompilable(TestClassE.class, noWarmup); + runWithExcludeAndGlobalAllowNotCompilable(TestClassF.class, noWarmup); + runOptoNoExecuteAndGlobalAllowNotCompilable(TestClassA.class, noWarmup); + runOptoNoExecuteAndGlobalAllowNotCompilable(TestClassB.class, noWarmup); + runOptoNoExecuteAndGlobalAllowNotCompilable(TestClassC.class, noWarmup); + runOptoNoExecuteAndGlobalAllowNotCompilable(TestClassD.class, noWarmup); + runOptoNoExecuteAndGlobalAllowNotCompilable(TestClassE.class, noWarmup); + runOptoNoExecuteAndGlobalAllowNotCompilable(TestClassF.class, noWarmup); + } + + private static void runNormal(Class c, boolean noWarmup) { + TestFramework framework = new TestFramework(c); + if (noWarmup) { framework.setDefaultWarmup(0); } + framework.start(); + } + + private static void runWithExcludeExpectFailure(Class c, boolean noWarmup) { + TestFramework framework = new TestFramework(c); + framework.addFlags("-XX:CompileCommand=exclude,*TestClass*::test*"); + if (noWarmup) { framework.setDefaultWarmup(0); } + try { + framework.start(); + throw new RuntimeException("should have thrown TestRunException/TestVMException or IRViolationException"); + } catch (TestVMException e) { + // Happens when we hit the issue during explicit compilation by the Framework. + } catch (IRViolationException e) { + // Happens in STANDALONE Run case, where the user is responsible for ensuring + // compilation. The failure happens during IR matching. + } + } + + private static void runWithExcludeExpectSuccess(Class c, boolean noWarmup) { + TestFramework framework = new TestFramework(c); + framework.addFlags("-XX:CompileCommand=exclude,*TestClass*::test*"); + if (noWarmup) { framework.setDefaultWarmup(0); } + framework.start(); + } + + private static void runOptoNoExecuteExpectFailure(Class c, boolean noWarmup) { + System.out.println("runOptoNoExecuteExpectFailure: " + c + ", noWarmup: " + noWarmup); + TestFramework framework = new TestFramework(c); + framework.addFlags("-XX:CompileCommand=compileonly,*TestClass*::test*", "-XX:+OptoNoExecute"); + if (noWarmup) { framework.setDefaultWarmup(0); } + try { + framework.start(); + throw new RuntimeException("should have thrown TestRunException/TestVMException"); + } catch (TestVMException e) {} + } + + private static void runOptoNoExecuteExpectSuccess(Class c, boolean noWarmup) { + TestFramework framework = new TestFramework(c); + framework.addFlags("-XX:CompileCommand=compileonly,*TestClass*::test*", "-XX:+OptoNoExecute"); + if (noWarmup) { framework.setDefaultWarmup(0); } + framework.start(); + } + + private static void runWithExcludeAndGlobalAllowNotCompilable(Class c, boolean noWarmup) { + TestFramework framework = new TestFramework(c); + framework.addFlags("-XX:CompileCommand=exclude,*TestClass*::test*"); + if (noWarmup) { framework.setDefaultWarmup(0); } + framework.allowNotCompilable(); + framework.start(); + } + + private static void runOptoNoExecuteAndGlobalAllowNotCompilable(Class c, boolean noWarmup) { + TestFramework framework = new TestFramework(c); + framework.addFlags("-XX:CompileCommand=compileonly,*TestClass*::test*", "-XX:+OptoNoExecute"); + if (noWarmup) { framework.setDefaultWarmup(0); } + framework.allowNotCompilable(); + framework.start(); + } +} + +class TestClassA { + @Test + public void test() {} +} + +class TestClassB { + @Test + @IR(failOn = IRNode.LOAD) + public void test() {} +} + +class TestClassC { + @Test(allowNotCompilable = true) + public void test() {} +} + +class TestClassD { + @Test(allowNotCompilable = true) + @IR(failOn = IRNode.LOAD) + public void test() {} +} + +class TestClassE { + @Run(test = {"test1", "test2"}, mode = RunMode.STANDALONE) + public void run() { + for (int i = 0; i < 10_000; i++) { + test1(i); + test2(i); + } + } + + @Test + public void test1(int i) {} + + @Test + @IR(failOn = IRNode.LOAD) + public void test2(int i) {} +} + +class TestClassF { + @Run(test = {"test1", "test2"}, mode = RunMode.STANDALONE) + public void run() { + for (int i = 0; i < 10_000; i++) { + test1(i); + test2(i); + } + } + + @Test(allowNotCompilable = true) + public void test1(int i) {} + + @Test(allowNotCompilable = true) + @IR(failOn = IRNode.LOAD) + public void test2(int i) {} +} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java index 3c4b769eaae..ca0e37de166 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,8 +66,8 @@ public class TestPhaseIRMatching { List noAdditionalFlags = new ArrayList<>(); FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, noAdditionalFlags); List testVMFlags = flagVMProcess.getTestVMFlags(); - TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1, false); - TestClassParser testClassParser = new TestClassParser(testClass); + TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1, false, false); + TestClassParser testClassParser = new TestClassParser(testClass, false); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), testVMProcess.getIrEncoding()); MatchResult result = testClassMatchable.match(); @@ -398,6 +398,11 @@ class FailureBuilder implements MatchResultVisitor { failures.add(new Failure(methodName, -1, CompilePhase.DEFAULT, CheckAttributeType.FAIL_ON, -1)); } + @Override + public void visitMethodNotCompilable(Method method, int failedIRRules) { + throw new RuntimeException("No test should bailout from compilation"); + } + @Override public void visitIRRule(AcceptChildren acceptChildren, int irRuleId, IR irAnno) { ruleId = irRuleId;