// This class contains common test utilities for testing CDS publicclass CDSTestUtils { publicstaticfinal String MSG_RANGE_NOT_WITHIN_HEAP = "UseSharedSpaces: Unable to allocate region, range is not within java heap."; publicstaticfinal String MSG_RANGE_ALREADT_IN_USE = "Unable to allocate region, java heap range is already in use."; publicstaticfinal String MSG_DYNAMIC_NOT_SUPPORTED = "-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded"; publicstaticfinalboolean DYNAMIC_DUMP = Boolean.getBoolean("test.dynamic.cds.archive");
if (hasNormalExit) { if ("on".equals(options.xShareMode) &&
output.getStderr().contains("java version") &&
!output.getStderr().contains(CDS_DISABLED)) { // "-showversion" is always passed in the command-line by the execXXX methods. // During normal exit, we require that the VM to show that sharing was enabled.
output.shouldContain("sharing");
}
}
}
public Result assertNormalExit(Checker checker) throws Exception {
checker.check(output);
output.shouldHaveExitValue(0); returnthis;
}
public Result assertAbnormalExit(Checker checker) throws Exception {
checker.check(output);
output.shouldNotHaveExitValue(0); returnthis;
}
// When {--limit-modules, --patch-module, and/or --upgrade-module-path} // are specified, CDS is silently disabled for both -Xshare:auto and -Xshare:on. public Result assertSilentlyDisabledCDS(Checker checker) throws Exception { // this comes from a JVM warning message.
output.shouldContain(CDS_DISABLED);
checker.check(output); returnthis;
}
public Result assertSilentlyDisabledCDS(int exitCode, String... matches) throws Exception { return assertSilentlyDisabledCDS((out) -> {
out.shouldHaveExitValue(exitCode);
checkMatches(out, matches);
});
}
public Result ifNormalExit(Checker checker) throws Exception { if (hasNormalExit) {
checker.check(output);
} returnthis;
}
public Result ifAbnormalExit(Checker checker) throws Exception { if (!hasNormalExit) {
checker.check(output);
} returnthis;
}
public Result ifNoMappingFailure(Checker checker) throws Exception {
checker.check(output); returnthis;
}
public Result assertNormalExit(String... matches) throws Exception {
checkMatches(output, matches);
output.shouldHaveExitValue(0); returnthis;
}
public Result assertAbnormalExit(String... matches) throws Exception {
checkMatches(output, matches);
output.shouldNotHaveExitValue(0); returnthis;
}
}
// A number to be included in the filename of the stdout and the stderr output file. staticint logCounter = 0;
// By default, stdout of child processes are logged in files such as // <testname>-0000-exec.stdout. If you want to also include the stdout // inside jtr files, you can override this in the jtreg command line like // "jtreg -Dtest.cds.copy.child.stdout=true ...." publicstaticfinalboolean copyChildStdoutToMainStdout = Boolean.getBoolean("test.cds.copy.child.stdout");
// This property is passed to child test processes publicstaticfinal String TestTimeoutFactor = System.getProperty("test.timeout.factor", "1.0");
publicstaticfinal String UnableToMapMsg = "Unable to map shared archive: test did not complete";
// Create bootstrap CDS archive, // use extra JVM command line args as a prefix. // For CDS tests specifying prefix makes more sense than specifying suffix, since // normally there are no classes or arguments to classes, just "-version" // To specify suffix explicitly use CDSOptions.addSuffix() publicstatic OutputAnalyzer createArchive(String... cliPrefix) throws Exception { return createArchive((new CDSOptions()).addPrefix(cliPrefix));
}
// check result of 'dump-the-archive' operation, that is "-Xshare:dump" publicstatic OutputAnalyzer checkDump(OutputAnalyzer output, String... extraMatches) throws Exception {
if (!DYNAMIC_DUMP) {
output.shouldContain("Loading classes to share");
} else {
output.shouldContain("Written dynamic archive 0x");
}
output.shouldHaveExitValue(0);
for (String match : extraMatches) {
output.shouldContain(match);
}
return output;
}
// check result of dumping base archive publicstatic OutputAnalyzer checkBaseDump(OutputAnalyzer output) throws Exception {
output.shouldContain("Loading classes to share");
output.shouldHaveExitValue(0); return output;
}
// A commonly used convenience methods to create an archive and check the results // Creates an archive and checks for errors publicstatic OutputAnalyzer createArchiveAndCheck(CDSOptions opts) throws Exception { return checkDump(createArchive(opts));
}
// This method should be used to check the output of child VM for common exceptions. // Most of CDS tests deal with child VM processes for creating and using the archive. // However exceptions that occur in the child process do not automatically propagate // to the parent process. This mechanism aims to improve the propagation // of exceptions and common errors. // Exception e argument - an exception to be re-thrown if none of the common // exceptions match. Pass null if you wish not to re-throw any exception. publicstaticvoid checkCommonExecExceptions(OutputAnalyzer output, Exception e) throws Exception { if (output.getStdout().contains("https://bugreport.java.com/bugreport/crash.jsp")) { thrownew RuntimeException("Hotspot crashed");
} if (output.getStdout().contains("TEST FAILED")) { thrownew RuntimeException("Test Failed");
} if (output.getOutput().contains("Unable to unmap shared space")) { thrownew RuntimeException("Unable to unmap shared space");
}
// Special case -- sometimes Xshare:on fails because it failed to map // at given address. This behavior is platform-specific, machine config-specific // and can be random (see ASLR).
checkMappingFailure(output);
// Check the output for indication that mapping of the archive failed. // Performance note: this check seems to be rather costly - searching the entire // output stream of a child process for multiple strings. However, it is necessary // to detect this condition, a failure to map an archive, since this is not a real // failure of the test or VM operation, and results in a test being "skipped". // Suggestions to improve: // 1. VM can designate a special exit code for such condition. // 2. VM can print a single distinct string indicating failure to map an archive, // instead of utilizing multiple messages. // These are suggestions to improve testibility of the VM. However, implementing them // could also improve usability in the field. privatestatic String hasUnableToMapMessage(OutputAnalyzer output) {
String outStr = output.getOutput(); if ((output.getExitValue() == 1)) { if (outStr.contains(MSG_RANGE_NOT_WITHIN_HEAP)) { return MSG_RANGE_NOT_WITHIN_HEAP;
} if (outStr.contains(MSG_DYNAMIC_NOT_SUPPORTED)) { return MSG_DYNAMIC_NOT_SUPPORTED;
}
}
// Dump a classlist using the -XX:DumpLoadedClassList option. publicstatic Result dumpClassList(String classListName, String... cli) throws Exception {
CDSOptions opts = (new CDSOptions())
.setUseVersion(false)
.setXShareMode("auto")
.addPrefix("-XX:DumpLoadedClassList=" + classListName)
.addSuffix(cli);
Result res = run(opts).assertNormalExit(); return res;
}
// Execute JVM with CDS archive, specify command line args suffix publicstatic OutputAnalyzer runWithArchive(String... cliPrefix) throws Exception {
return runWithArchive( (new CDSOptions())
.setArchiveName(getDefaultArchiveName())
.addPrefix(cliPrefix) );
}
// Enable basic verification (VerifyArchivedFields=1, no side effects) for all CDS // tests to make sure the archived heap objects are mapped/loaded properly. publicstaticvoid addVerifyArchivedFields(ArrayList<String> cmd) {
cmd.add("-XX:+UnlockDiagnosticVMOptions");
cmd.add("-XX:VerifyArchivedFields=1");
}
// A commonly used convenience methods to create an archive and check the results // Creates an archive and checks for errors publicstatic OutputAnalyzer runWithArchiveAndCheck(CDSOptions opts) throws Exception { return checkExec(runWithArchive(opts));
}
// check result of 'exec' operation, that is when JVM is run using the archive publicstatic OutputAnalyzer checkExec(OutputAnalyzer output, CDSOptions opts,
String... extraMatches) throws Exception { try { if ("on".equals(opts.xShareMode)) {
output.shouldContain("sharing");
}
output.shouldHaveExitValue(0);
} catch (RuntimeException e) {
checkCommonExecExceptions(output, e); return output;
}
// get the file object for the test artifact publicstatic File getTestArtifact(String name, boolean checkExistence) {
File file = new File(outputDirAsFile, name);
privatestaticfinal SimpleDateFormat timeStampFormat = new SimpleDateFormat("HH'h'mm'm'ss's'SSS");
privatestatic String defaultArchiveName;
// Call this method to start new archive with new unique name publicstaticvoid startNewArchiveName() {
defaultArchiveName = testName +
timeStampFormat.format(new Date()) + ".jsa";
}
// Format a line that defines an extra symbol in the file specify by -XX:SharedArchiveConfigFile=<file> publicstatic String formatArchiveConfigSymbol(String symbol) { int refCount = -1; // This is always -1 in the current HotSpot implementation. if (isAsciiPrintable(symbol)) { return symbol.length() + " " + refCount + ": " + symbol;
} else {
StringBuilder sb = new StringBuilder(); int utf8_length = escapeArchiveConfigString(sb, symbol); return utf8_length + " " + refCount + ": " + sb.toString();
}
}
// This method generates the same format as HashtableTextDump::put_utf8() in HotSpot, // to be used by -XX:SharedArchiveConfigFile=<file>. privatestaticint escapeArchiveConfigString(StringBuilder sb, String s) { byte arr[]; try {
arr = s.getBytes("UTF8");
} catch (java.io.UnsupportedEncodingException e) { thrownew RuntimeException("Unexpected", e);
} for (int i = 0; i < arr.length; i++) { char ch = (char)(arr[i] & 0xff); if (isAsciiPrintable(ch)) {
sb.append(ch);
} elseif (ch == '\t') {
sb.append("\\t");
} elseif (ch == '\r') {
sb.append("\\r");
} elseif (ch == '\n') {
sb.append("\\n");
} elseif (ch == '\\') {
sb.append("\\\\");
} else {
String hex = Integer.toHexString(ch); if (ch < 16) {
sb.append("\\x0");
} else {
sb.append("\\x");
}
sb.append(hex);
}
}
return arr.length;
}
privatestaticboolean isAsciiPrintable(String s) { for (int i = 0; i < s.length(); i++) { if (!isAsciiPrintable(s.charAt(i))) { returnfalse;
}
} returntrue;
}
// Do a cheap clone of the JDK. Most files can be sym-linked. However, $JAVA_HOME/bin/java and $JAVA_HOME/lib/.../libjvm.so" // must be copied, because the java.home property is derived from the canonicalized paths of these 2 files. // Set a list of {jvm, "java"} which will be physically copied. If a file needs copied physically, add it to the list. privatestatic String[] phCopied = {System.mapLibraryName("jvm"), "java"}; publicstaticvoid clone(File src, File dst) throws Exception { if (dst.exists()) { if (!dst.isDirectory()) { thrownew RuntimeException("Not a directory :" + dst);
}
} else { if (!dst.mkdir()) { thrownew RuntimeException("Cannot create directory: " + dst);
}
} // final String jvmLib = System.mapLibraryName("jvm"); for (String child : src.list()) { if (child.equals(".") || child.equals("..")) { continue;
}
File child_src = new File(src, child);
File child_dst = new File(dst, child); if (child_dst.exists()) { thrownew RuntimeException("Already exists: " + child_dst);
} if (child_src.isFile()) { boolean needPhCopy = false; for (String target : phCopied) { if (child.equals(target)) {
needPhCopy = true; break;
}
} if (needPhCopy) {
Files.copy(child_src.toPath(), /* copy data to -> */ child_dst.toPath(), new CopyOption[] { StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES});
} else {
Files.createSymbolicLink(child_dst.toPath(), /* link to -> */ child_src.toPath());
}
} else {
clone(child_src, child_dst);
}
}
}
// modulesDir, like $JDK/lib // oldName, module name under modulesDir // newName, new name for oldName publicstaticvoid rename(File fromFile, File toFile) throws Exception { if (!fromFile.exists()) { thrownew RuntimeException(fromFile.getName() + " does not exist");
}
if (toFile.exists()) { thrownew RuntimeException(toFile.getName() + " already exists");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.