8281122: [IR Framework] Cleanup IR matching code in preparation for JDK-8280378

Reviewed-by: thartmann, kvn
This commit is contained in:
Christian Hagedorn 2022-03-03 07:17:56 +00:00
parent d0eb6fa220
commit 2da677793f
56 changed files with 2739 additions and 752 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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,7 +23,7 @@
package compiler.lib.ir_framework;
import compiler.lib.ir_framework.driver.IRViolationException;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
@ -58,8 +58,8 @@ import java.lang.annotation.RetentionPolicy;
* If the specified preconditions fail, then the framework does not apply the IR rule. These preconditions can be
* set with {@link #applyIf()}, {@link #applyIfNot()}, {@link #applyIfAnd()}, or {@link #applyIfOr()}.
* <p>
* Examples on how to write tests with IR rules can be found in {@link jdk.test.lib.hotspot.ir_framework.examples.IRExample}
* and also as part of the internal testing in {@link jdk.test.lib.hotspot.ir_framework.tests.TestIRMatching}.
* Examples on how to write tests with IR rules can be found in {@link ir_framework.examples.IRExample}
* and also as part of the internal testing in {@link ir_framework.tests.TestIRMatching}.
*
* @see Test
* @see IRNode

View file

@ -23,7 +23,7 @@
package compiler.lib.ir_framework;
import compiler.lib.ir_framework.driver.IRMatcher;
import compiler.lib.ir_framework.driver.irmatching.IRMatcher;
import compiler.lib.ir_framework.shared.*;
import jdk.test.lib.Platform;
import sun.hotspot.WhiteBox;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,6 +24,8 @@
package compiler.lib.ir_framework;
import compiler.lib.ir_framework.driver.*;
import compiler.lib.ir_framework.driver.irmatching.IRMatcher;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
import compiler.lib.ir_framework.shared.*;
import compiler.lib.ir_framework.test.*;
import jdk.test.lib.Platform;
@ -603,11 +605,11 @@ public class TestFramework {
// Print stack trace otherwise
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
builder.append(errors.toString());
builder.append(errors);
}
builder.append(System.lineSeparator());
}
System.err.println(builder.toString());
System.err.println(builder);
if (!VERBOSE && !REPORT_STDOUT && !TESTLIST && !EXCLUDELIST) {
// Provide a hint to the user how to get additional output/debugging information.
System.err.println(RERUN_HINT);

View file

@ -1,504 +0,0 @@
/*
* 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 compiler.lib.ir_framework.driver;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.shared.*;
import compiler.lib.ir_framework.test.*;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parse the hotspot pid file of the test VM to match all @IR rules.
*/
public class IRMatcher {
public static final String SAFEPOINT_WHILE_PRINTING_MESSAGE = "<!-- safepoint while printing -->";
private static final boolean PRINT_IR_ENCODING = Boolean.parseBoolean(System.getProperty("PrintIREncoding", "false"));
private static final Pattern IR_ENCODING_PATTERN =
Pattern.compile("(?<=" + IREncodingPrinter.START + "\r?\n)[\\s\\S]*(?=" + IREncodingPrinter.END + ")");
private static final Pattern COMPILE_ID_PATTERN = Pattern.compile("compile_id='(\\d+)'");
private final Map<String, IRMethod> compilations;
private final Class<?> testClass;
private final Map<Method, List<String>> fails;
private final Pattern compileIdPatternForTestClass;
private final String hotspotPidFileName;
private IRMethod irMethod; // Current IR method to which rules are applied
private Method method; // Current method to which rules are applied
private IR irAnno; // Current IR annotation that is processed.
private int irRuleIndex; // Current IR rule index;
public IRMatcher(String hotspotPidFileName, String irEncoding, Class<?> testClass) {
this.compilations = new HashMap<>();
this.fails = new HashMap<>();
this.testClass = testClass;
this.compileIdPatternForTestClass = Pattern.compile("compile_id='(\\d+)'.*" + Pattern.quote(testClass.getCanonicalName())
+ " (\\S+)");
this.hotspotPidFileName = hotspotPidFileName;
setupTestMethods(irEncoding);
if (TestFramework.VERBOSE || PRINT_IR_ENCODING) {
System.out.println("Read IR encoding from test VM:");
System.out.println(irEncoding);
}
if (!compilations.isEmpty()) {
parseHotspotPidFile();
applyRules();
}
}
/**
* Sets up a map testname -> IRMethod (containing the PrintIdeal and PrintOptoAssembly output for testname).
*/
private void setupTestMethods(String irEncoding) {
Map<String, int[]> irRulesMap = parseIREncoding(irEncoding);
for (Method m : testClass.getDeclaredMethods()) {
method = m;
IR[] irAnnos = m.getAnnotationsByType(IR.class);
if (irAnnos.length > 0) {
// Validation of legal @IR attributes and placement of the annotation was already done in Test VM.
int[] ids = irRulesMap.get(m.getName());
TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m);
TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m);
TestFramework.check(ids[ids.length - 1] < irAnnos.length, "Invalid IR rule index found in validIrRulesMap for " + m);
if (ids[0] != IREncodingPrinter.NO_RULE_APPLIED) {
// If -1, than there was no matching IR rule for the given conditions.
compilations.put(m.getName(), new IRMethod(m, ids, irAnnos));
}
}
}
}
/**
* Read the IR encoding emitted by the test VM to decide if an @IR rule must be checked for a method.
*/
private Map<String, int[]> parseIREncoding(String irEncoding) {
Map<String, int[]> irRulesMap = new HashMap<>();
Matcher matcher = IR_ENCODING_PATTERN.matcher(irEncoding);
TestFramework.check(matcher.find(), "Did not find IR encoding");
String[] lines = matcher.group(0).split("\\R");
// Skip first line containing information about the format only
for (int i = 1; i < lines.length; i++) {
String line = lines[i].trim();
String[] splitComma = line.split(",");
if (splitComma.length < 2) {
throw new TestFrameworkException("Invalid IR match rule encoding. No comma found: " + splitComma[0]);
}
String testName = splitComma[0];
int[] irRulesIdx = new int[splitComma.length - 1];
for (int j = 1; j < splitComma.length; j++) {
try {
irRulesIdx[j - 1] = Integer.parseInt(splitComma[j]);
} catch (NumberFormatException e) {
throw new TestFrameworkException("Invalid IR match rule encoding. No number found: " + splitComma[j]);
}
}
irRulesMap.put(testName, irRulesIdx);
}
return irRulesMap;
}
/**
* Parse the hotspot_pid*.log file from the test VM. Read the PrintIdeal and PrintOptoAssembly entries for all
* methods of the test class that need to be IR matched (according to IR encoding).
*/
private void parseHotspotPidFile() {
Map<Integer, String> compileIdMap = new HashMap<>();
try (var br = Files.newBufferedReader(Paths.get(hotspotPidFileName))) {
String line;
StringBuilder builder = new StringBuilder();
boolean append = false;
String currentMethod = "";
while ((line = br.readLine()) != null) {
if (append && line.startsWith("</")) {
flushOutput(line, builder, currentMethod);
append = false;
currentMethod = "";
continue;
} else if (append) {
appendLine(builder, line);
continue;
}
if (maybeTestEntry(line)) {
addTestMethodCompileId(compileIdMap, line);
} else if (isPrintIdealStart(line)) {
String methodName = getMethodName(compileIdMap, line);
if (methodName != null) {
currentMethod = methodName;
append = true; // Append all following lines until we hit the closing </ideal> tag.
}
} else if (isPrintOptoAssemblyStart(line)) {
String methodName = getMethodName(compileIdMap, line);
if (methodName != null) {
TestFramework.check(compilations.containsKey(methodName), "Must be second entry of " + methodName);
currentMethod = methodName;
append = true; // Append all following lines until we hit the closing </opto_assembly> tag.
}
}
}
} catch (IOException e) {
throw new TestFrameworkException("Error while reading " + hotspotPidFileName, e);
}
}
/**
* Write the input to the IR method and reset the builder.
*/
private void flushOutput(String line, StringBuilder builder, String currentMethod) {
TestFramework.check(!currentMethod.isEmpty(), "current method must be set");
IRMethod irMethod = compilations.get(currentMethod);
if (line.startsWith("</i")) {
// PrintIdeal
irMethod.setIdealOutput(builder.toString());
} else {
// PrintOptoAssembly
irMethod.setOptoAssemblyOutput(builder.toString());
}
builder.setLength(0);
}
/**
* Only consider non-osr (no "compile_kind") and compilations with C2 (no "level")
*/
private boolean maybeTestEntry(String line) {
return line.startsWith("<task_queued") && !line.contains("compile_kind='") && !line.contains("level='");
}
/**
* Need to escape XML special characters.
*/
private static void appendLine(StringBuilder builder, String line) {
if (line.contains("&")) {
line = line.replace("&lt;", "<");
line = line.replace("&gt;", ">");
line = line.replace("&quot;", "\"");
line = line.replace("&apos;", "'");
line = line.replace("&amp;", "&");
}
builder.append(line).append(System.lineSeparator());
}
private static int getCompileId(Matcher matcher) {
int compileId;
try {
compileId = Integer.parseInt(matcher.group(1));
} catch (NumberFormatException e) {
throw new TestRunException("Could not parse compile id", e);
}
return compileId;
}
/**
* Parse the compile id from this line if it belongs to a method that needs to be IR tested (part of test class
* and IR encoding from the test VM specifies that this method has @IR rules to be checked).
*/
private void addTestMethodCompileId(Map<Integer, String> compileIdMap, String line) {
Matcher matcher = compileIdPatternForTestClass.matcher(line);
if (matcher.find()) {
// Only care about test class entries. Might have non-class entries as well if user specified additional
// compile commands. Ignore these.
String methodName = matcher.group(2);
if (compilations.containsKey(methodName)) {
// We only care about methods that we are actually gonna IR match based on IR encoding.
int compileId = getCompileId(matcher);
TestRun.check(!methodName.isEmpty(), "method name cannot be empty");
compileIdMap.put(compileId, methodName);
}
}
}
/**
* Make sure that line does not contain compile_kind which is used for OSR compilations which we are not
* interested in.
*/
private static boolean isPrintIdealStart(String line) {
return line.startsWith("<ideal") && !line.contains("compile_kind='");
}
/**
* Make sure that line does not contain compile_kind which is used for OSR compilations which we are not
* interested in.
*/
private static boolean isPrintOptoAssemblyStart(String line) {
return line.startsWith("<opto_assembly") && !line.contains("compile_kind='");
}
/**
* Get method name for this line by looking up the compile id.
* Returns null if not an interesting method (i.e. from test class).
*/
private String getMethodName(Map<Integer, String> compileIdMap, String line) {
Matcher matcher = COMPILE_ID_PATTERN.matcher(line);
TestFramework.check(matcher.find(), "Is " + hotspotPidFileName + " corrupted?");
int compileId = getCompileId(matcher);
return compileIdMap.get(compileId);
}
/**
* Do an IR matching of all methods with appliable @IR rules fetched during parsing of the hotspot pid file.
*/
private void applyRules() {
compilations.values().forEach(this::applyRulesForMethod);
reportFailuresIfAny();
}
private void applyRulesForMethod(IRMethod irMethod) {
this.irMethod = irMethod;
method = irMethod.getMethod();
String testOutput = irMethod.getOutput();
if (testOutput.isEmpty()) {
String msg = "Method was not compiled. Did you specify any compiler directives preventing a compilation or used a " +
"@Run method in STANDALONE mode? In the latter case, make sure to always trigger a C2 compilation " +
"by invoking the test enough times.";
fails.computeIfAbsent(method, k -> new ArrayList<>()).add(msg);
return;
}
if (TestFramework.VERBOSE) {
System.out.println("Output of " + method + ":");
System.out.println(testOutput);
}
Arrays.stream(irMethod.getRuleIds()).forEach(this::applyIRRule);
}
/**
* Apply a single @IR rule as part of a method.
*/
private void applyIRRule(int id) {
irAnno = irMethod.getIrAnno(id);
irRuleIndex = id;
StringBuilder failMsg = new StringBuilder();
applyFailOn(failMsg);
try {
applyCounts(failMsg);
} catch (TestFormatException e) {
// Logged. Continue to check other rules.
}
if (!failMsg.isEmpty()) {
failMsg.insert(0, "@IR rule " + (id + 1) + ": \"" + irAnno + "\"" + System.lineSeparator());
fails.computeIfAbsent(method, k -> new ArrayList<>()).add(failMsg.toString());
}
}
/**
* Apply the failOn regexes of the @IR rule.
*/
private void applyFailOn(StringBuilder failMsg) {
if (irAnno.failOn().length != 0) {
String failOnRegex = String.join("|", IRNode.mergeNodes(irAnno.failOn()));
Pattern pattern = Pattern.compile(failOnRegex);
Matcher matcher = pattern.matcher(irMethod.getOutput());
long matchCount = matcher.results().count();
if (matchCount > 0) {
addFailOnFailsForOutput(failMsg, pattern, matchCount);
}
}
}
/**
* A failOn regex failed. Apply all regexes again to log the exact regex which failed. The failure is later reported
* to the user.
*/
private void addFailOnFailsForOutput(StringBuilder failMsg, Pattern pattern, long matchCount) {
long idealCount = pattern.matcher(irMethod.getIdealOutput()).results().count();
long optoAssemblyCount = pattern.matcher(irMethod.getOptoAssemblyOutput()).results().count();
if (matchCount != idealCount + optoAssemblyCount || (idealCount != 0 && optoAssemblyCount != 0)) {
// Report with Ideal and Opto Assembly
addFailOnFailsForOutput(failMsg, irMethod.getOutput());
irMethod.needsAllOutput();
} else if (optoAssemblyCount == 0) {
// Report with Ideal only
addFailOnFailsForOutput(failMsg, irMethod.getIdealOutput());
irMethod.needsIdeal();
} else {
// Report with Opto Assembly only
addFailOnFailsForOutput(failMsg, irMethod.getOptoAssemblyOutput());
irMethod.needsOptoAssembly();
}
}
/**
* Apply the regexes to the testOutput and log the failures.
*/
private void addFailOnFailsForOutput(StringBuilder failMsg, String testOutput) {
List<String> failOnNodes = IRNode.mergeNodes(irAnno.failOn());
Pattern pattern;
Matcher matcher;
failMsg.append("- failOn: Graph contains forbidden nodes:").append(System.lineSeparator());
int nodeId = 1;
for (String nodeRegex : failOnNodes) {
pattern = Pattern.compile(nodeRegex);
matcher = pattern.matcher(testOutput);
long matchCount = matcher.results().count();
if (matchCount > 0) {
matcher.reset();
failMsg.append(" Regex ").append(nodeId).append(": ").append(nodeRegex).append(System.lineSeparator());
failMsg.append(" Matched forbidden node").append(matchCount > 1 ? "s (" + matchCount + ")" : "")
.append(":").append(System.lineSeparator());
matcher.results().forEach(r -> failMsg.append(" ").append(r.group()).append(System.lineSeparator()));
}
nodeId++;
}
}
/**
* Apply the counts regexes of the @IR rule.
*/
private void applyCounts(StringBuilder failMsg) {
if (irAnno.counts().length != 0) {
boolean hasFails = false;
String testOutput = irMethod.getOutput();
int countsId = 1;
final List<String> nodesWithCount = IRNode.mergeNodes(irAnno.counts());
for (int i = 0; i < nodesWithCount.size(); i += 2) {
String node = nodesWithCount.get(i);
TestFormat.check(i + 1 < nodesWithCount.size(), "Missing count" + getPostfixErrorMsg(node));
String countString = nodesWithCount.get(i + 1);
long expectedCount;
ParsedComparator<Long> parsedComparator;
try {
parsedComparator = ParsedComparator.parseComparator(countString);
expectedCount = Long.parseLong(parsedComparator.getStrippedString());
} catch (NumberFormatException e) {
TestFormat.fail("Provided invalid count \"" + countString + "\"" + getPostfixErrorMsg(node));
return;
} catch (CheckedTestFrameworkException e) {
TestFormat.fail("Invalid comparator \"" + e.getMessage() + "\" in \"" + countString + "\" for count" + getPostfixErrorMsg(node));
return;
} catch (IndexOutOfBoundsException e) {
TestFormat.fail("Provided empty value" + getPostfixErrorMsg(node));
return;
}
TestFormat.check(expectedCount >= 0,"Provided invalid negative count \"" + countString + "\"" + getPostfixErrorMsg(node));
Pattern pattern = Pattern.compile(node);
Matcher matcher = pattern.matcher(testOutput);
long actualCount = matcher.results().count();
if (!parsedComparator.getPredicate().test(actualCount, expectedCount)) {
if (!hasFails) {
failMsg.append("- counts: Graph contains wrong number of nodes:").append(System.lineSeparator());
hasFails = true;
}
addCountsFail(failMsg, node, pattern, expectedCount, actualCount, countsId);
}
countsId++;
}
}
}
private String getPostfixErrorMsg(String node) {
return " for IR rule " + irRuleIndex + ", node \"" + node + "\" at " + method;
}
/**
* A counts regex failed. Apply all regexes again to log the exact regex which failed. The failure is later reported
* to the user.
*/
private void addCountsFail(StringBuilder failMsg, String node, Pattern pattern, long expectedCount, long actualCount, int countsId) {
failMsg.append(" Regex ").append(countsId).append(": ").append(node).append(System.lineSeparator());
failMsg.append(" Expected ").append(expectedCount).append(" but found ").append(actualCount);
if (actualCount > 0) {
Matcher matcher = pattern.matcher(irMethod.getOutput());
long idealCount = pattern.matcher(irMethod.getIdealOutput()).results().count();
long optoAssemblyCount = pattern.matcher(irMethod.getOptoAssemblyOutput()).results().count();
if (actualCount != idealCount + optoAssemblyCount || (idealCount != 0 && optoAssemblyCount != 0)) {
irMethod.needsAllOutput();
} else if (optoAssemblyCount == 0) {
irMethod.needsIdeal();
} else {
irMethod.needsOptoAssembly();
}
failMsg.append(" node").append(actualCount > 1 ? "s" : "").append(":").append(System.lineSeparator());
matcher.results().forEach(r -> failMsg.append(" ").append(r.group()).append(System.lineSeparator()));
} else {
irMethod.needsAllOutput();
failMsg.append(" nodes.").append(System.lineSeparator());
}
}
/**
* Report all IR violations in a pretty format to the user. Depending on the failed regex, we only report
* PrintIdeal or PrintOptoAssembly if the match failed there. If there were failures that matched things
* in both outputs than the entire output is reported. Throws IRViolationException from which the compilation
* can be read and reported to the stdout separately. The exception message only includes the summary of the
* failures.
*/
private void reportFailuresIfAny() {
TestFormat.reportIfAnyFailures();
if (!fails.isEmpty()) {
StringBuilder failuresBuilder = new StringBuilder();
StringBuilder compilationsBuilder = new StringBuilder();
int failures = 0;
for (Map.Entry<Method, List<String>> entry : fails.entrySet()) {
Method method = entry.getKey();
compilationsBuilder.append(">>> Compilation of ").append(method).append(":").append(System.lineSeparator());
IRMethod irMethod = compilations.get(method.getName());
String output;
if (irMethod.usesIdeal() && irMethod.usesOptoAssembly()) {
output = irMethod.getOutput();
} else if (irMethod.usesIdeal()) {
output = irMethod.getIdealOutput();
} else if (irMethod.usesOptoAssembly()) {
output = irMethod.getOptoAssemblyOutput();
} else {
output = "<empty>";
}
compilationsBuilder.append(output).append(System.lineSeparator()).append(System.lineSeparator());
List<String> list = entry.getValue();
failuresBuilder.append("- Method \"").append(method).append("\":").append(System.lineSeparator());
failures += list.size();
list.forEach(s -> failuresBuilder.append(" * ")
.append(s.replace(System.lineSeparator(),
System.lineSeparator() + " ").trim())
.append(System.lineSeparator()));
failuresBuilder.append(System.lineSeparator());
}
failuresBuilder.insert(0, ("One or more @IR rules failed:" + System.lineSeparator()
+ System.lineSeparator() + "Failed IR Rules (" + failures + ")"
+ System.lineSeparator()) + "-----------------"
+ "-".repeat(String.valueOf(failures).length()) + System.lineSeparator());
failuresBuilder.append(">>> Check stdout for compilation output of the failed methods")
.append(System.lineSeparator()).append(System.lineSeparator());
// In some very rare cases, the VM output to regex match on contains "<!-- safepoint while printing -->"
// (emitted by ttyLocker::break_tty_for_safepoint) which might be the reason for a matching error.
// Do not throw an exception in this case (i.e. bailout).
String compilations = compilationsBuilder.toString();
if (!compilations.contains(SAFEPOINT_WHILE_PRINTING_MESSAGE)) {
throw new IRViolationException(failuresBuilder.toString(), compilations);
} else {
System.out.println("Found " + SAFEPOINT_WHILE_PRINTING_MESSAGE + ", bail out of IR matching");
}
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -194,13 +194,13 @@ public class TestVMProcess {
if (!testListBuilder.isEmpty()) {
System.out.println("Run flag defined test list");
System.out.println("--------------------------");
System.out.println(testListBuilder.toString());
System.out.println(testListBuilder);
System.out.println();
}
if (!messagesBuilder.isEmpty()) {
System.out.println("Messages from Test VM");
System.out.println("---------------------");
System.out.println(messagesBuilder.toString());
System.out.println(messagesBuilder);
}
irEncoding = nonStdOutBuilder.toString();
} else {
@ -226,7 +226,7 @@ public class TestVMProcess {
*/
private void throwTestVMException() {
String stdErr = oa.getStderr();
if (stdErr.contains("TestFormat.reportIfAnyFailures")) {
if (stdErr.contains("TestFormat.throwIfAnyFailures")) {
Pattern pattern = Pattern.compile("Violations \\(\\d+\\)[\\s\\S]*(?=/============/)");
Matcher matcher = pattern.matcher(stdErr);
TestFramework.check(matcher.find(), "Must find violation matches");

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2022, 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;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchResult;
import java.util.List;
/**
* Class to build the compilation output of IR matching failures.
*
* @see IRMethodMatchResult
*/
class CompilationOutputBuilder {
public static String build(List<IRMethodMatchResult> results) {
StringBuilder compilationsBuilder = new StringBuilder();
for (IRMethodMatchResult result : results) {
if (result.fail()) {
compilationsBuilder.append(buildMatchedCompilationMessage(result));
}
}
return compilationsBuilder.toString();
}
private static String buildMatchedCompilationMessage(IRMethodMatchResult result) {
return result.getMatchedCompilationOutput() + System.lineSeparator() + System.lineSeparator();
}
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2021, 2022, 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;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchResult;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import compiler.lib.ir_framework.driver.irmatching.parser.IRMethodParser;
import java.util.*;
/**
* This class parses the hotspot_pid* file of the test VM to match all applicable @IR rules afterwards.
*/
public class IRMatcher {
public static final String SAFEPOINT_WHILE_PRINTING_MESSAGE = "<!-- safepoint while printing -->";
public IRMatcher(String hotspotPidFileName, String irEncoding, Class<?> testClass) {
IRMethodParser irMethodParser = new IRMethodParser(testClass);
Collection<IRMethod> irMethods = irMethodParser.parse(hotspotPidFileName, irEncoding);
if (irMethods != null) {
applyIRRules(irMethods);
}
}
/**
* Do an IR matching of all methods with applicable @IR rules prepared with by the {@link IRMethodParser}.
*/
private void applyIRRules(Collection<IRMethod> irMethods) {
List<IRMethodMatchResult> results = new ArrayList<>();
irMethods.forEach(irMethod -> applyIRRule(irMethod, results));
if (!results.isEmpty()) {
reportFailures(results);
}
}
private void applyIRRule(IRMethod irMethod, List<IRMethodMatchResult> results) {
if (TestFramework.VERBOSE) {
printMethodOutput(irMethod);
}
IRMethodMatchResult result = irMethod.applyIRRules();
if (result.fail()) {
results.add(result);
}
}
private void printMethodOutput(IRMethod irMethod) {
System.out.println("Output of " + irMethod.getOutput() + ":");
System.out.println(irMethod.getOutput());
}
/**
* Report all IR violations in a pretty format to the user. Depending on the failed regex, we only report
* PrintIdeal or PrintOptoAssembly if the match failed there. If there were failures that matched things
* in both outputs then the entire output is reported. Throws IRViolationException from which the compilation
* can be read and reported to the stdout separately. The exception message only includes the summary of the
* failures.
*/
private void reportFailures(List<IRMethodMatchResult> results) {
Collections.sort(results); // Alphabetically
throwIfNoSafepointWhilePrinting(IRMatcherFailureMessageBuilder.build(results),
CompilationOutputBuilder.build(results));
}
// In some very rare cases, the VM output to regex match on contains "<!-- safepoint while printing -->"
// (emitted by ttyLocker::break_tty_for_safepoint) which might be the reason for a matching error.
// Do not throw an exception in this case (i.e. bailout).
private void throwIfNoSafepointWhilePrinting(String failures, String compilations) {
if (!compilations.contains(SAFEPOINT_WHILE_PRINTING_MESSAGE)) {
throw new IRViolationException(failures, compilations);
} else {
System.out.println("Found " + SAFEPOINT_WHILE_PRINTING_MESSAGE + ", bail out of IR matching");
}
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2022, 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;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethodMatchResult;
import java.util.List;
/**
* Class to build the failure message output of IR matching failures.
*
* @see IRMethodMatchResult
*/
class IRMatcherFailureMessageBuilder {
public static String build(List<IRMethodMatchResult> results) {
StringBuilder failuresBuilder = new StringBuilder();
failuresBuilder.append(buildHeaderMessage(results));
int failureNumber = 1;
for (IRMethodMatchResult irMethodResult : results) {
if (irMethodResult.fail()) {
failuresBuilder.append(buildIRMethodFailureMessage(failureNumber, irMethodResult));
failureNumber++;
}
}
failuresBuilder.append(buildFooterMessage());
return failuresBuilder.toString();
}
private static String buildHeaderMessage(List<IRMethodMatchResult> results) {
int failedIRRulesCount = getFailedIRRulesCount(results);
long failedMethodCount = getFailedMethodCount(results);
return "One or more @IR rules failed:" + System.lineSeparator() + System.lineSeparator()
+ "Failed IR Rules (" + failedIRRulesCount + ") of Methods (" + failedMethodCount + ")"
+ System.lineSeparator()
+ "-".repeat(32 + digitCount(failedIRRulesCount) + digitCount(failedMethodCount))
+ System.lineSeparator();
}
private static int getFailedIRRulesCount(List<IRMethodMatchResult> results) {
return results.stream().map(IRMethodMatchResult::getFailedIRRuleCount).reduce(0, Integer::sum);
}
private static long getFailedMethodCount(List<IRMethodMatchResult> results) {
return results.stream().filter(IRMethodMatchResult::fail).count();
}
private static int digitCount(long digit) {
return String.valueOf(digit).length();
}
private static String buildIRMethodFailureMessage(int failureNumber, IRMethodMatchResult result) {
return failureNumber + ")" + result.buildFailureMessage() + System.lineSeparator();
}
private static String buildFooterMessage() {
return ">>> Check stdout for compilation output of the failed methods" + System.lineSeparator() + System.lineSeparator();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -21,7 +21,7 @@
* questions.
*/
package compiler.lib.ir_framework.driver;
package compiler.lib.ir_framework.driver.irmatching;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.Test;

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022, 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;
/**
* Interface used by all classes which represent a IR match result. A result should also provide a failure message
* in a pretty format to be used by the {@link IRMatcher}.
*/
public interface MatchResult {
/**
* Does this match result represent a failure?
*/
boolean fail();
/**
* Builds a failure message in a pretty format to be used by the IR matching failure reporting.
*/
String buildFailureMessage();
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2022, 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;
import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult;
/**
* Enum to describe what kind of compilation output that was matched for a method during IR matching.
*
* @see IRRuleMatchResult
*/
public enum OutputMatch {
/**
* There was no compilation output. Should not happen and results in a failure.
*/
NONE,
/**
* Matched on PrintIdeal.
*/
IDEAL,
/**
* Matched on PrintOptoAssembly.
*/
OPTO_ASSEMBLY,
/**
* Matched on PrintIdeal and PrintOptoAssembly.
*/
BOTH
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.irrule.IRRuleMatchResult;
import java.util.List;
/**
* Base class to build the failure message output for an IR method.
*
* @see IRMethodMatchResult
*/
abstract class FailureMessageBuilder {
protected final IRMethod irMethod;
public FailureMessageBuilder(IRMethod irMethod) {
this.irMethod = irMethod;
}
abstract public String build();
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -21,30 +21,34 @@
* questions.
*/
package compiler.lib.ir_framework.driver;
package compiler.lib.ir_framework.driver.irmatching.irmethod;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.TestFramework;
import compiler.lib.ir_framework.driver.irmatching.irrule.IRRule;
import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class to store information about a method that needs to be IR matched.
*/
class IRMethod {
public class IRMethod {
private final Method method;
private final int[] ruleIds;
private final IR[] irAnnos;
private final List<IRRule> irRules;
private final StringBuilder outputBuilder;
private String output;
private String idealOutput;
private String optoAssemblyOutput;
private boolean needsIdeal;
private boolean needsOptoAssembly;
public IRMethod(Method method, int[] ruleIds, IR[] irAnnos) {
this.method = method;
this.ruleIds = ruleIds;
this.irAnnos = irAnnos;
this.irRules = new ArrayList<>();
for (int i : ruleIds) {
irRules.add(new IRRule(this, i, irAnnos[i - 1]));
}
this.outputBuilder = new StringBuilder();
this.output = "";
this.idealOutput = "";
@ -55,13 +59,6 @@ class IRMethod {
return method;
}
public int[] getRuleIds() {
return ruleIds;
}
public IR getIrAnno(int idx) {
return irAnnos[idx];
}
/**
* The Ideal output comes always before the Opto Assembly output. We might parse multiple C2 compilations of this method.
@ -94,24 +91,26 @@ class IRMethod {
return optoAssemblyOutput;
}
public void needsAllOutput() {
needsIdeal();
needsOptoAssembly();
/**
* Apply all IR rules of this IR method.
*/
public IRMethodMatchResult applyIRRules() {
TestFramework.check(!irRules.isEmpty(), "IRMethod cannot be created if there are no IR rules to apply");
List<IRRuleMatchResult> results = new ArrayList<>();
if (!output.isEmpty()) {
return getNormalMatchResult(results);
} else {
return new MissingCompilationResult(this, irRules.size());
}
}
public void needsIdeal() {
needsIdeal = true;
}
public boolean usesIdeal() {
return needsIdeal;
}
public void needsOptoAssembly() {
needsOptoAssembly = true;
}
public boolean usesOptoAssembly() {
return needsOptoAssembly;
private NormalMatchResult getNormalMatchResult(List<IRRuleMatchResult> results) {
for (IRRule irRule : irRules) {
IRRuleMatchResult result = irRule.applyCheckAttribute();
if (result.fail()) {
results.add(result);
}
}
return new NormalMatchResult(this, results);
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.MatchResult;
import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult;
/**
* This base class represents an IR matching result of all IR rules of a method.
*
* @see IRRuleMatchResult
* @see IRMethod
*/
abstract public class IRMethodMatchResult implements Comparable<IRMethodMatchResult>, MatchResult {
protected final IRMethod irMethod;
IRMethodMatchResult(IRMethod irMethod) {
this.irMethod = irMethod;
}
abstract public String getMatchedCompilationOutput();
abstract public int getFailedIRRuleCount();
/**
* Used to sort the failed IR methods alphabetically.
*/
@Override
public int compareTo(IRMethodMatchResult other) {
return this.irMethod.getMethod().getName().compareTo(other.irMethod.getMethod().getName());
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.OutputMatch;
import compiler.lib.ir_framework.driver.irmatching.irrule.IRRuleMatchResult;
import compiler.lib.ir_framework.shared.TestFrameworkException;
import java.util.List;
/**
* Class to build the compilation output for an IR method.
*
* @see IRMethodMatchResult
*/
class MatchedCompilationOutputBuilder {
private final IRMethod irMethod;
private final OutputMatch outputMatch;
public MatchedCompilationOutputBuilder(IRMethod irMethod, List<IRRuleMatchResult> irRulesMatchResults) {
this.irMethod = irMethod;
this.outputMatch = getOutputMatch(irRulesMatchResults);
}
private OutputMatch getOutputMatch(List<IRRuleMatchResult> irRulesMatchResults) {
OutputMatch outputMatch;
if (allMatchesOn(irRulesMatchResults, OutputMatch.IDEAL)) {
outputMatch = OutputMatch.IDEAL;
} else if (allMatchesOn(irRulesMatchResults, OutputMatch.OPTO_ASSEMBLY)) {
outputMatch = OutputMatch.OPTO_ASSEMBLY;
} else {
outputMatch = OutputMatch.BOTH;
}
return outputMatch;
}
private boolean allMatchesOn(List<IRRuleMatchResult> irRulesMatchResults, OutputMatch outputMatch) {
return irRulesMatchResults.stream().allMatch(r -> r.getOutputMatch() == outputMatch);
}
public String build() {
StringBuilder builder = new StringBuilder();
builder.append(getMethodLine());
switch (outputMatch) {
case IDEAL -> builder.append(irMethod.getIdealOutput());
case OPTO_ASSEMBLY -> builder.append(irMethod.getOptoAssemblyOutput());
case BOTH -> builder.append(irMethod.getOutput());
default -> throw new TestFrameworkException("found unexpected OutputMatch " + outputMatch.name());
}
return builder.toString();
}
private String getMethodLine() {
return ">>> Compilation of " + irMethod.getMethod() + ":" + System.lineSeparator();
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.irrule.IRRuleMatchResult;
import java.util.List;
/**
* Class to build the failure message output for an IR method with a missing compilation output.
*
* @see IRMethodMatchResult
*/
class MissingCompilationMessageBuilder extends FailureMessageBuilder {
public MissingCompilationMessageBuilder(IRMethod irMethod) {
super(irMethod);
}
@Override
public String build() {
return getMethodLine() + getMissingCompilationMessage();
}
private String getMissingCompilationMessage() {
return " * Method was not compiled. Did you specify any compiler directives preventing a compilation "
+ "or used a @Run method in STANDALONE mode? In the latter case, make sure to always trigger a C2 "
+ "compilation by " + "invoking the test enough times.";
}
private String getMethodLine() {
return " Method \"" + irMethod.getMethod() + "\":" + System.lineSeparator();
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.irrule.IRRuleMatchResult;
/**
* This class represents an IR matching result where the compilation output was empty.
*
* @see IRRuleMatchResult
* @see IRMethod
*/
public class MissingCompilationResult extends IRMethodMatchResult {
private final int failedIRRules;
private final MissingCompilationMessageBuilder failureMessageBuilder;
MissingCompilationResult(IRMethod irMethod, int failedIRRules) {
super(irMethod);
this.failedIRRules = failedIRRules;
this.failureMessageBuilder = new MissingCompilationMessageBuilder(irMethod);
}
@Override
public boolean fail() {
return true;
}
@Override
public String getMatchedCompilationOutput() {
return "<empty>";
}
@Override
public String buildFailureMessage() {
return failureMessageBuilder.build();
}
private String getMethodLine() {
return " Method \"" + irMethod.getMethod() + "\":" + System.lineSeparator();
}
@Override
public int getFailedIRRuleCount() {
return failedIRRules;
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.irrule.IRRuleMatchResult;
import java.util.List;
import java.util.stream.Collectors;
/**
* Class to build the failure message output for an IR method for failed IR rules.
*
* @see IRMethodMatchResult
*/
class NormalFailureMessageBuilder extends FailureMessageBuilder {
private final List<IRRuleMatchResult> irRulesMatchResults;
public NormalFailureMessageBuilder(IRMethod irMethod, List<IRRuleMatchResult> irRulesMatchResults) {
super(irMethod);
this.irRulesMatchResults = irRulesMatchResults.stream()
.filter(IRRuleMatchResult::fail)
.collect(Collectors.toList());
}
@Override
public String build() {
return getMethodLine() + getIRRulesFailureMessage();
}
private String getMethodLine() {
int failures = irRulesMatchResults.size();
return " Method \"" + irMethod.getMethod() + "\" - [Failed IR rules: " + failures + "]:"
+ System.lineSeparator();
}
private String getIRRulesFailureMessage() {
StringBuilder failMsg = new StringBuilder();
for (IRRuleMatchResult irRuleResult : irRulesMatchResults) {
failMsg.append(irRuleResult.buildFailureMessage());
}
return failMsg.toString();
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2022, 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.driver.irmatching.irrule.IRRuleMatchResult;
import java.util.List;
/**
* This class represents a normal IR matching result of all IR rules of a method.
*
* @see IRRuleMatchResult
* @see IRMethod
*/
class NormalMatchResult extends IRMethodMatchResult {
private final List<IRRuleMatchResult> irRulesMatchResults;
private final NormalFailureMessageBuilder failureMessageBuilder;
private final MatchedCompilationOutputBuilder matchedCompilationOutputBuilder;
NormalMatchResult(IRMethod irMethod, List<IRRuleMatchResult> irRulesMatchResults) {
super(irMethod);
this.irRulesMatchResults = irRulesMatchResults;
this.failureMessageBuilder = new NormalFailureMessageBuilder(irMethod, irRulesMatchResults);
this.matchedCompilationOutputBuilder = new MatchedCompilationOutputBuilder(irMethod, irRulesMatchResults);
}
@Override
public boolean fail() {
return !irRulesMatchResults.isEmpty();
}
@Override
public String getMatchedCompilationOutput() {
return matchedCompilationOutputBuilder.build();
}
@Override
public String buildFailureMessage() {
return failureMessageBuilder.build();
}
@Override
public int getFailedIRRuleCount() {
return irRulesMatchResults.size();
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
/**
* Base class representing a check attribute of an IR rule.
*
* @see IR
*/
abstract class CheckAttribute {
abstract public CheckAttributeMatchResult apply(String compilation);
protected List<String> getMatchedNodes(Matcher m) {
List<String> matches = new ArrayList<>();
do {
matches.add(m.group());
} while (m.find());
return matches;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.driver.irmatching.MatchResult;
import java.util.List;
/**
* Base class representing a result of an applied check attribute of an IR rule.
*
* @see IR
*/
abstract class CheckAttributeMatchResult implements MatchResult {
protected List<RegexFailure> regexFailures = null;
@Override
public boolean fail() {
return regexFailures != null;
}
public int getMatchesCount() {
if (fail()) {
return regexFailures.stream().map(RegexFailure::getMatchesCount).reduce(0, Integer::sum);
} else {
return 0;
}
}
protected String collectRegexFailureMessages() {
StringBuilder failMsg = new StringBuilder();
for (RegexFailure regexFailure : regexFailures) {
failMsg.append(regexFailure.buildFailureMessage());
}
return failMsg.toString();
}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.shared.Comparison;
import compiler.lib.ir_framework.shared.ComparisonConstraintParser;
import compiler.lib.ir_framework.shared.TestFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class representing a counts attribute of an IR rule.
*
* @see IR#counts()
*/
class Counts extends CheckAttribute {
public List<Constraint> constraints;
private Counts(List<Constraint> constraints) {
this.constraints = constraints;
}
public static Counts create(List<String> nodesWithCountConstraint, IRRule irRule) {
List<Constraint> constraints = new ArrayList<>();
int nodeId = 1;
for (int i = 0; i < nodesWithCountConstraint.size(); i += 2, nodeId++) {
String node = nodesWithCountConstraint.get(i);
TestFormat.check(i + 1 < nodesWithCountConstraint.size(),
"Missing count " + getPostfixErrorMsg(irRule, node));
String countConstraint = nodesWithCountConstraint.get(i + 1);
Comparison<Long> comparison = parseComparison(irRule, node, countConstraint);
constraints.add(new Constraint(node, comparison, nodeId));
}
return new Counts(constraints);
}
private static String getPostfixErrorMsg(IRRule irRule, String node) {
return "for IR rule " + irRule.getRuleId() + ", node \"" + node + "\" at " + irRule.getMethod();
}
private static Comparison<Long> parseComparison(IRRule irRule, String node, String constraint) {
String postfixErrorMsg = "in count constraint " + getPostfixErrorMsg(irRule, node);
return ComparisonConstraintParser.parse(constraint, Long::parseLong, postfixErrorMsg);
}
@Override
public CheckAttributeMatchResult apply(String compilation) {
CountsMatchResult result = new CountsMatchResult();
checkConstraints(result, compilation);
return result;
}
private void checkConstraints(CountsMatchResult result, String compilation) {
for (Constraint constraint : constraints) {
checkConstraint(result, compilation, constraint);
}
}
private void checkConstraint(CountsMatchResult result, String compilation, Constraint constraint) {
long foundCount = getFoundCount(compilation, constraint);
Comparison<Long> comparison = constraint.comparison;
if (!comparison.compare(foundCount)) {
result.addFailure(createRegexFailure(compilation, constraint, foundCount));
}
}
private long getFoundCount(String compilation, Constraint constraint) {
Pattern pattern = Pattern.compile(constraint.nodeRegex);
Matcher matcher = pattern.matcher(compilation);
return matcher.results().count();
}
private CountsRegexFailure createRegexFailure(String compilation, Constraint constraint, long foundCount) {
Pattern p = Pattern.compile(constraint.nodeRegex);
Matcher m = p.matcher(compilation);
List<String> matches;
if (m.find()) {
matches = getMatchedNodes(m);
} else {
matches = new ArrayList<>();
}
return new CountsRegexFailure(constraint.nodeRegex, constraint.nodeId, foundCount, constraint.comparison, matches);
}
static class Constraint {
final String nodeRegex;
final Comparison<Long> comparison;
private final int nodeId;
Constraint(String nodeRegex, Comparison<Long> comparison, int nodeId) {
this.nodeRegex = nodeRegex;
this.comparison = comparison;
this.nodeId = nodeId;
}
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import java.util.ArrayList;
/**
* Class representing a result of an applied counts attribute of an IR rule.
*
* @see IR#counts()
*/
class CountsMatchResult extends CheckAttributeMatchResult {
public void addFailure(RegexFailure regexFailure) {
if (regexFailures == null) {
regexFailures = new ArrayList<>();
}
regexFailures.add(regexFailure);
}
@Override
public String buildFailureMessage() {
return " - counts: Graph contains wrong number of nodes:" + System.lineSeparator()
+ collectRegexFailureMessages();
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.shared.Comparison;
import java.util.List;
/**
* This class represents an IR matching failure of a regex of a counts attribute of an IR rule.
*
* @see Counts
*/
class CountsRegexFailure extends RegexFailure {
String failedComparison;
public CountsRegexFailure(String nodeRegex, int nodeId, long foundValue, Comparison<Long> comparison, List<String> matches) {
super(nodeRegex, nodeId, matches);
this.failedComparison = "[found] " + foundValue + " " + comparison.getComparator() + " "
+ comparison.getGivenValue() + " [given]";
}
@Override
public String buildFailureMessage() {
return getRegexLine()
+ getFailedComparison()
+ getMatchedNodesBlock();
}
private String getFailedComparison() {
return " - Failed comparison: " + failedComparison + System.lineSeparator();
}
@Override
protected String getMatchedNodesBlock() {
if (matches.isEmpty()) {
return getEmptyNodeMatchesLine();
} else {
return super.getMatchedNodesBlock();
}
}
private String getEmptyNodeMatchesLine() {
return getMatchedNodesWhiteSpace() + "- No nodes matched!" + System.lineSeparator();
}
@Override
protected String getMatchedPrefix() {
return "Matched";
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class representing a failOn attribute of an IR rule.
*
* @see IR#failOn()
*/
class FailOn extends CheckAttribute {
private final Pattern quickPattern;
private final List<String> nodes;
public FailOn(List<String> nodes) {
this.nodes = nodes;
this.quickPattern = Pattern.compile(String.join("|", nodes));
}
@Override
public CheckAttributeMatchResult apply(String compilation) {
FailOnMatchResult result = new FailOnMatchResult();
Matcher matcher = quickPattern.matcher(compilation);
if (matcher.find()) {
result.setFailures(createFailOnFailures(compilation));
}
return result;
}
private List<RegexFailure> createFailOnFailures(String compilation) {
List<RegexFailure> regexFailures = new ArrayList<>();
for (int i = 0; i < nodes.size(); i++) {
checkNode(regexFailures, compilation, nodes.get(i), i + 1);
}
return regexFailures;
}
private void checkNode(List<RegexFailure> regexFailures, String compilation, String node, int nodeId) {
Pattern p = Pattern.compile(node);
Matcher m = p.matcher(compilation);
if (m.find()) {
List<String> matches = getMatchedNodes(m);
regexFailures.add(new FailOnRegexFailure(node, nodeId, matches));
}
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import java.util.List;
/**
* Class representing a result of an applied failOn attribute of an IR rule.
*
* @see IR#failOn()
*/
class FailOnMatchResult extends CheckAttributeMatchResult {
public void setFailures(List<RegexFailure> regexFailures) {
this.regexFailures = regexFailures;
}
@Override
public String buildFailureMessage() {
return " - failOn: Graph contains forbidden nodes:" + System.lineSeparator()
+ collectRegexFailureMessages();
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022, 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.irrule;
import java.util.List;
/**
* This class represents an IR matching failure of a regex of a failOn attribute of an IR rule.
*
* @see FailOn
*/
class FailOnRegexFailure extends RegexFailure {
public FailOnRegexFailure(String nodeRegex, int nodeId, List<String> matches) {
super(nodeRegex, nodeId, matches);
}
@Override
public String buildFailureMessage() {
return getRegexLine()
+ getMatchedNodesBlock();
}
@Override
protected String getMatchedPrefix() {
return "Matched forbidden";
}
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.IRNode;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import compiler.lib.ir_framework.driver.irmatching.OutputMatch;
import compiler.lib.ir_framework.shared.*;
import java.lang.reflect.Method;
import java.util.function.Consumer;
public class IRRule {
private final IRMethod irMethod;
private final int ruleId;
private final IR irAnno;
private final FailOn failOn;
private final Counts counts;
public IRRule(IRMethod irMethod, int ruleId, IR irAnno) {
this.irMethod = irMethod;
this.ruleId = ruleId;
this.irAnno = irAnno;
this.failOn = initFailOn(irAnno);
this.counts = initCounts(irAnno);
}
private Counts initCounts(IR irAnno) {
String[] countsConstraints = irAnno.counts();
if (countsConstraints.length != 0) {
try {
return Counts.create(IRNode.mergeNodes(countsConstraints), this);
} catch (TestFormatException e) {
// Logged and reported later. Continue.
}
}
return null;
}
private FailOn initFailOn(IR irAnno) {
String[] failOnNodes = irAnno.failOn();
if (failOnNodes.length != 0) {
return new FailOn(IRNode.mergeNodes(failOnNodes));
}
return null;
}
public int getRuleId() {
return ruleId;
}
public IR getIRAnno() {
return irAnno;
}
public Method getMethod() {
return irMethod.getMethod();
}
/**
* Apply this IR rule by checking any failOn and counts attributes.
*/
public IRRuleMatchResult applyCheckAttribute() {
IRRuleMatchResult result = new IRRuleMatchResult(this);
if (failOn != null) {
applyCheckAttribute(failOn, result, result::setFailOnFailures);
}
if (counts != null) {
applyCheckAttribute(counts, result, result::setCountsFailures);
}
return result;
}
private void applyCheckAttribute(CheckAttribute checkAttribute, IRRuleMatchResult result,
Consumer<CheckAttributeMatchResult> setFailures) {
CheckAttributeMatchResult checkAttributeResult = checkAttribute.apply(irMethod.getOutput());
if (checkAttributeResult.fail()) {
setFailures.accept(checkAttributeResult);
result.updateOutputMatch(getOutputMatch(checkAttribute, checkAttributeResult));
}
}
/**
* Determine how the output was matched by reapplying the check attribute for the PrintIdeal and PrintOptoAssembly
* output separately.
*/
private OutputMatch getOutputMatch(CheckAttribute checkAttribute, CheckAttributeMatchResult checkAttributeResult) {
int totalMatches = checkAttributeResult.getMatchesCount();
int idealFailuresCount = getMatchesCount(checkAttribute, irMethod.getIdealOutput());
int optoAssemblyFailuresCount = getMatchesCount(checkAttribute, irMethod.getOptoAssemblyOutput());
return findOutputMatch(totalMatches, idealFailuresCount, optoAssemblyFailuresCount);
}
private int getMatchesCount(CheckAttribute checkAttribute, String compilation) {
CheckAttributeMatchResult result = checkAttribute.apply(compilation);
return result.getMatchesCount();
}
/**
* Compare different counts to find out, on what output a failure was matched.
*/
private OutputMatch findOutputMatch(int totalMatches, int idealFailuresCount, int optoAssemblyFailuresCount) {
if (totalMatches == 0
|| someRegexMatchOnlyEntireOutput(totalMatches, idealFailuresCount, optoAssemblyFailuresCount)
|| anyMatchOnIdealAndOptoAssembly(idealFailuresCount, optoAssemblyFailuresCount)) {
return OutputMatch.BOTH;
} else if (optoAssemblyFailuresCount == 0) {
return OutputMatch.IDEAL;
} else {
return OutputMatch.OPTO_ASSEMBLY;
}
}
/**
* Do we have a regex that is only matched on the entire ideal + opto assembly output?
*/
private boolean someRegexMatchOnlyEntireOutput(int totalCount, int idealFailuresCount, int optoAssemblyFailuresCount) {
return totalCount != idealFailuresCount + optoAssemblyFailuresCount;
}
/**
* Do we have a match on ideal and opto assembly for this rule?
*/
private boolean anyMatchOnIdealAndOptoAssembly(int idealFailuresCount, int optoAssemblyFailuresCount) {
return idealFailuresCount > 0 && optoAssemblyFailuresCount > 0;
}
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2022, 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.irrule;
import compiler.lib.ir_framework.TestFramework;
import compiler.lib.ir_framework.driver.irmatching.MatchResult;
import compiler.lib.ir_framework.driver.irmatching.OutputMatch;
/**
* This class represents an IR matching result of an IR rule.
*
* @see CheckAttributeMatchResult
* @see IRRule
*/
public class IRRuleMatchResult implements MatchResult {
private final IRRule irRule;
private CheckAttributeMatchResult failOnFailures = null;
private CheckAttributeMatchResult countsFailures = null;
private OutputMatch outputMatch;
public IRRuleMatchResult(IRRule irRule) {
this.irRule = irRule;
this.outputMatch = OutputMatch.NONE;
}
private boolean hasFailOnFailures() {
return failOnFailures != null;
}
public void setFailOnFailures(CheckAttributeMatchResult failOnFailures) {
this.failOnFailures = failOnFailures;
}
private boolean hasCountsFailures() {
return countsFailures != null;
}
public void setCountsFailures(CheckAttributeMatchResult countsFailures) {
this.countsFailures = countsFailures;
}
public OutputMatch getOutputMatch() {
return outputMatch;
}
@Override
public boolean fail() {
return failOnFailures != null || countsFailures != null;
}
public void updateOutputMatch(OutputMatch newOutputMatch) {
TestFramework.check(newOutputMatch != OutputMatch.NONE, "must be valid state");
switch (outputMatch) {
case NONE -> outputMatch = newOutputMatch;
case IDEAL -> outputMatch = newOutputMatch != OutputMatch.IDEAL
? OutputMatch.BOTH : OutputMatch.IDEAL;
case OPTO_ASSEMBLY -> outputMatch = newOutputMatch != OutputMatch.OPTO_ASSEMBLY
? OutputMatch.BOTH : OutputMatch.OPTO_ASSEMBLY;
}
}
/**
* Build a failure message based on the collected failures of this object.
*/
@Override
public String buildFailureMessage() {
StringBuilder failMsg = new StringBuilder();
failMsg.append(getIRRuleLine());
if (hasFailOnFailures()) {
failMsg.append(failOnFailures.buildFailureMessage());
}
if (hasCountsFailures()) {
failMsg.append(countsFailures.buildFailureMessage());
}
return failMsg.toString();
}
private String getIRRuleLine() {
return " * @IR rule " + irRule.getRuleId() + ": \"" + irRule.getIRAnno() + "\"" + System.lineSeparator();
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2022, 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.irrule;
import java.util.List;
import java.util.stream.Collectors;
/**
* Base class representing an IR matching failure of a regex of a check attribute of an IR rule.
*
* @see CheckAttributeMatchResult
* @see CheckAttribute
* @see IRRule
*/
abstract class RegexFailure {
protected final String nodeRegex;
protected final int nodeId;
protected final List<String> matches;
public RegexFailure(String nodeRegex, int nodeId, List<String> matches) {
this.nodeRegex = nodeRegex;
this.nodeId = nodeId;
this.matches = addWhiteSpacePrefixForEachLine(matches);
}
private List<String> addWhiteSpacePrefixForEachLine(List<String> matches) {
return matches
.stream()
.map(s -> s.replaceAll(System.lineSeparator(), System.lineSeparator()
+ getMatchedNodesItemWhiteSpace() + " "))
.collect(Collectors.toList());
}
abstract public String buildFailureMessage();
public int getMatchesCount() {
return matches.size();
}
protected String getRegexLine() {
return " * Regex " + nodeId + ": " + nodeRegex + System.lineSeparator();
}
protected String getMatchedNodesBlock() {
return getMatchedNodesHeader() + getMatchesNodeLines();
}
protected String getMatchedNodesHeader() {
int matchCount = matches.size();
return "" + getMatchedNodesWhiteSpace() + "- " + getMatchedPrefix() + " node"
+ (matchCount != 1 ? "s (" + matchCount + ")" : "") + ":" + System.lineSeparator();
}
protected String getMatchedNodesWhiteSpace() {
return " ";
}
abstract protected String getMatchedPrefix();
protected String getMatchesNodeLines() {
StringBuilder builder = new StringBuilder();
matches.forEach(match -> builder.append(getMatchedNodesItemWhiteSpace()).append("* ").append(match).append(System.lineSeparator()));
return builder.toString();
}
private String getMatchedNodesItemWhiteSpace() {
return " ";
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022, 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.parser;
import java.io.BufferedReader;
import java.io.IOException;
/**
* Base class of a read line from the hotspot_pid* file.
*/
abstract class AbstractLine {
private final BufferedReader reader;
protected String line;
public AbstractLine(BufferedReader reader) {
this.reader = reader;
}
public String getLine() {
return line;
}
/**
* Read next line and return it. If we've reached the end of the file, return NULL instead.
*/
public boolean readLine() throws IOException {
line = reader.readLine();
return line != null;
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2022, 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.parser;
import java.io.BufferedReader;
/**
* Class representing a block line inside a PrintIdeal or PrintOptoAssembly output block read from the hotspot_pid* file.
*/
class BlockLine extends AbstractLine {
public BlockLine(BufferedReader reader) {
super(reader);
}
/**
* Is this line an end of a PrintIdeal or PrintOptoAssembly output block?
*/
public boolean isBlockEnd() {
return line.startsWith("</");
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2022, 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.parser;
import java.io.BufferedReader;
import java.io.IOException;
/**
* Class to read all lines of a PrintIdeal or PrintOptoAssembly block.
*/
class BlockOutputReader {
private final BufferedReader reader;
public BlockOutputReader(BufferedReader reader) {
this.reader = reader;
}
/**
* Read all lines belonging to a PrintIdeal or PrintOptoAssembly output block.
*/
public String readBlock() throws IOException {
BlockLine line = new BlockLine(reader);
StringBuilder builder = new StringBuilder();
while (line.readLine() && !line.isBlockEnd()) {
builder.append(escapeXML(line.getLine())).append(System.lineSeparator());
}
return builder.toString();
}
/**
* Need to escape XML special characters.
*/
private static String escapeXML(String line) {
if (line.contains("&")) {
line = line.replace("&lt;", "<");
line = line.replace("&gt;", ">");
line = line.replace("&quot;", "\"");
line = line.replace("&apos;", "'");
line = line.replace("&amp;", "&");
}
return line;
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022, 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.parser;
/**
* Exception thrown when facing an unexpected format during parsing of the hotspot-pid* file
*/
class FileCorruptedException extends RuntimeException {
public FileCorruptedException(String s) {
super(s);
}
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2022, 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.parser;
import compiler.lib.ir_framework.TestFramework;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import compiler.lib.ir_framework.shared.TestFrameworkException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class to parse the PrintIdeal and PrintOptoAssembly outputs of the test class from the hotspot_pid* file and add them
* to the collection of {@link IRMethod} created by {@link IREncodingParser}.
*
* @see IRMethod
* @see IREncodingParser
*/
class HotSpotPidFileParser {
private static final Pattern COMPILE_ID_PATTERN = Pattern.compile("compile_id='(\\d+)'");
private final Pattern compileIdPatternForTestClass;
private Map<String, IRMethod> compilationsMap;
public HotSpotPidFileParser(String testClass) {
this.compileIdPatternForTestClass = Pattern.compile("compile_id='(\\d+)'.*" + Pattern.quote(testClass) + " (\\S+)");
}
public void setCompilationsMap(Map<String, IRMethod> compilationsMap) {
this.compilationsMap = compilationsMap;
}
/**
* Parse the hotspot_pid*.log file from the test VM. Read the PrintIdeal and PrintOptoAssembly outputs for all
* methods of the test class that need to be IR matched (found in compilations map).
*/
public Collection<IRMethod> parseCompilations(String hotspotPidFileName) {
try {
processFileLines(hotspotPidFileName);
return compilationsMap.values();
} catch (IOException e) {
throw new TestFrameworkException("Error while reading " + hotspotPidFileName, e);
} catch (FileCorruptedException e) {
throw new TestFrameworkException("Unexpected format of " + hotspotPidFileName, e);
}
}
private void processFileLines(String hotspotPidFileName) throws IOException {
Map<Integer, IRMethod> compileIdMap = new HashMap<>();
try (var reader = Files.newBufferedReader(Paths.get(hotspotPidFileName))) {
Line line = new Line(reader, compileIdPatternForTestClass);
BlockOutputReader blockOutputReader = new BlockOutputReader(reader);
while (line.readLine()) {
if (line.isTestClassCompilation()) {
parseTestMethodCompileId(compileIdMap, line.getLine());
} else if (isTestMethodBlockStart(line, compileIdMap)) {
String blockOutput = blockOutputReader.readBlock();
setIRMethodOutput(blockOutput, line, compileIdMap);
}
}
}
}
private void parseTestMethodCompileId(Map<Integer, IRMethod> compileIdMap, String line) {
String methodName = parseMethodName(line);
if (isTestAnnotatedMethod(methodName)) {
int compileId = getCompileId(line);
compileIdMap.put(compileId, getIrMethod(methodName));
}
}
private String parseMethodName(String line) {
Matcher matcher = compileIdPatternForTestClass.matcher(line);
TestFramework.check(matcher.find(), "must find match");
return matcher.group(2);
}
private boolean isTestAnnotatedMethod(String testMethodName) {
return compilationsMap.containsKey(testMethodName);
}
private IRMethod getIrMethod(String testMethodName) {
return compilationsMap.get(testMethodName);
}
private int getCompileId(String line) {
Matcher matcher = COMPILE_ID_PATTERN.matcher(line);
if (!matcher.find()) {
throw new FileCorruptedException("Unexpected format found on this line: " + line);
}
return Integer.parseInt(matcher.group(1));
}
private boolean isTestMethodBlockStart(Line line, Map<Integer, IRMethod> compileIdMap) {
return line.isBlockStart() && isTestClassMethodBlock(line, compileIdMap);
}
private boolean isTestClassMethodBlock(Line line, Map<Integer, IRMethod> compileIdMap) {
return compileIdMap.containsKey(getCompileId(line.getLine()));
}
public void setIRMethodOutput(String blockOutput, Line blockStartLine, Map<Integer, IRMethod> compileIdMap) {
IRMethod irMethod = compileIdMap.get(getCompileId(blockStartLine.getLine()));
setIRMethodOutput(blockOutput, blockStartLine, irMethod);
}
private void setIRMethodOutput(String blockOutput, Line blockStartLine, IRMethod irMethod) {
if (blockStartLine.isPrintIdealStart()) {
irMethod.setIdealOutput(blockOutput);
} else {
irMethod.setOptoAssemblyOutput(blockOutput);
}
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2022, 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.parser;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.TestFramework;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import compiler.lib.ir_framework.shared.TestFormat;
import compiler.lib.ir_framework.shared.TestFrameworkException;
import compiler.lib.ir_framework.test.IREncodingPrinter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class to parse the IR encoding emitted by the test VM and creating {@link IRMethod} objects for each entry.
*
* @see IRMethod
*/
class IREncodingParser {
private static final boolean PRINT_IR_ENCODING = Boolean.parseBoolean(System.getProperty("PrintIREncoding", "false"));
private static final Pattern IR_ENCODING_PATTERN =
Pattern.compile("(?<=" + IREncodingPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + IREncodingPrinter.END + ")");
private final Map<String, IRMethod> compilations;
private final Class<?> testClass;
public IREncodingParser(Class<?> testClass) {
this.testClass = testClass;
this.compilations = new HashMap<>();
}
public Map<String, IRMethod> parseIRMethods(String irEncoding) {
if (TestFramework.VERBOSE || PRINT_IR_ENCODING) {
System.out.println("Read IR encoding from test VM:");
System.out.println(irEncoding);
}
createCompilationsMap(irEncoding, testClass);
// We could have found format errors in @IR annotations. Report them now with an exception.
TestFormat.throwIfAnyFailures();
return compilations;
}
/**
* Sets up a map testname -> IRMethod (containing the PrintIdeal and PrintOptoAssembly output for testname).
*/
private void createCompilationsMap(String irEncoding, Class<?> testClass) {
Map<String, int[]> irRulesMap = parseIREncoding(irEncoding);
createIRMethodsWithEncoding(testClass, irRulesMap);
}
/**
* Read the IR encoding emitted by the test VM to decide if an @IR rule must be checked for a method.
*/
private Map<String, int[]> parseIREncoding(String irEncoding) {
Map<String, int[]> irRulesMap = new HashMap<>();
String[] irEncodingLines = getIREncodingLines(irEncoding);
for (String s : irEncodingLines) {
String line = s.trim();
String[] splitLine = line.split(",");
if (splitLine.length < 2) {
throw new TestFrameworkException("Invalid IR match rule encoding. No comma found: " + splitLine[0]);
}
String testName = splitLine[0];
int[] irRulesIdx = getRuleIndexes(splitLine);
irRulesMap.put(testName, irRulesIdx);
}
return irRulesMap;
}
/**
* Parse the IR encoding lines without header, explanation line and footer and return them in an array.
*/
private String[] getIREncodingLines(String irEncoding) {
Matcher matcher = IR_ENCODING_PATTERN.matcher(irEncoding);
TestFramework.check(matcher.find(), "Did not find IR encoding");
String lines = matcher.group(1).trim();
if (lines.isEmpty()) {
// Nothing to IR match.
return new String[0];
}
return lines.split("\\R");
}
/**
* Parse rule indexes from IR encoding line of the format: <method,idx1,idx2,...>
*/
private int[] getRuleIndexes(String[] splitLine) {
int[] irRulesIdx = new int[splitLine.length - 1];
for (int i = 1; i < splitLine.length; i++) {
try {
irRulesIdx[i - 1] = Integer.parseInt(splitLine[i]);
} catch (NumberFormatException e) {
throw new TestFrameworkException("Invalid IR match rule encoding. No number found: " + splitLine[i]);
}
}
return irRulesIdx;
}
private void createIRMethodsWithEncoding(Class<?> testClass, Map<String, int[]> irRulesMap) {
for (Method m : testClass.getDeclaredMethods()) {
IR[] irAnnos = m.getAnnotationsByType(IR.class);
if (irAnnos.length > 0) {
// Validation of legal @IR attributes and placement of the annotation was already done in Test VM.
int[] irRuleIds = irRulesMap.get(m.getName());
validateIRRuleIds(m, irAnnos, irRuleIds);
if (hasAnyApplicableIRRules(irRuleIds)) {
compilations.put(m.getName(), new IRMethod(m, irRuleIds, irAnnos));
}
}
}
}
private void validateIRRuleIds(Method m, IR[] irAnnos, int[] ids) {
TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m);
TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m);
TestFramework.check((ids[0] >= 1 || ids[0] == IREncodingPrinter.NO_RULE_APPLIED)
&& ids[ids.length - 1] <= irAnnos.length,
"Invalid IR rule index found in validIrRulesMap for " + m);
}
/**
* Does the list of IR rules contain any applicable IR rules for the given conditions?
*/
private boolean hasAnyApplicableIRRules(int[] irRuleIds) {
return irRuleIds[0] != IREncodingPrinter.NO_RULE_APPLIED;
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2022, 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.parser;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import java.util.Collection;
import java.util.Map;
/**
* Class to parse the PrintIdeal and PrintOptoAssembly outputs of the test class and store them into a collection
* of dedicated IRMethod objects used throughout IR matching.
*
* @see IRMethod
*/
public class IRMethodParser {
private final IREncodingParser irEncodingParser;
private final HotSpotPidFileParser hotSpotPidFileParser;
public IRMethodParser(Class<?> testClass) {
this.irEncodingParser = new IREncodingParser(testClass);
this.hotSpotPidFileParser = new HotSpotPidFileParser(testClass.getName());
}
/**
* Parse the IR encoding and hotspot_pid* file to create a collection of {@link IRMethod} objects.
* Return null if there are no applicable @IR rules in any method of the test class.
*/
public Collection<IRMethod> parse(String hotspotPidFileName, String irEncoding) {
Map<String, IRMethod> compilationsMap = irEncodingParser.parseIRMethods(irEncoding);
if (!compilationsMap.isEmpty()) {
hotSpotPidFileParser.setCompilationsMap(compilationsMap);
return hotSpotPidFileParser.parseCompilations(hotspotPidFileName);
}
return null;
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2022, 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.parser;
import java.io.BufferedReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class representing a normal line read from the hotspot_pid* file.
*/
class Line extends AbstractLine {
private final Pattern compileIdPatternForTestClass;
public Line(BufferedReader reader, Pattern compileIdPatternForTestClass) {
super(reader);
this.compileIdPatternForTestClass = compileIdPatternForTestClass;
}
/**
* Is this line a start of a @Test annotated method? We only care about test class entries. There might be non-class
* entries as well if user specified additional compile commands. Ignore these.
*/
public boolean isTestClassCompilation() {
if (isCompilation()) {
Matcher matcher = compileIdPatternForTestClass.matcher(line);
return matcher.find();
}
return false;
}
/**
* Is this header a C2 non-OSR compilation header entry?
*/
public boolean isCompilation() {
return line.startsWith("<task_queued") && notOSRCompilation() && notC2Compilation();
}
/**
* OSR compilations have compile_kind set.
*/
private boolean notOSRCompilation() {
return !line.contains("compile_kind='");
}
/**
* Non-C2 compilations have level set.
*/
private boolean notC2Compilation() {
return !line.contains("level='");
}
/**
* Is this line a start of a PrintIdeal or PrintOptoAssembly output block?
*/
public boolean isBlockStart() {
return isPrintIdealStart() || isPrintOptoAssemblyStart();
}
/**
* Is this line a start of a PrintIdeal output block?
*/
public boolean isPrintIdealStart() {
// Ignore OSR compilations which have compile_kind set.
return line.startsWith("<ideal") && notOSRCompilation();
}
/**
* Is this line a start of a PrintOptoAssembly output block?
*/
private boolean isPrintOptoAssemblyStart() {
// Ignore OSR compilations which have compile_kind set.
return line.startsWith("<opto_assembly") && notOSRCompilation();
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022, 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.shared;
import java.util.function.BiPredicate;
import java.util.function.Function;
/**
* Comparison result of parsing a constraint with {@link ComparisonConstraintParser#parse(String, Function, String)}.
*/
public class Comparison<T extends Comparable<T>> {
private final T givenValue; // Right hand side
private final BiPredicate<T, T> comparisonPredicate;
private final String comparator;
public Comparison(T givenValue, String comparator, BiPredicate<T, T> comparisonPredicate) {
this.givenValue = givenValue;
this.comparator = comparator;
this.comparisonPredicate = comparisonPredicate;
}
public T getGivenValue() {
return givenValue;
}
public String getComparator() {
return comparator;
}
/**
* Comparison: foundValue OP givenValue
*/
public boolean compare(T foundValue) {
return comparisonPredicate.test(foundValue, givenValue);
}
}

View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2021, 2022, 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.shared;
import java.util.function.BiPredicate;
import java.util.function.Function;
/**
* Utility class to parse a comparator either in the applyIf* or in the counts properties of an @IR rules.
*/
public class ComparisonConstraintParser<T extends Comparable<T>> {
private enum Comparator {
ONE_CHAR, TWO_CHARS
}
public static <T extends Comparable<T>> Comparison<T> parse(String constraint, Function<String, T> parseFunction,
String postfixErrorMsg) {
try {
return parseConstraintAndValue(constraint, parseFunction);
} catch (EmptyConstraintException e) {
TestFormat.fail("Provided empty value " + postfixErrorMsg);
throw new UnreachableCodeException();
} catch (MissingConstraintValueException e) {
TestFormat.fail("Provided empty value after comparator \"" + e.getComparator() + "\" " + postfixErrorMsg);
throw new UnreachableCodeException();
} catch (InvalidComparatorException e) {
TestFormat.fail("Provided invalid comparator \"" + e.getComparator() + "\" " + postfixErrorMsg);
throw new UnreachableCodeException();
} catch (InvalidConstraintValueException e) {
String comparator = e.getComparator();
if (!comparator.isEmpty()) {
comparator = " after comparator \"" + comparator + "\"";
}
TestFormat.fail("Provided invalid value \"" + e.getInvalidValue() + "\""
+ comparator + " " + postfixErrorMsg);
throw new UnreachableCodeException();
}
}
private static <T extends Comparable<T>> Comparison<T> parseConstraintAndValue(String constraint,
Function<String, T> parseFunction) throws
EmptyConstraintException, MissingConstraintValueException,
InvalidComparatorException, InvalidConstraintValueException {
ParsedResult<T> result = parse(constraint);
T givenValue = parseGivenValue(parseFunction, result);
return new Comparison<>(givenValue, result.comparator, result.comparisonPredicate);
}
private static <T extends Comparable<T>> ParsedResult<T> parse(String constraint) throws
EmptyConstraintException, MissingConstraintValueException, InvalidComparatorException {
constraint = constraint.trim();
if (constraint.isEmpty()) {
throw new EmptyConstraintException();
}
switch (constraint.charAt(0)) {
case '<' -> {
throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR);
if (constraint.charAt(1) == '=') {
throwIfNoValueAfterComparator(constraint, Comparator.TWO_CHARS);
return new ParsedResult<>(constraint.substring(2).trim(), "<=", (x, y) -> x.compareTo(y) <= 0);
} else {
return new ParsedResult<>(constraint.substring(1).trim(), "<", (x, y) -> x.compareTo(y) < 0);
}
}
case '>' -> {
throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR);
if (constraint.charAt(1) == '=') {
throwIfNoValueAfterComparator(constraint, Comparator.TWO_CHARS);
return new ParsedResult<>(constraint.substring(2).trim(), ">=", (x, y) -> x.compareTo(y) >= 0);
} else {
return new ParsedResult<>(constraint.substring(1).trim(), ">", (x, y) -> x.compareTo(y) > 0);
}
}
case '!' -> {
throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR);
if (constraint.charAt(1) != '=') {
throw new InvalidComparatorException("!");
}
throwIfNoValueAfterComparator(constraint, Comparator.TWO_CHARS);
return new ParsedResult<>(constraint.substring(2).trim(), "!=", (x, y) -> x.compareTo(y) != 0);
}
case '=' -> { // Allowed syntax, equivalent to not using any symbol.
throwIfNoValueAfterComparator(constraint, Comparator.ONE_CHAR);
return new ParsedResult<>(constraint.substring(1).trim(), "=", (x, y) -> x.compareTo(y) == 0);
}
default -> {
return new ParsedResult<>(constraint.trim(), "=", (x, y) -> x.compareTo(y) == 0);
}
}
}
private static void throwIfNoValueAfterComparator(String constraint, Comparator comparator) throws MissingConstraintValueException {
switch (comparator) {
case ONE_CHAR -> {
if (constraint.length() == 1) {
throw new MissingConstraintValueException(constraint);
}
}
case TWO_CHARS -> {
if (constraint.length() == 2) {
throw new MissingConstraintValueException(constraint);
}
}
}
}
private static <T extends Comparable<T>> T parseGivenValue(Function<String, T> parseFunction, ParsedResult<T> result)
throws InvalidConstraintValueException {
try {
return parseFunction.apply(result.value);
}
catch (NumberFormatException e) {
throw new InvalidConstraintValueException(result.value, result.comparator);
}
}
static class ParsedResult<T> {
public String value;
public BiPredicate<T, T> comparisonPredicate;
public String comparator;
public ParsedResult(String value, String comparator,BiPredicate<T, T> comparisonPredicate) {
this.value = value;
this.comparator = comparator;
this.comparisonPredicate = comparisonPredicate;
}
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2022, 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.shared;
/**
* Exception thrown when {@link ComparisonConstraintParser} cannot find a constraint.
*/
class EmptyConstraintException extends Exception {
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2022, 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.shared;
/**
* Exception threw when {@link ComparisonConstraintParser} parses an invalid comparator.
*/
public class InvalidComparatorException extends Exception {
private final String comparator;
public InvalidComparatorException(String comparator) {
this.comparator = comparator;
}
public String getComparator() {
return comparator;
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022, 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.shared;
/**
* Exception thrown when {@link ComparisonConstraintParser} parses an invalid value.
*/
class InvalidConstraintValueException extends Exception {
private final String invalidValue;
private final String comparator;
public InvalidConstraintValueException(String invalidValue, String comparator) {
this.invalidValue = invalidValue;
this.comparator = comparator;
}
public String getInvalidValue() {
return invalidValue;
}
public String getComparator() {
return comparator;
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2022, 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.shared;
/**
* Exception thrown when {@link ComparisonConstraintParser} cannot find a value in a constraint after a comparator.
*/
class MissingConstraintValueException extends Exception {
private final String comparator;
public MissingConstraintValueException(String comparator) {
this.comparator = comparator;
}
public String getComparator() {
return comparator;
}
}

View file

@ -1,104 +0,0 @@
/*
* 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 compiler.lib.ir_framework.shared;
import java.util.function.BiPredicate;
/**
* Utility class to parse a comparator either in the applyIf* or in the counts properties of an @IR rules.
*/
public class ParsedComparator<T extends Comparable<T>> {
private final String strippedString;
private final BiPredicate<T, T> predicate;
private final String comparator;
public ParsedComparator(String strippedString, BiPredicate<T, T> predicate, String comparator) {
this.strippedString = strippedString;
this.predicate = predicate;
this.comparator = comparator;
}
public String getStrippedString() {
return strippedString;
}
public BiPredicate<T, T> getPredicate() {
return predicate;
}
public String getComparator() {
return comparator;
}
/**
* Return parsed comparator object which provides the predicate to perform the test.
* Allowed comparators: <, <=, >, =>, =, !=
*/
public static <T extends Comparable<T>> ParsedComparator<T> parseComparator(String value) throws CheckedTestFrameworkException {
BiPredicate<T, T> comparison;
value = value.trim();
String comparator = "";
switch (value.charAt(0)) {
case '<':
if (value.charAt(1) == '=') {
comparator = "<=";
comparison = (x, y) -> x.compareTo(y) <= 0;
value = value.substring(2).trim();
} else {
comparator = "<";
comparison = (x, y) -> x.compareTo(y) < 0;
value = value.substring(1).trim();
}
break;
case '>':
if (value.charAt(1) == '=') {
comparator = ">=";
comparison = (x, y) -> x.compareTo(y) >= 0;
value = value.substring(2).trim();
} else {
comparator = ">";
comparison = (x, y) -> x.compareTo(y) > 0;
value = value.substring(1).trim();
}
break;
case '!':
if (value.charAt(1) != '=') {
throw new CheckedTestFrameworkException(value.substring(0, 1));
}
comparator = "!=";
comparison = (x, y) -> x.compareTo(y) != 0;
value = value.substring(2).trim();
break;
case '=': // Allowed syntax, equivalent to not using any symbol.
comparator = "=";
value = value.substring(1).trim();
// Fall through
default:
comparison = (x, y) -> x.compareTo(y) == 0;
value = value.trim();
break;
}
return new ParsedComparator<>(value, comparison, comparator);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -53,7 +53,7 @@ public class TestFormat {
FAILURES.add(failureMessage);
}
public static void reportIfAnyFailures() {
public static void throwIfAnyFailures() {
if (FAILURES.isEmpty()) {
// No format violation detected.
return;

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2022, 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.shared;
/**
* The error reporting of the IR framework is throwing exceptions unconditionally in separate methods. The calling methods,
* however, do not see these exceptions. As a result, Java and/or some IDEs could complain about impossible states
* (e.g. uninitialized variables, null pointer dereferences etc. even though an exception will be thrown earlier).
* To avoid that, throw an instance of this class instead.
*/
class UnreachableCodeException extends RuntimeException {
public UnreachableCodeException() {
super("Unreachable code");
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -37,7 +37,7 @@ import java.util.function.Function;
/**
* Prints an encoding to the dedicated test framework socket whether @IR rules of @Test methods should be applied or not.
* This is done during the execution of the test VM by checking the active VM flags. This encoding is eventually parsed
* and checked by the IRMatcher class in the driver VM after the termination of the test VM.
* and checked by the IRMatcher class in the driver VM after the termination of the test VM. IR rule indices start at 1.
*/
public class IREncodingPrinter {
public static final String START = "##### IRMatchRulesEncoding - used by TestFramework #####";
@ -73,7 +73,7 @@ public class IREncodingPrinter {
ruleIndex = i + 1;
try {
if (shouldApplyIrRule(irAnno)) {
validRules.add(i);
validRules.add(ruleIndex);
}
} catch (TestFormatException e) {
// Catch logged failure and continue to check other IR annotations.
@ -206,11 +206,11 @@ public class IREncodingPrinter {
}
actualFlagValue = LONG_GETTERS.stream().map(f -> f.apply(flag)).filter(Objects::nonNull).findAny().orElse(null);
if (actualFlagValue != null) {
return checkLongFlag(flag, value, (Long) actualFlagValue);
return checkFlag(Long::parseLong, "integer", flag, value, (Long) actualFlagValue);
}
actualFlagValue = WHITE_BOX.getDoubleVMFlag(flag);
if (actualFlagValue != null) {
return checkDoubleFlag(flag, value, (Double) actualFlagValue);
return checkFlag(Double::parseDouble, "floating point", flag, value, (Double) actualFlagValue);
}
actualFlagValue = WHITE_BOX.getStringVMFlag(flag);
if (actualFlagValue != null) {
@ -242,60 +242,20 @@ public class IREncodingPrinter {
return booleanValue == actualFlagValue;
}
private boolean checkLongFlag(String flag, String value, long actualFlagValue) {
long longValue;
ParsedComparator<Long> parsedComparator;
private <T extends Comparable<T>> boolean checkFlag(Function<String, T> parseFunction, String kind, String flag,
String value, T actualFlagValue) {
try {
parsedComparator = ParsedComparator.parseComparator(value);
} catch (CheckedTestFrameworkException e) {
TestFormat.failNoThrow("Invalid comparator in \"" + value + "\" for integer based flag " + flag + failAt());
return false;
} catch (IndexOutOfBoundsException e) {
TestFormat.failNoThrow("Provided empty value for integer based flag " + flag + failAt());
String postFixErrorMsg = "for " + kind + " based flag \"" + flag + "\"" + failAt();
Comparison<T> comparison = ComparisonConstraintParser.parse(value, parseFunction, postFixErrorMsg);
return comparison.compare(actualFlagValue);
} catch (TestFormatException e) {
// Format exception, do not apply rule.
return false;
}
try {
longValue = Long.parseLong(parsedComparator.getStrippedString());
} catch (NumberFormatException e) {
String comparator = parsedComparator.getComparator();
if (!comparator.isEmpty()) {
comparator = "after comparator \"" + parsedComparator.getComparator() + "\"";
}
TestFormat.failNoThrow("Invalid value \"" + parsedComparator.getStrippedString() + "\" "
+ comparator + " for integer based flag " + flag + failAt());
return false;
}
return parsedComparator.getPredicate().test(actualFlagValue, longValue);
}
private boolean checkDoubleFlag(String flag, String value, double actualFlagValue) {
double doubleValue;
ParsedComparator<Double> parsedComparator;
try {
parsedComparator = ParsedComparator.parseComparator(value);
} catch (CheckedTestFrameworkException e) {
TestFormat.failNoThrow("Invalid comparator in \"" + value + "\" for floating point based flag " + flag + failAt());
return false;
} catch (IndexOutOfBoundsException e) {
TestFormat.failNoThrow("Provided empty value for floating point based flag " + flag + failAt());
return false;
}
try {
doubleValue = Double.parseDouble(parsedComparator.getStrippedString());
} catch (NumberFormatException e) {
String comparator = parsedComparator.getComparator();
if (!comparator.isEmpty()) {
comparator = "after comparator \"" + parsedComparator.getComparator() + "\"";
}
TestFormat.failNoThrow("Invalid value \"" + parsedComparator.getStrippedString() + "\" "
+ comparator + " for floating point based flag " + flag + failAt());
return false;
}
return parsedComparator.getPredicate().test(actualFlagValue, doubleValue);
}
private String failAt() {
return " for @IR rule " + ruleIndex + " at " + method;
return " in @IR rule " + ruleIndex + " at " + method;
}
public void emit() {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -267,7 +267,7 @@ public class TestVM {
if (PRINT_VALID_IR_RULES) {
irMatchRulePrinter.emit();
}
TestFormat.reportIfAnyFailures();
TestFormat.throwIfAnyFailures();
declaredTests.clear();
testMethodMap.clear();
}

View file

@ -37,9 +37,6 @@ package compiler.vectorapi;
import java.util.concurrent.Callable;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.IRViolationException;
import jdk.test.lib.Asserts;
import jdk.test.lib.Asserts;
import jdk.test.lib.Utils;
import java.util.Random;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,7 +24,7 @@
package ir_framework.examples;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.IRViolationException;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
/*
* @test

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,7 +24,7 @@
package ir_framework.tests;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.IRViolationException;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
import compiler.lib.ir_framework.driver.TestVMException;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,7 +24,7 @@
package ir_framework.tests;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.IRViolationException;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
import jdk.test.lib.Asserts;
/*

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,7 +24,7 @@
package ir_framework.tests;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.IRViolationException;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
import jdk.test.lib.Asserts;
import jdk.test.lib.Platform;
import sun.hotspot.WhiteBox;
@ -60,7 +60,7 @@ public class TestIRMatching {
private static void addException(Exception e) {
System.out.flush();
System.err.flush();
exceptions.put(e, baos.toString() + System.lineSeparator() + baosErr.toString());
exceptions.put(e, baos + System.lineSeparator() + baosErr);
}
public static void main(String[] args) {
@ -285,20 +285,20 @@ public class TestIRMatching {
runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=50");
System.out.flush();
String output = baos.toString();
findIrIds(output, "testMatchAllIf50", 0, 21);
findIrIds(output, "testMatchAllIf50", 1, 22);
findIrIds(output, "testMatchNoneIf50", -1, -1);
runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=49");
System.out.flush();
output = baos.toString();
findIrIds(output, "testMatchAllIf50", 4, 6, 13, 18);
findIrIds(output, "testMatchNoneIf50", 0, 3, 8, 10, 17, 22);
findIrIds(output, "testMatchAllIf50", 5, 7, 14, 19);
findIrIds(output, "testMatchNoneIf50", 1, 4, 9, 11, 18, 23);
runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=51");
System.out.flush();
output = baos.toString();
findIrIds(output, "testMatchAllIf50", 7, 12, 19, 21);
findIrIds(output, "testMatchNoneIf50", 4, 7, 11, 16, 20, 22);
findIrIds(output, "testMatchAllIf50", 8, 13, 20, 22);
findIrIds(output, "testMatchNoneIf50", 5, 8, 12, 17, 21, 23);
System.setOut(oldOut);
System.setErr(oldErr);
@ -395,7 +395,7 @@ public class TestIRMatching {
}
}
if (!output.contains(builder.toString())) {
addException(new RuntimeException("Could not find encoding: \"" + builder.toString() + System.lineSeparator()));
addException(new RuntimeException("Could not find encoding: \"" + builder + System.lineSeparator()));
}
}
}
@ -550,20 +550,20 @@ class MultipleFailOnBad {
class FlagComparisons {
// Applies all IR rules if TLABRefillWasteFraction=50
@Test
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "50"}) // Index 0
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "50"}) // Index 1
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=50"}) // Index 4
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=50"}) // Index 5
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <= 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=50"}) // Index 7
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=50"}) // Index 8
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >= 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " > 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<51"}) // Index 13
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<51"}) // Index 14
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "< 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " < 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=51"})
@ -571,34 +571,34 @@ class FlagComparisons {
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 49"}) // Index 21
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 49"}) // Index 22
public void testMatchAllIf50() {}
// Applies no IR rules if TLABRefillWasteFraction=50
@Test
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "49"}) // Index 0
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "49"}) // Index 1
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "51"}) // Index 4
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "51"}) // Index 5
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=49"}) // Index 8
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=49"}) // Index 9
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <= 49"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=51"}) // Index 11
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=51"}) // Index 12
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >= 51"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " > 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<50"}) // Index 17
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<50"}) // Index 18
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "< 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " < 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 50"})
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 50"}) // Index 22
@IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 50"}) // Index 23
public void testMatchNoneIf50() {}
}
@ -814,14 +814,14 @@ class BadCount {
int iFld;
int result;
@Test
@IR(counts = {IRNode.LOAD, "!= 1"})
@IR(counts = {IRNode.LOAD, "!= 1"}) // fail
@IR(counts = {IRNode.STORE, "> 0"})
public void bad1() {
result = iFld;
}
@Test
@IR(counts = {IRNode.LOAD, "1"})
@IR(counts = {IRNode.LOAD, "1"}) // fail
@IR(counts = {IRNode.STORE, "< 1"})
public void bad2() {
result = iFld;
@ -829,8 +829,8 @@ class BadCount {
@Test
@IR(counts = {IRNode.LOAD, "0"})
@IR(counts = {IRNode.STORE, " <= 0"})
@IR(counts = {IRNode.LOAD, "0"}) // fail
@IR(counts = {IRNode.STORE, " <= 0"}) // fail
public void bad3() {
result = iFld;
}
@ -1514,7 +1514,7 @@ abstract class Constraint {
}
}
}
Asserts.assertTrue(matched, toString() + " should have been matched");
Asserts.assertTrue(matched, this + " should have been matched");
}
abstract protected void checkIRRule(String irRule);
@ -1732,7 +1732,7 @@ class BadCountsConstraint extends RegexConstraint {
private static List<String> getMatchesList(int foundCount, String[] matches, List<String> strings) {
List<String> matchesList = new ArrayList<>();
matchesList.add("but found " + foundCount);
matchesList.add("Failed comparison: [found] " + foundCount);
if (matches != null) {
matchesList.addAll(strings);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,7 +24,7 @@
package ir_framework.tests;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.IRViolationException;
import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
import compiler.lib.ir_framework.shared.TestRunException;
import jdk.test.lib.Asserts;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -24,8 +24,7 @@
package ir_framework.tests;
import compiler.lib.ir_framework.Scenario;
import compiler.lib.ir_framework.driver.IRMatcher;
import compiler.lib.ir_framework.driver.TestVMProcess;
import compiler.lib.ir_framework.driver.irmatching.IRMatcher;
import jdk.test.lib.Asserts;
import java.util.Arrays;