Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8254129: IR Test Framework to support regex-based matching on the IR in JTreg compiler tests #3508

Closed
wants to merge 29 commits into from
Closed
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a563fb3
8254129: IR Test Framework to support regex-based matching on the IR …
chhagedorn Apr 13, 2021
aa005f3
Add Javadoc files
chhagedorn Apr 14, 2021
5ada49e
Fix whitespaces
chhagedorn Apr 15, 2021
4ec7f0e
Fix whitespaces + minor fix
chhagedorn Apr 15, 2021
cc6e285
Remove accidentally added print statement
chhagedorn Apr 15, 2021
e284341
Fix comment
chhagedorn Apr 15, 2021
7ed789d
Adjust whitelist
chhagedorn Apr 15, 2021
b3f5811
Apply review comments in code from Igor I. and Vladimir K.
chhagedorn Apr 19, 2021
6e5a954
Fix typos and grammar, code format (JohnTortugo), fix exception throw…
chhagedorn Apr 20, 2021
5451ad2
Replace "\n" by System.lineSeparator()
chhagedorn Apr 20, 2021
433006c
Improve error format output by changing some new lines
chhagedorn Apr 20, 2021
72eece6
Remove Javadocs and README.html, update README.md to reference java f…
chhagedorn Apr 20, 2021
0720a33
Review comments by Tobias: Formatting fields, spacing, README.md typo…
chhagedorn Apr 23, 2021
0a3cc3f
Apply review comments: Added new Compiler annotation class for @DontC…
chhagedorn Apr 27, 2021
90a0064
Fix XCOMP cases from old framework and turn it into new debug flag -D…
chhagedorn Apr 27, 2021
5890c4a
Apply review comments: Extract Test classes into own files, extract F…
chhagedorn May 3, 2021
8f56dd6
Rename TestFrameworkPrepareFlags -> FlagVM and rename TestFrameworkEx…
chhagedorn May 3, 2021
b08235c
Minor improvements, comment fixes, and test fixes
chhagedorn May 3, 2021
d6c72ec
Remove TestFramework: both runWithScenarios, both runWithHelperClasse…
chhagedorn May 3, 2021
fd25de7
Move framework to test/hotspot/jtreg/compiler/lib and tests to test/h…
chhagedorn May 4, 2021
a9f0429
Fix package names and fixing internal tests, examples and README file…
chhagedorn May 4, 2021
4424e01
Splitting classes into subpackages and updating README accordingly, f…
chhagedorn May 4, 2021
85a5921
Merge branch 'master' into JDK-8254129
chhagedorn May 31, 2021
c35c658
Fix Compiler and CompLevel ANY and fix tests after merge
chhagedorn May 31, 2021
7a316de
Add more whitelisted flags
chhagedorn Jun 2, 2021
df7576f
Fix failing internal tests on Windows and add missing flag descriptio…
chhagedorn Jun 3, 2021
2ba1338
Move tests and examples #1
chhagedorn Jun 4, 2021
e6b2f60
Move tests and examples #2
chhagedorn Jun 4, 2021
7b77370
Update test and example package names, README files and fix some test…
chhagedorn Jun 4, 2021
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
@@ -40,7 +40,7 @@
* @see Run
*/
abstract public class AbstractInfo {
private static final Random random = Utils.getRandomInstance();
private static final Random RANDOM = Utils.getRandomInstance();

protected final Class<?> testClass;
private boolean onWarmUp = true;
@@ -55,7 +55,7 @@
* @return the random object.
*/
public Random getRandom() {
return random;
return RANDOM;
}

/**
@@ -84,7 +84,7 @@ public Method getMethod(Class<?> c, String name, Class<?>... args) {
} catch (NoSuchMethodException e) {
String parameters = args == null || args.length == 0 ? "" :
" with arguments [" + Arrays.stream(args).map(Class::getName).collect(Collectors.joining(",")) + "]";
throw new TestRunException("Could not find method " + name + " in " + c + parameters);
throw new TestRunException("Could not find method " + name + " in " + c + parameters, e);
}
}

@@ -77,5 +77,5 @@
* Provides a different random primitive value on each test invocation.
* Float and double values are restricted to the range [-10000,10000].
*/
RANDOM_EACH
RANDOM_EACH,
}
@@ -34,7 +34,7 @@
* This class represents an argument value specified by {@link Argument} in {@link Arguments}.
*/
class ArgumentValue {
private static final Random random = Utils.getRandomInstance();
private static final Random RANDOM = Utils.getRandomInstance();

private final Object argumentValue;
private final boolean isRandomEach;
@@ -282,23 +282,23 @@ private static boolean isFloatNumber(Class<?> c) {

private static Object getRandom(Class<?> c) {
if (isBoolean(c)) {
return random.nextBoolean();
return RANDOM.nextBoolean();
} else if (c.equals(byte.class)) {
return (byte)random.nextInt(256);
return (byte) RANDOM.nextInt(256);
} else if (isChar(c)) {
return (char)random.nextInt(65536);
return (char) RANDOM.nextInt(65536);
} else if (c.equals(short.class)) {
return (short)random.nextInt(65536);
return (short) RANDOM.nextInt(65536);
} else if (c.equals(int.class)) {
return random.nextInt();
return RANDOM.nextInt();
} else if (c.equals(long.class)) {
return random.nextLong();
return RANDOM.nextLong();
} else if (c.equals(float.class)) {
// Get float between -10000 and 10000.
return random.nextFloat() * 20000 - 10000;
return RANDOM.nextFloat() * 20000 - 10000;
} else if (c.equals(double.class)) {
// Get double between -10000 and 10000.
return random.nextDouble() * 20000 - 10000;
return RANDOM.nextDouble() * 20000 - 10000;
} else {
TestFormat.fail("Cannot generate random value for non-primitive type");
return null;
@@ -39,5 +39,5 @@
* Invoke the {@link Check} method only once after the warm-up of the associated {@link Test} method had been completed
* and the framework has compiled the associated {@link Test} method.
*/
COMPILED
COMPILED,
}
@@ -23,27 +23,32 @@

package jdk.test.lib.hotspot.ir_framework;

import jdk.test.lib.Utils;

import java.lang.reflect.Executable;
import java.util.HashMap;
import java.util.Map;

/**
* Compilation levels used by the framework. The compilation levels map to the used levels in HotSpot (apart from the
* framework specific values {@link #SKIP} and {@link #WAIT_FOR_COMPILATION} that cannot be found in HotSpot).
* Compilation levels used by the framework to initiate a compilation of a method. The compilation levels map to the used
* levels in HotSpot (apart from the framework specific values {@link #SKIP} and {@link #WAIT_FOR_COMPILATION} that cannot
* be found in HotSpot). The HotSpot specific levels must be in sync with hotspot/share/compiler/compilerDefinitions.hpp.
*
* <p>
* The compilation levels can be specified in the {@link Test}, {@link ForceCompile} and {@link DontCompile} annotation.
*
* The compilation levels can be specified in the {@link Test}, {@link ForceCompile}, and
* {@link ForceCompileClassInitializer} annotation.
*
* @see Test
* @see ForceCompile
* @see DontCompile
* @see ForceCompileClassInitializer
*/
public enum CompLevel {
/**
* Can only be used at {@link Test#compLevel()}. After the warm-up, the framework keeps invoking the test over a span
* of 10s (configurable by setting the property flag {@code -DWaitForCompilationTimeout}) until HotSpot compiles the
* {@link Test} method. If the method was not compiled after 10s, an exception is thrown. The framework does not wait
* for the compilation if the test VM is run with {@code -Xcomp}, {@code -XX:-UseCompiler} or {@code -DStressCC=true}.
* for the compilation if the test VM is run with {@code -Xcomp}, {@code -XX:-UseCompiler}, or
* {@code -DExcludeRandom=true}.
*/
WAIT_FOR_COMPILATION(-4),
/**
@@ -62,7 +67,7 @@
/**

This comment has been minimized.

Loading
@vnkozlov

vnkozlov Apr 15, 2021
Contributor Outdated

For completeness may be add value NONE(0) for Interpreter only case.

This comment has been minimized.

Loading
@chhagedorn

chhagedorn Apr 19, 2021
Author Member Outdated

I agree that it makes sense for completeness. But I'm not sure if this is useful to have as NONE would not be supported by the framework for the time being and would just require additional handling, informing the user that this has no effect.

* Compilation level 1: C1 compilation without any profile information.
*/
C1(1),
C1_SIMPLE(1),
/**
* Compilation level 2: C1 compilation with limited profile information: Includes Invocation and backedge counters.
*/
@@ -74,14 +79,16 @@
/**
* Compilation level 4: C2 compilation with full optimizations.
*/
C2(4);
C2(4),

;

private static final Map<Integer, CompLevel> typesByValue = new HashMap<>();
private static final Map<Integer, CompLevel> TYPES_BY_VALUE = new HashMap<>();
private final int value;

static {
for (CompLevel level : CompLevel.values()) {
typesByValue.put(level.value, level);
TYPES_BY_VALUE.put(level.value, level);
}
}

@@ -106,28 +113,54 @@ public int getValue() {
* @return the compilation level enum for {@code value}.
*/
public static CompLevel forValue(int value) {
CompLevel level = typesByValue.get(value);
CompLevel level = TYPES_BY_VALUE.get(value);
TestRun.check(level != null, "Invalid compilation level " + value);
return level;
}

/**
* Checks if two compilation levels are overlapping.
* Checks if this compilation level is not part of the compiler.
*/
boolean isNotCompilationLevelOfCompiler(Compiler c) {
return switch (c) {
case C1 -> !isC1();
case C2 -> this != C2;
default -> throw new TestFrameworkException("Should not be called with compiler " + c);
};
}

/**
* Flip the compilation levels.
*/
static boolean overlapping(CompLevel l1, CompLevel l2) {
return l1.isC1() == l2.isC1() || (l1 == C2 && l2 == C2);
CompLevel flipCompLevel() {
switch (this) {
case C1_SIMPLE, C1_LIMITED_PROFILE, C1_FULL_PROFILE -> {
return CompLevel.C2;
}
case C2 -> {
return CompLevel.C1_SIMPLE;
}
}
return this;
}

static CompLevel join(CompLevel l1, CompLevel l2) {
return switch (l1) {
case ANY -> l2;
case C1, C1_LIMITED_PROFILE, C1_FULL_PROFILE -> l2.isC1() || l2 == ANY ? C1 : SKIP;
case C2 -> l2 == C2 || l2 == ANY ? C2 : SKIP;
default -> SKIP;
/**
* Return the compilation level when only allowing a compilation with the specified compiler.
*/
CompLevel excludeCompilationRandomly(Executable ex) {
if (Utils.getRandomInstance().nextBoolean()) {
// No exclusion
return this;
}
Compiler compiler = TestFrameworkExecution.excludeRandomly(ex);
return switch (compiler) {
case ANY -> SKIP;
case C1 -> isC1() ? SKIP : this;
case C2 -> this == C2 ? SKIP : this;
};
}

private boolean isC1() {
return this == C1 || this == C1_LIMITED_PROFILE || this == C1_FULL_PROFILE;
return this == C1_SIMPLE || this == C1_LIMITED_PROFILE || this == C1_FULL_PROFILE;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2021, 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 jdk.test.lib.hotspot.ir_framework;

/**
* Compilers to select for {@link DontCompile}. HotSpot does not handle the exclusion of a C1 method at a specific level.
* It can only exclude a method for the entire C1 compilation. Thus, this annotation is provided for {@link DontCompile}
* instead of {@link CompLevel}.
*
* @see DontCompile
*/
public enum Compiler {
/**
* Selecting both the C1 and C2 compiler. This must be in sync with hotspot/share/compiler/compilerDefinitions.hpp.
*/
ANY(-2),
/**
* The C1 compiler.
*/
C1(1),
/**
* The C2 compiler.
*/
C2(4),

;

private final int value;

Compiler(int level) {
this.value = level;
}

/**
* Get the compilation level as integer value. These will match the levels specified in HotSpot (if available).
*
* @return the compilation level as integer.
*/
public int getValue() {
return value;
}
}
@@ -83,11 +83,11 @@ public void printFixedRandomArguments() {
if (argument.isFixedRandom()) {
hasRandomArgs = true;
Object argumentVal = argument.getArgument();
String argumentValString = argumentVal.toString();
builder.append("arg ").append(i).append(": ").append(argumentVal.toString());
if (argumentVal instanceof Character) {
argumentValString += " (" + (int)(Character)argumentVal + ")";
builder.append(" (").append((int)(Character)argumentVal).append(")");
}
builder.append("arg ").append(i).append(": ").append(argumentValString).append(", ");
builder.append(", ");
}
}
if (hasRandomArgs) {
@@ -28,22 +28,20 @@

/**
* Prevent a compilation of the annotated <b>helper method</b> (not specifying {@link Test @Test},
* {@link Check @Check} or {@link Run @Run}):
* {@link Check @Check} or {@link Run @Run}) with the specified compiler.
*
* <ul>
* <li><p>{@link CompLevel#ANY} (default): No C1 or C2 compilation.</li>
* <li><p>{@link CompLevel#C1}: No C1 compilation, C2 compilation still possible.</li>
* <li><p>{@link CompLevel#C2}: No C2 compilation, C1 compilation still possible.</li>
* <li><p>The usage of any other compilation level is forbidden and results in a
* {@link TestFormatException TestFormatException}.</li>
* <li><p>{@link Compiler#ANY} (default): No C1 or C2 compilation.</li>
* <li><p>{@link Compiler#C1}: No C1 compilation, C2 compilation still possible.</li>
* <li><p>{@link Compiler#C2}: No C2 compilation, C1 compilation still possible.</li>
* </ul>
* <p>
* Using this annotation on <i>non-helper methods</i> results in a {@link TestFormatException TestFormatException}.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface DontCompile {
/**
* The excluded compilation level for the helper method.
* The compiler with which a compilation of a helper method is excluded.
*/
CompLevel value() default CompLevel.ANY;
Compiler value() default Compiler.ANY;
}
@@ -27,24 +27,12 @@
import java.lang.annotation.RetentionPolicy;

/**
* Force a compilation of the annotated <b>helper method</b> (not specifying {@link Test @Test},
* {@link Check @Check} or {@link Test @Run}) immediately at the specified level:
* <ul>
* <li><p>{@link CompLevel#ANY} (default): Highest available compilation level is selected which is usually
* {@link CompLevel#C2}</li>
* <li><p>{@link CompLevel#C1}: Level 1: C1 compilation without any profile information.</li>
* <li><p>{@link CompLevel#C1_LIMITED_PROFILE}: Level 2: C1 compilation with limited profile information:
* Includes Invocation and backedge counters.</li>
* <li><p>{@link CompLevel#C1_FULL_PROFILE}: Level 3: C1 compilation with full profile information:
* Includes Invocation and backedge counters with MDO.</li>
* <li><p>{@link CompLevel#C2}: Level 4: C2 compilation with full optimizations.</li>
* <li><p>{@link CompLevel#SKIP}: Does not apply to {@code @ForceCompile} and results in a
* {@link TestFormatException}.</li>
* <li><p>{@link CompLevel#WAIT_FOR_COMPILATION}: Does not apply to {@code @ForceCompile} and results in a
* {@link TestFormatException}.</li>
* </ul>
* Force a compilation of the annotated <b>helper method</b> (not specifying {@link Test @Test}, {@link Check @Check},
* or {@link Test @Run}) immediately at the specified level. {@link CompLevel#SKIP} and
* {@link CompLevel#WAIT_FOR_COMPILATION} do not apply and result in a {@link TestFormatException}.
*
* <p>
* Using this annotation on <i>non-helper</i> methods results in a {@link TestFormatException}.
* Using this annotation on <i>non-helper</i> methods also results in a {@link TestFormatException}.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ForceCompile {
@@ -28,23 +28,11 @@

/**
* Force a compilation of the static class initializer method ({@code <clinit>}) of the annotated test or helper class
* immediately at the specified level:
* <ul>
* <li><p>{@link CompLevel#ANY} (default): Highest available compilation level is selected which is usually
* {@link CompLevel#C2}</li>
* <li><p>{@link CompLevel#C1}: Level 1: C1 compilation without any profile information.</li>
* <li><p>{@link CompLevel#C1_LIMITED_PROFILE}: Level 2: C1 compilation with limited profile information:
* Includes Invocation and backedge counters.</li>
* <li><p>{@link CompLevel#C1_FULL_PROFILE}: Level 3: C1 compilation with full profile information:
* Includes Invocation and backedge counters with MDO.</li>
* <li><p>{@link CompLevel#C2}: Level 4: C2 compilation with full optimizations.</li>
* <li><p>{@link CompLevel#SKIP}: Does not apply to {@code @ForceCompileClassInitializer} and results in a
* {@link TestFormatException}.</li>
* <li><p>{@link CompLevel#WAIT_FOR_COMPILATION}: Does not apply to {@code @ForceCompileClassInitializer} and results in a
* {@link TestFormatException}.</li>
* </ul>
* immediately at the specified level. {@link CompLevel#SKIP} and {@link CompLevel#WAIT_FOR_COMPILATION} do not apply
* and result in a {@link TestFormatException}.
* <p>
* Using this annotation on non-classes results in a {@link TestFormatException}.
* Using this annotation on non-classes also results in a {@link TestFormatException}.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ForceCompileClassInitializer {
@@ -43,7 +43,7 @@
public static final int NO_RULE_APPLIED = -1;

private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
private static final List<Function<String, Object>> longGetters = Arrays.asList(
private static final List<Function<String, Object>> LONG_GETTERS = Arrays.asList(
WHITE_BOX::getIntVMFlag, WHITE_BOX::getUintVMFlag, WHITE_BOX::getIntxVMFlag,
WHITE_BOX::getUintxVMFlag, WHITE_BOX::getUint64VMFlag, WHITE_BOX::getSizeTVMFlag);

@@ -185,7 +185,7 @@ private boolean check(String flag, String value) {
if (actualFlagValue != null) {
return checkBooleanFlag(flag, value, (Boolean) actualFlagValue);
}
actualFlagValue = longGetters.stream().map(f -> f.apply(flag)).filter(Objects::nonNull).findAny().orElse(null);
actualFlagValue = LONG_GETTERS.stream().map(f -> f.apply(flag)).filter(Objects::nonNull).findAny().orElse(null);
if (actualFlagValue != null) {
return checkLongFlag(flag, value, (Long) actualFlagValue);
}
Loading