diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 117e4497014..5fa0c381ebb 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -770,10 +770,13 @@ define SetupRunJtregTestBody # Make sure the tmp dir is normalized as some tests will react badly otherwise $1_TEST_TMP_DIR := $$(abspath $$($1_TEST_SUPPORT_DIR)/tmp) + # test.boot.jdk is used by some test cases that want to execute a previous + # version of the JDK. $1_JTREG_BASIC_OPTIONS += -$$($1_JTREG_TEST_MODE) \ -verbose:$$(JTREG_VERBOSE) -retain:$$(JTREG_RETAIN) \ -concurrency:$$($1_JTREG_JOBS) -timeoutFactor:$$(JTREG_TIMEOUT_FACTOR) \ -vmoption:-XX:MaxRAMPercentage=$$($1_JTREG_MAX_RAM_PERCENTAGE) \ + -vmoption:-Dtest.boot.jdk="$$(BOOT_JDK)" \ -vmoption:-Djava.io.tmpdir="$$($1_TEST_TMP_DIR)" $1_JTREG_BASIC_OPTIONS += -automatic -ignore:quiet diff --git a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java index 6f676c57318..7dd6bf6a5e4 100644 --- a/src/java.base/share/classes/java/lang/ProcessHandleImpl.java +++ b/src/java.base/share/classes/java/lang/ProcessHandleImpl.java @@ -100,7 +100,7 @@ final class ProcessHandleImpl implements ProcessHandle { ThreadFactory threadFactory = grimReaper -> { Thread t = InnocuousThread.newSystemThread("process reaper", grimReaper, stackSize, Thread.MAX_PRIORITY); - t.setDaemon(true); + privilegedThreadSetDaemon(t, true); return t; }; @@ -115,6 +115,22 @@ private static class ExitCompletion extends CompletableFuture { } } + @SuppressWarnings("removal") + private static void privilegedThreadSetName(Thread thread, String name) { + AccessController.doPrivileged((PrivilegedAction) () -> { + thread.setName(name); + return null; + }); + } + + @SuppressWarnings("removal") + private static void privilegedThreadSetDaemon(Thread thread, boolean on) { + AccessController.doPrivileged((PrivilegedAction) () -> { + thread.setDaemon(on); + return null; + }); + } + /** * Returns a CompletableFuture that completes with process exit status when * the process completes. @@ -140,8 +156,9 @@ static CompletableFuture completion(long pid, boolean shouldReap) { processReaperExecutor.execute(new Runnable() { // Use inner class to avoid lambda stack overhead public void run() { - String threadName = Thread.currentThread().getName(); - Thread.currentThread().setName("process reaper (pid " + pid + ")"); + Thread t = Thread.currentThread(); + String threadName = t.getName(); + privilegedThreadSetName(t, "process reaper (pid " + pid + ")"); try { int exitValue = waitForProcessExit0(pid, shouldReap); if (exitValue == NOT_A_CHILD) { @@ -172,7 +189,7 @@ public void run() { completions.remove(pid, newCompletion); } finally { // Restore thread name - Thread.currentThread().setName(threadName); + privilegedThreadSetName(t, threadName); } } }); diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java index 401119989a9..2be66b7002c 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java @@ -74,6 +74,7 @@ * @jvms 4.4 The Constant Pool * * @since 12 + * @sealedGraph */ public sealed interface ConstantDesc permits ClassDesc, diff --git a/src/java.base/share/classes/java/lang/invoke/CallSite.java b/src/java.base/share/classes/java/lang/invoke/CallSite.java index 82e82fe2672..817cb3b6138 100644 --- a/src/java.base/share/classes/java/lang/invoke/CallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java @@ -83,6 +83,7 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam } * @author John Rose, JSR 292 EG * @since 1.7 + * @sealedGraph */ public abstract sealed class CallSite permits ConstantCallSite, MutableCallSite, VolatileCallSite { diff --git a/src/java.base/share/classes/javax/security/auth/Subject.java b/src/java.base/share/classes/javax/security/auth/Subject.java index cb20ba6abde..9d304a1da44 100644 --- a/src/java.base/share/classes/javax/security/auth/Subject.java +++ b/src/java.base/share/classes/javax/security/auth/Subject.java @@ -325,10 +325,6 @@ public Subject run() { * retrieved by this method. After {@code action} is finished, the current * subject is reset to its previous value. The current * subject is {@code null} before the first call of {@code callAs()}. - *

- * When a new thread is created, its current subject is the same as - * the one of its parent thread, and will not change even if - * its parent thread's current subject is changed to another value. * * @implNote * This method returns the same value as diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 27c2d4bad4a..02e3fa0271b 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -415,8 +415,8 @@ If you are expected to specify the percentage, then use a number from 0 to 1. For example, specify \f[V]0.25\f[R] for 25%. .PP -The following sections describe the options that are obsolete, -deprecated, and removed: +The following sections describe the options that are deprecated, +obsolete, and removed: .IP \[bu] 2 \f[B]Deprecated Java Options\f[R]: Accepted and acted upon --- a warning is issued when they\[aq]re used. @@ -441,17 +441,22 @@ either \f[V]--\f[R]\f[I]name\f[R]\f[V]=\f[R]\f[I]value\f[R] or Loads the specified native agent library. After the library name, a comma-separated list of options specific to the library can be used. +If the option \f[V]-agentlib:foo\f[R] is specified, then the JVM +attempts to load the library named \f[V]foo\f[R] using the platform +specific naming conventions and locations: .RS .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] If the option \f[V]-agentlib:foo\f[R] is -specified, then the JVM attempts to load the library named -\f[V]libfoo.so\f[R] in the location specified by the -\f[V]LD_LIBRARY_PATH\f[R] system variable (on macOS this variable is -\f[V]DYLD_LIBRARY_PATH\f[R]). +\f[B]Linux and other POSIX-like platforms:\f[R] The JVM attempts to load +the library named \f[V]libfoo.so\f[R] in the location specified by the +\f[V]LD_LIBRARY_PATH\f[R] system variable. .IP \[bu] 2 -\f[B]Windows:\f[R] If the option \f[V]-agentlib:foo\f[R] is specified, -then the JVM attempts to load the library named \f[V]foo.dll\f[R] in the -location specified by the \f[V]PATH\f[R] system variable. +\f[B]macOS:\f[R] The JVM attempts to load the library named +\f[V]libfoo.dylib\f[R] in the location specified by the +\f[V]DYLD_LIBRARY_PATH\f[R] system variable. +.IP \[bu] 2 +\f[B]Windows:\f[R] The JVM attempts to load the library named +\f[V]foo.dll\f[R] in the location specified by the \f[V]PATH\f[R] system +variable. .RS 2 .PP The following example shows how to load the Java Debug Wire Protocol @@ -966,7 +971,7 @@ running user cleanup code (such as closing database connections) at shutdown, even if the JVM terminates abruptly. .RS .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] +\f[B]Non-Windows:\f[R] .RS 2 .IP \[bu] 2 The JVM catches signals to implement shutdown hooks for unexpected @@ -1012,13 +1017,13 @@ process \f[V]CTRL_C_EVENT\f[R], \f[V]CTRL_CLOSE_EVENT\f[R], .PP There are two consequences of specifying \f[V]-Xrs\f[R]: .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] \f[V]SIGQUIT\f[R] thread dumps aren\[aq]t +\f[B]Non-Windows:\f[R] \f[V]SIGQUIT\f[R] thread dumps aren\[aq]t available. .IP \[bu] 2 \f[B]Windows:\f[R] Ctrl + Break thread dumps aren\[aq]t available. .PP User code is responsible for causing shutdown hooks to run, for example, -by calling the \f[V]System.exit()\f[R] when the JVM is to be terminated. +by calling \f[V]System.exit()\f[R] when the JVM is to be terminated. .RE .TP \f[V]-Xshare:\f[R]\f[I]mode\f[R] @@ -1069,7 +1074,7 @@ Shows settings related to system properties. Shows the settings of the JVM. .TP \f[V]system\f[R] -\f[B]Linux:\f[R] Shows host system or container configuration and +\f[B]Linux only:\f[R] Shows host system or container configuration and continues. .RE .TP @@ -1080,12 +1085,17 @@ or \f[V]M\f[R] to indicate MB, or \f[V]g\f[R] or \f[V]G\f[R] to indicate GB. The actual size may be rounded up to a multiple of the system page size as required by the operating system. -The default value depends on the platform: +The default value depends on the platform. +For example: .RS .IP \[bu] 2 -Linux/x64 (64-bit): 1024 KB +Linux/x64: 1024 KB +.IP \[bu] 2 +Linux/Aarch64: 2048 KB +.IP \[bu] 2 +macOS/x64: 1024 KB .IP \[bu] 2 -macOS (64-bit): 1024 KB +macOS/Aarch64: 2048 KB .IP \[bu] 2 Windows: The default value depends on virtual memory .PP @@ -1251,8 +1261,8 @@ the identifier of the process is specified as \f[V]%p\f[R]): \f[V]-XX:ErrorFile=./hs_err_pid%p.log\f[R] .RE .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] The following example shows how to set the -error log to \f[V]/var/log/java/java_error.log\f[R]: +\f[B]Non-Windows:\f[R] The following example shows how to set the error +log to \f[V]/var/log/java/java_error.log\f[R]: .RS 2 .RS .PP @@ -1274,7 +1284,7 @@ Otherwise, if the file can\[aq]t be created in the specified directory (due to insufficient space, permission problem, or another issue), then the file is created in the temporary directory for the operating system: .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] The temporary directory is \f[V]/tmp\f[R]. +\f[B]Non-Windows:\f[R] The temporary directory is \f[V]/tmp\f[R]. .IP \[bu] 2 \f[B]Windows:\f[R] The temporary directory is specified by the value of the \f[V]TMP\f[R] environment variable; if that environment variable @@ -1406,7 +1416,7 @@ Disables the attempt to set the soft limit for the number of open file descriptors to the hard limit. By default, this option is enabled on all platforms, but is ignored on Windows. -The only time that you may need to disable this is on Mac OS, where its +The only time that you may need to disable this is on macOS, where its use imposes a maximum of 10240, which is lower than the actual system maximum. .TP @@ -1485,7 +1495,7 @@ If the string contains spaces, then it must be enclosed in quotation marks. .RS .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] The following example shows how the +\f[B]Non-Windows:\f[R] The following example shows how the \f[V]-XX:OnError\f[R] option can be used to run the \f[V]gcore\f[R] command to create a core image, and start the \f[V]gdb\f[R] debugger to attach to the process in case of an irrecoverable error (the @@ -1729,12 +1739,17 @@ Sets the Java thread stack size (in kilobytes). Use of a scaling suffix, such as \f[V]k\f[R], results in the scaling of the kilobytes value so that \f[V]-XX:ThreadStackSize=1k\f[R] sets the Java thread stack size to 1024*1024 bytes or 1 megabyte. -The default value depends on the platform: +The default value depends on the platform. +For example: .RS .IP \[bu] 2 -Linux/x64 (64-bit): 1024 KB +Linux/x64: 1024 KB +.IP \[bu] 2 +Linux/Aarch64: 2048 KB .IP \[bu] 2 -macOS (64-bit): 1024 KB +macOS/x64: 1024 KB +.IP \[bu] 2 +macOS/Aarch64: 2048 KB .IP \[bu] 2 Windows: The default value depends on virtual memory .PP @@ -1772,13 +1787,13 @@ See the \f[V]-XX:ObjectAlignmentInBytes\f[R] option. .RE .TP \f[V]-XX:-UseContainerSupport\f[R] -The VM now provides automatic container detection support, which allows -the VM to determine the amount of memory and number of processors that -are available to a Java process running in docker containers. +\f[B]Linux only:\f[R] The VM now provides automatic container detection +support, which allows the VM to determine the amount of memory and +number of processors that are available to a Java process running in +docker containers. It uses this information to allocate system resources. -This support is only available on Linux x64 platforms. -If supported, the default for this flag is \f[V]true\f[R], and container -support is enabled by default. +The default for this flag is \f[V]true\f[R], and container support is +enabled by default. It can be disabled with \f[V]-XX:-UseContainerSupport\f[R]. .RS .PP @@ -1822,7 +1837,8 @@ the OS moves other pages around to create huge pages; this option is made available for experimentation. .TP \f[V]-XX:+AllowUserSignalHandlers\f[R] -Enables installation of signal handlers by the application. +\f[B]Non-Windows:\f[R] Enables installation of signal handlers by the +application. By default, this option is disabled and the application isn\[aq]t allowed to install signal handlers. .TP @@ -2782,8 +2798,8 @@ The following example shows how to set the default file explicitly \f[V]-XX:HeapDumpPath=./java_pid%p.hprof\f[R] .RE .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] The following example shows how to set the -heap dump file to \f[V]/var/log/java/java_heapdump.hprof\f[R]: +\f[B]Non-Windows:\f[R] The following example shows how to set the heap +dump file to \f[V]/var/log/java/java_heapdump.hprof\f[R]: .RS 2 .RS .PP @@ -2807,8 +2823,8 @@ By default, the file is created in the current working directory, and it\[aq]s named \f[V]hotspot.log\f[R]. .RS .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] The following example shows how to set the -log file to \f[V]/var/log/java/hotspot.log\f[R]: +\f[B]Non-Windows:\f[R] The following example shows how to set the log +file to \f[V]/var/log/java/hotspot.log\f[R]: .RS 2 .RS .PP @@ -2831,7 +2847,7 @@ Enables printing of a class instance histogram after one of the following events: .RS .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] \f[V]Control+Break\f[R] +\f[B]Non-Windows:\f[R] \f[V]Control+\[rs]\f[R] (\f[V]SIGQUIT\f[R]) .IP \[bu] 2 \f[B]Windows:\f[R] \f[V]Control+C\f[R] (\f[V]SIGTERM\f[R]) .PP @@ -2848,7 +2864,7 @@ Enables printing of \f[V]java.util.concurrent\f[R] locks after one of the following events: .RS .IP \[bu] 2 -\f[B]Linux and macOS:\f[R] \f[V]Control+Break\f[R] +\f[B]Non-Windows:\f[R] \f[V]Control+\[rs]\f[R] (\f[V]SIGQUIT\f[R]) .IP \[bu] 2 \f[B]Windows:\f[R] \f[V]Control+C\f[R] (\f[V]SIGTERM\f[R]) .PP diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index a697db1cff1..fb2706e2ab9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -4119,6 +4119,10 @@ private boolean checkCastablePattern(DiagnosticPosition pos, Type exprType, Type pattType) { Warner warner = new Warner(); + // if any type is erroneous, the problem is reported elsewhere + if (exprType.isErroneous() || pattType.isErroneous()) { + return false; + } if (!types.isCastable(exprType, pattType, warner)) { chk.basicHandler.report(pos, diags.fragment(Fragments.InconvertibleTypes(exprType, pattType))); @@ -4180,7 +4184,7 @@ public void visitRecordPattern(JCRecordPattern tree) { tree.record = record; } else { log.error(tree.pos(), Errors.DeconstructionPatternOnlyRecords(site.tsym)); - expectedRecordTypes = Stream.generate(() -> Type.noType) + expectedRecordTypes = Stream.generate(() -> types.createErrorType(tree.type)) .limit(tree.nested.size()) .collect(List.collector()); tree.record = syms.errSymbol; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/main/CommandLine.java b/src/jdk.internal.opt/share/classes/jdk/internal/opt/CommandLine.java similarity index 56% rename from src/jdk.jpackage/share/classes/jdk/jpackage/main/CommandLine.java rename to src/jdk.internal.opt/share/classes/jdk/internal/opt/CommandLine.java index 8038be759fd..81eb0d26912 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/main/CommandLine.java +++ b/src/jdk.internal.opt/share/classes/jdk/internal/opt/CommandLine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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,34 +23,38 @@ * questions. */ -package jdk.jpackage.main; +package jdk.internal.opt; -import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.Charset; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -/** +/* * This file was originally a copy of CommandLine.java in - * com.sun.tools.javac.main. - * It should track changes made to that file. + * com.sun.tools.javac.main -- and it will be the last. + * + * Find details at https://bugs.openjdk.org/browse/JDK-8236919 */ /** * Various utility methods for processing Java tool command line arguments. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. */ -class CommandLine { +public final class CommandLine { + /** + * Convenient wrapper for the {@code List}-based parse method. + * + * @see #parse(List) + */ + public static String[] parse(String... args) throws IOException { + return parse(List.of(args)).toArray(String[]::new); + } + /** * Process Win32-style command files for the specified command line * arguments and return the resulting arguments. A command file argument @@ -64,14 +68,13 @@ class CommandLine { * @return the arguments, with @files expanded * @throws IOException if there is a problem reading any of the @files */ - public static String[] parse(String[] args) throws IOException { + public static List parse(List args) throws IOException { List newArgs = new ArrayList<>(); - appendParsedCommandArgs(newArgs, Arrays.asList(args)); - return newArgs.toArray(new String[newArgs.size()]); + appendParsedCommandArgs(newArgs, args); + return newArgs; } - private static void appendParsedCommandArgs(List newArgs, - List args) throws IOException { + private static void appendParsedCommandArgs(List newArgs, List args) throws IOException { for (String arg : args) { if (arg.length() > 1 && arg.charAt(0) == '@') { arg = arg.substring(1); @@ -86,13 +89,45 @@ private static void appendParsedCommandArgs(List newArgs, } } - private static void loadCmdFile(String name, List args) - throws IOException { - if (!Files.isReadable(Path.of(name))) { - throw new FileNotFoundException(name); - } - try (Reader r = Files.newBufferedReader(Paths.get(name), - Charset.defaultCharset())) { + /** + * Process the given environment variable and appends any Win32-style + * command files for the specified command line arguments and return + * the resulting arguments. A command file argument + * is of the form '@file' where 'file' is the name of the file whose + * contents are to be parsed for additional arguments. The contents of + * the command file are parsed using StreamTokenizer and the original + * '@file' argument replaced with the resulting tokens. Recursive command + * files are not supported. The '@' character itself can be quoted with + * the sequence '@@'. + * @param envVariable the env variable to process + * @param args the arguments that may contain @files + * @return the arguments, with environment variable's content and expansion of @files + * @throws IOException if there is a problem reading any of the @files + * @throws CommandLine.UnmatchedQuote + */ + public static List parse(String envVariable, List args) + throws IOException, UnmatchedQuote { + + List inArgs = new ArrayList<>(); + appendParsedEnvVariables(inArgs, envVariable); + inArgs.addAll(args); + List newArgs = new ArrayList<>(); + appendParsedCommandArgs(newArgs, inArgs); + return newArgs; + } + + public static void loadCmdFile(InputStream in, List args) throws IOException { + Reader reader = new InputStreamReader(in); + loadCmdFileAndCloseReader(reader, args); + } + + private static void loadCmdFile(String name, List args) throws IOException { + Reader reader = Files.newBufferedReader(Paths.get(name), Charset.defaultCharset()); + loadCmdFileAndCloseReader(reader, args); + } + + private static void loadCmdFileAndCloseReader(Reader r, List args) throws IOException { + try (r) { Tokenizer t = new Tokenizer(r); String s; while ((s = t.nextToken()) != null) { @@ -151,9 +186,7 @@ public String nextToken() throws IOException { switch (ch) { case '\n': case '\r': - while (ch == ' ' || ch == '\n' - || ch == '\r' || ch == '\t' - || ch == '\f') { + while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') { ch = in.read(); } continue; @@ -170,8 +203,6 @@ public String nextToken() throws IOException { case 'f': ch = '\f'; break; - default: - break; } } sb.append((char) ch); @@ -212,4 +243,75 @@ void skipWhite() throws IOException { } } } + + @SuppressWarnings("fallthrough") + private static void appendParsedEnvVariables(List newArgs, String envVariable) + throws UnmatchedQuote { + + if (envVariable == null) { + return; + } + String in = System.getenv(envVariable); + if (in == null || in.trim().isEmpty()) { + return; + } + + final char NUL = (char)0; + final int len = in.length(); + + int pos = 0; + StringBuilder sb = new StringBuilder(); + char quote = NUL; + char ch; + + loop: + while (pos < len) { + ch = in.charAt(pos); + switch (ch) { + case '\"': case '\'': + if (quote == NUL) { + quote = ch; + } else if (quote == ch) { + quote = NUL; + } else { + sb.append(ch); + } + pos++; + break; + case '\f': case '\n': case '\r': case '\t': case ' ': + if (quote == NUL) { + newArgs.add(sb.toString()); + sb.setLength(0); + while (ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') { + pos++; + if (pos >= len) { + break loop; + } + ch = in.charAt(pos); + } + break; + } + // fall through + default: + sb.append(ch); + pos++; + } + } + if (sb.length() != 0) { + newArgs.add(sb.toString()); + } + if (quote != NUL) { + throw new UnmatchedQuote(envVariable); + } + } + + public static class UnmatchedQuote extends Exception { + private static final long serialVersionUID = 0; + + public final String variableName; + + UnmatchedQuote(String variable) { + this.variableName = variable; + } + } } diff --git a/src/jdk.internal.opt/share/classes/module-info.java b/src/jdk.internal.opt/share/classes/module-info.java index 2bc55831c78..778970a65e1 100644 --- a/src/jdk.internal.opt/share/classes/module-info.java +++ b/src/jdk.internal.opt/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -30,4 +30,5 @@ */ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell; + exports jdk.internal.opt to jdk.jartool, jdk.jlink, jdk.jpackage; } diff --git a/src/jdk.jartool/share/classes/module-info.java b/src/jdk.jartool/share/classes/module-info.java index b14e47f7c29..fc630c3002c 100644 --- a/src/jdk.jartool/share/classes/module-info.java +++ b/src/jdk.jartool/share/classes/module-info.java @@ -48,6 +48,8 @@ * @since 9 */ module jdk.jartool { + requires jdk.internal.opt; + exports com.sun.jarsigner; exports jdk.security.jarsigner; diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/CommandLine.java b/src/jdk.jartool/share/classes/sun/tools/jar/CommandLine.java deleted file mode 100644 index 7a17f4600db..00000000000 --- a/src/jdk.jartool/share/classes/sun/tools/jar/CommandLine.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2003, 2012, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 sun.tools.jar; - -import java.io.IOException; -import java.io.Reader; -import java.io.FileReader; -import java.io.BufferedReader; -import java.io.StreamTokenizer; -import java.util.List; -import java.util.ArrayList; - -/** - * Various utility methods for processing Java tool command line arguments. - * - *

This is NOT part of any API supported by Oracle. If - * you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class CommandLine { - /** - * Process Win32-style command files for the specified command line - * arguments and return the resulting arguments. A command file argument - * is of the form '@file' where 'file' is the name of the file whose - * contents are to be parsed for additional arguments. The contents of - * the command file are parsed using StreamTokenizer and the original - * '@file' argument replaced with the resulting tokens. Recursive command - * files are not supported. The '@' character itself can be quoted with - * the sequence '@@'. - */ - public static String[] parse(String[] args) - throws IOException - { - List newArgs = new ArrayList<>(args.length); - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.length() > 1 && arg.charAt(0) == '@') { - arg = arg.substring(1); - if (arg.charAt(0) == '@') { - newArgs.add(arg); - } else { - loadCmdFile(arg, newArgs); - } - } else { - newArgs.add(arg); - } - } - return newArgs.toArray(new String[newArgs.size()]); - } - - private static void loadCmdFile(String name, List args) - throws IOException - { - Reader r = new BufferedReader(new FileReader(name)); - StreamTokenizer st = new StreamTokenizer(r); - st.resetSyntax(); - st.wordChars(' ', 255); - st.whitespaceChars(0, ' '); - st.commentChar('#'); - st.quoteChar('"'); - st.quoteChar('\''); - while (st.nextToken() != StreamTokenizer.TT_EOF) { - args.add(st.sval); - } - r.close(); - } -} diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index c582f2d80ce..8c94eb7f85e 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -68,6 +68,7 @@ import jdk.internal.module.ModuleInfoExtender; import jdk.internal.module.ModuleResolution; import jdk.internal.module.ModuleTarget; +import jdk.internal.opt.CommandLine; import jdk.internal.util.jar.JarIndex; import java.time.LocalDateTime; import java.time.ZoneOffset; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/CommandLine.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/CommandLine.java deleted file mode 100644 index f504d7a5739..00000000000 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/CommandLine.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.tools.jlink.internal; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.List; - -/** - * This file was originally a copy of CommandLine.java in - * com.sun.tools.javac.main. - * It should track changes made to that file. - */ - -/** - * Various utility methods for processing Java tool command line arguments. - */ -public class CommandLine { - - static void loadCmdFile(InputStream in, List args) - throws IOException { - try (Reader r = new InputStreamReader(in)) { - Tokenizer t = new Tokenizer(r); - String s; - while ((s = t.nextToken()) != null) { - args.add(s); - } - } - } - public static class Tokenizer { - private final Reader in; - private int ch; - - public Tokenizer(Reader in) throws IOException { - this.in = in; - ch = in.read(); - } - - public String nextToken() throws IOException { - skipWhite(); - if (ch == -1) { - return null; - } - - StringBuilder sb = new StringBuilder(); - char quoteChar = 0; - - while (ch != -1) { - switch (ch) { - case ' ': - case '\t': - case '\f': - if (quoteChar == 0) { - return sb.toString(); - } - sb.append((char) ch); - break; - - case '\n': - case '\r': - return sb.toString(); - - case '\'': - case '"': - if (quoteChar == 0) { - quoteChar = (char) ch; - } else if (quoteChar == ch) { - quoteChar = 0; - } else { - sb.append((char) ch); - } - break; - - case '\\': - if (quoteChar != 0) { - ch = in.read(); - switch (ch) { - case '\n': - case '\r': - while (ch == ' ' || ch == '\n' - || ch == '\r' || ch == '\t' - || ch == '\f') { - ch = in.read(); - } - continue; - - case 'n': - ch = '\n'; - break; - case 'r': - ch = '\r'; - break; - case 't': - ch = '\t'; - break; - case 'f': - ch = '\f'; - break; - default: - break; - } - } - sb.append((char) ch); - break; - - default: - sb.append((char) ch); - } - - ch = in.read(); - } - - return sb.toString(); - } - - void skipWhite() throws IOException { - while (ch != -1) { - switch (ch) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - break; - - case '#': - ch = in.read(); - while (ch != '\n' && ch != '\r' && ch != -1) { - ch = in.read(); - } - break; - - default: - return; - } - - ch = in.read(); - } - } - } -} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 3484332cdd3..344c91d0e75 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -70,6 +70,7 @@ import jdk.tools.jlink.plugin.PluginException; import jdk.tools.jlink.builder.DefaultImageBuilder; import jdk.tools.jlink.plugin.Plugin; +import jdk.internal.opt.CommandLine; import jdk.internal.module.ModulePath; import jdk.internal.module.ModuleResolution; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/main/Main.java b/src/jdk.jpackage/share/classes/jdk/jpackage/main/Main.java index e2163322ab3..97b1faee249 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/main/Main.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -25,6 +25,7 @@ package jdk.jpackage.main; +import jdk.internal.opt.CommandLine; import jdk.jpackage.internal.Arguments; import jdk.jpackage.internal.Log; import jdk.jpackage.internal.CLIHelp; diff --git a/src/jdk.jpackage/share/classes/module-info.java b/src/jdk.jpackage/share/classes/module-info.java index 5fd36ee6b2f..ea41abd75d8 100644 --- a/src/jdk.jpackage/share/classes/module-info.java +++ b/src/jdk.jpackage/share/classes/module-info.java @@ -51,6 +51,7 @@ */ module jdk.jpackage { + requires jdk.internal.opt; requires jdk.jlink; requires java.desktop; diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 7133210fac9..f6956d30c3c 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -68,9 +68,6 @@ compiler/c2/Test8004741.java 8235801 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all -compiler/debug/TestStressCM.java 8297343 generic-all -compiler/debug/TestStressIGVNAndCCP.java 8297343 generic-all - ############################################################################# # :hotspot_gc diff --git a/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java b/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java index 31f28d9eee2..050261194ef 100644 --- a/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java +++ b/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java @@ -35,29 +35,33 @@ import jdk.test.whitebox.WhiteBox; import jdk.test.lib.classloader.ClassUnloadCommon; +import java.lang.reflect.Array; + /** - * Test that verifies that classes are unloaded when they are no longer reachable. + * Test that verifies that liveness of classes is correctly tracked. * - * The test creates a class loader, uses the loader to load a class and creates an instance - * of that class. The it nulls out all the references to the instance, class and class loader - * and tries to trigger class unloading. Then it verifies that the class is no longer - * loaded by the VM. + * The test creates a class loader, uses the loader to load a class and creates + * an instance related to that class. + * 1. Then, it nulls out references to the class loader, triggers class + * unloading and verifies the class is *not* unloaded. + * 2. Next, it nulls out references to the instance, triggers class unloading + * and verifies the class is unloaded. */ public class UnloadTest { - private static String className = "test.Empty"; public static void main(String... args) throws Exception { - run(); + test_unload_instance_klass(); + test_unload_obj_array_klass(); } - private static void run() throws Exception { + private static void test_unload_instance_klass() throws Exception { + final String className = "test.Empty"; final WhiteBox wb = WhiteBox.getWhiteBox(); ClassUnloadCommon.failIf(wb.isClassAlive(className), "is not expected to be alive yet"); ClassLoader cl = ClassUnloadCommon.newClassLoader(); - Class c = cl.loadClass(className); - Object o = c.newInstance(); + Object o = cl.loadClass(className).newInstance(); ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here"); @@ -65,8 +69,42 @@ private static void run() throws Exception { int loadedRefcount = wb.getSymbolRefcount(loaderName); System.out.println("Refcount of symbol " + loaderName + " is " + loadedRefcount); - cl = null; c = null; o = null; + cl = null; + ClassUnloadCommon.triggerUnloading(); + + ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should still be live"); + + o = null; ClassUnloadCommon.triggerUnloading(); + + + ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded"); + + int unloadedRefcount = wb.getSymbolRefcount(loaderName); + System.out.println("Refcount of symbol " + loaderName + " is " + unloadedRefcount); + ClassUnloadCommon.failIf(unloadedRefcount != (loadedRefcount - 1), "Refcount must be decremented"); + } + + private static void test_unload_obj_array_klass() throws Exception { + final WhiteBox wb = WhiteBox.getWhiteBox(); + + ClassLoader cl = ClassUnloadCommon.newClassLoader(); + Object o = Array.newInstance(cl.loadClass("test.Empty"), 1); + final String className = o.getClass().getName(); + + ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here"); + + String loaderName = cl.getName(); + int loadedRefcount = wb.getSymbolRefcount(loaderName); + System.out.println("Refcount of symbol " + loaderName + " is " + loadedRefcount); + + cl = null; + ClassUnloadCommon.triggerUnloading(); + ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should still be live"); + + o = null; + ClassUnloadCommon.triggerUnloading(); + ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded"); int unloadedRefcount = wb.getSymbolRefcount(loaderName); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/BadNativeStackInErrorHandlingTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/BadNativeStackInErrorHandlingTest.java index 64faeada1eb..0da66113db4 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/BadNativeStackInErrorHandlingTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/BadNativeStackInErrorHandlingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -58,44 +58,15 @@ public static void main(String[] args) throws Exception { output_detail.shouldMatch("# +(?:SIGSEGV|SIGBUS|EXCEPTION_ACCESS_VIOLATION).*"); // extract hs-err file - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs-err file in output.\n"); - } - - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs-err file missing at " + - f.getAbsolutePath() + ".\n"); - } - - System.out.println("Found hs_err file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); // The failing line looks like this: // [error occurred during error reporting (printing native stack), id 0xb] - Pattern pattern = - Pattern.compile("\\[error occurred during error reporting \\(printing native stack\\), id .*\\]"); - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (pattern.matcher(line).matches()) { - System.out.println("Found: " + line + "."); - throw new RuntimeException("hs-err file should not contain: '" + - pattern + "'"); - } - lastLine = line; - } - br.close(); + Pattern negativePatterns[] = { + Pattern.compile("\\[error occurred during error reporting \\(printing native stack\\), id .*\\]") + }; - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + HsErrFileUtils.checkHsErrFileContent(hs_err_file, null, negativePatterns, true /* check end marker */, false /* verbose */); System.out.println("OK."); } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/HsErrFileUtils.java b/test/hotspot/jtreg/runtime/ErrorHandling/HsErrFileUtils.java index a818989fe48..4eb21a8e937 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/HsErrFileUtils.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/HsErrFileUtils.java @@ -25,6 +25,7 @@ import jdk.test.lib.process.OutputAnalyzer; import java.io.*; +import java.util.*; import java.util.regex.Pattern; public class HsErrFileUtils { @@ -47,8 +48,6 @@ public static String extractHsErrFileNameFromOutput(OutputAnalyzer output) { /** * Given the output of a java VM that crashed, extract the name of the hs-err file from the output, * open that file and return its File. - * @param output - * @return */ public static File openHsErrFileFromOutput(OutputAnalyzer output) { String name = extractHsErrFileNameFromOutput(output); @@ -60,46 +59,86 @@ public static File openHsErrFileFromOutput(OutputAnalyzer output) { } /** - * Given an open hs-err file, read it line by line and check for pattern. Pattern - * need to appear in order, but not necessarily uninterrupted. + * Given an open hs-err file, read it line by line and check for existence of a set of patterns. Will fail + * if patterns are missing, or if the END marker is missing. + * @param f Input file + * @param patterns An array of patterns that need to match, in that order + * @param verbose If true, the content of the hs-err file is printed while matching. If false, only the matched patterns + * are printed. + * @throws RuntimeException, {@link IOException} */ public static void checkHsErrFileContent(File f, Pattern[] patterns, boolean verbose) throws IOException { + checkHsErrFileContent(f, patterns, null, true, verbose); + } - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; - - int currentPattern = 0; - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (verbose) { - System.out.println(line); + /** + * Given an open hs-err file, read it line by line and check for various conditions. + * @param f input file + * @param positivePatterns Optional array of patterns that need to appear, in given order, in the file. Missing + * patterns cause the test to fail. + * @param negativePatterns Optional array of patterns that must not appear in the file; test fails if they do. + * Order is irrelevant. + * @param checkEndMarker If true, we check for the final "END" in an hs-err file; if it is missing it indicates + * that hs-err file printing did not complete successfully. + * @param verbose If true, the content of the hs-err file is printed while matching. If false, only important + * information are printed. + * @throws RuntimeException, {@link IOException} + */ + public static void checkHsErrFileContent(File f, Pattern[] positivePatterns, Pattern[] negativePatterns, boolean checkEndMarker, boolean verbose) throws IOException { + try ( + FileInputStream fis = new FileInputStream(f); + BufferedReader br = new BufferedReader(new InputStreamReader(fis)); + ) { + String line = null; + String lastLine = null; + int lineNo = 0; + + Deque positivePatternStack = new ArrayDeque(); + if (positivePatterns != null) { + Collections.addAll(positivePatternStack, positivePatterns); } - if (currentPattern < patterns.length) { - if (patterns[currentPattern].matcher(line).matches()) { - if (!verbose) { - System.out.println(line); + Pattern currentPositivePattern = positivePatternStack.pollFirst(); + + while ((line = br.readLine()) != null) { + if (verbose) { + System.out.println(line); + } + if (currentPositivePattern != null) { + if (currentPositivePattern.matcher(line).matches()) { + if (!verbose) { + System.out.println(line); + } + System.out.println("^^^ Matches " + currentPositivePattern + " at line " + lineNo + "^^^"); + currentPositivePattern = positivePatternStack.pollFirst(); + if (currentPositivePattern == null && negativePatterns == null && checkEndMarker == false) { + System.out.println("Lazily skipping the rest of the hs-err file..."); + break; // Shortcut. Nothing to do. + } + } + } + if (negativePatterns != null) { + for (Pattern negativePattern : negativePatterns) { + if (negativePattern.matcher(line).matches()) { + if (!verbose) { + System.out.println(line); + } + System.out.println("^^^ Forbidden pattern found at line " + lineNo + ": " + negativePattern + "^^^"); + throw new RuntimeException("Forbidden pattern found at line " + lineNo + ": " + negativePattern); + } } - System.out.println("^^^ Match " + currentPattern + ": matches " + patterns[currentPattern] + "^^^"); - currentPattern ++; } + lastLine = line; + lineNo++; } - lastLine = line; - } - br.close(); - - if (currentPattern < patterns.length) { - throw new RuntimeException("hs-err file incomplete (found " + currentPattern + " matching pattern, " + - "first missing pattern: " + patterns[currentPattern] + ")"); - } - - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); + // Found all positive pattern? + if (!positivePatternStack.isEmpty()) { + throw new RuntimeException("hs-err file incomplete (first missing pattern: " + positivePatternStack.peek() + ")"); + } + if (checkEndMarker && !lastLine.equals("END.")) { + throw new RuntimeException("hs-err file incomplete (missing END marker.)"); + } + System.out.println("hs-err file " + f.getAbsolutePath() + " scanned successfully."); } - - System.out.println("Found all expected pattern in hs-err file at " + f.getAbsolutePath()); - } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java index e591a58e357..fabc477a631 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java @@ -34,6 +34,7 @@ * @run driver MachCodeFramesInErrorFile */ +import java.io.File; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.nio.file.Files; @@ -126,12 +127,8 @@ private static void run(boolean crashInJava) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); // Extract hs_err_pid file. - String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - output.reportDiagnosticSummary(); - throw new RuntimeException("Did not find hs_err_pid file in output"); - } - Path hsErrPath = Paths.get(hs_err_file); + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output); + Path hsErrPath = hs_err_file.toPath(); if (!Files.exists(hsErrPath)) { throw new RuntimeException("hs_err_pid file missing at " + hsErrPath + ".\n"); } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java index d21c8a04ab6..75ce802890e 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -70,22 +70,7 @@ public static void main(String[] args) throws Exception { System.out.println("Found specific fatal error."); // Extract hs_err_pid file. - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs_err_pid file in output.\n"); - } - - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs_err_pid file missing at " - + f.getAbsolutePath() + ".\n"); - } - - System.out.println("Found hs_err_pid file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); Pattern [] pattern = new Pattern[] { // The "Current thread" line should show a hazard ptr and @@ -101,31 +86,9 @@ public static void main(String[] args) throws Exception { // should show a nested hazard ptr: Pattern.compile("=>.* JavaThread \"main\" .*, _nested_threads_hazard_ptr_cnt=1, _nested_threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*.*"), }; - int currentPattern = 0; - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern++; - } - } - lastLine = line; - } - br.close(); - - if (currentPattern < pattern.length) { - throw new RuntimeException("hs_err_pid file incomplete (first missing pattern: " + currentPattern + ")"); - } - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, false); - System.out.println("Done scanning hs_err_pid_file."); System.out.println("PASSED."); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/ResourceMarkTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/ResourceMarkTest.java index 2ae060684ac..1e5550afcad 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/ResourceMarkTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/ResourceMarkTest.java @@ -63,54 +63,18 @@ public static void main(String[] args) throws Exception { output_detail.shouldMatch("This is a message with no ResourceMark"); // extract hs-err file - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs-err file in output.\n"); - } + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); // scan hs-err file: File should NOT contain the "[error occurred during error reporting..]" // markers which show that the secondary error handling kicked in and handled the // error successfully. As an added test, we check that the last line contains "END.", // which is an end marker written in the last step and proves that hs-err file was // completely written. - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs-err file missing at " - + f.getAbsolutePath() + ".\n"); - } - - System.out.println("Found hs_err file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; - - Pattern [] pattern = new Pattern[] { + Pattern [] negativePattern = new Pattern[] { Pattern.compile("\\[error occurred during error reporting \\(test missing ResourceMark does not crash\\), id 0xe0000000, Internal Error \\(.*resourceArea.cpp:.*\\)\\]"), }; - int currentPattern = 0; - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern ++; - } - } - lastLine = line; - } - br.close(); - - if (currentPattern == pattern.length) { - throw new RuntimeException("hs-err file found secondary crash for ResourceMark"); - } - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + HsErrFileUtils.checkHsErrFileContent(hs_err_file, null, negativePattern, true /* check end marker */, false /* verbose */); System.out.println("OK."); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java index 8f3419d88e8..8c9d70373f7 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/SafeFetchInErrorHandlingTest.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022 SAP SE. All rights reserved. + * Copyright (c) 2015, 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 @@ -60,50 +61,16 @@ public static void main(String[] args) throws Exception { output_detail.shouldMatch("# +(?:SIGSEGV|SIGBUS|EXCEPTION_ACCESS_VIOLATION).*"); // extract hs-err file - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs-err file in output.\n"); - } - - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs-err file missing at " - + f.getAbsolutePath() + ".\n"); - } - - System.out.println("Found hs_err file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); + // File should contain "Will test SafeFetch, SafeFetch OK". The latter indicates we survived the SafeFetch without + // a secondary crash. Pattern [] pattern = new Pattern[] { Pattern.compile("Will test SafeFetch..."), Pattern.compile("SafeFetch OK."), }; - int currentPattern = 0; - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern ++; - } - } - lastLine = line; - } - br.close(); - - if (currentPattern < pattern.length) { - throw new RuntimeException("hs-err file incomplete (first missing pattern: " + currentPattern + ")"); - } - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, true); System.out.println("OK."); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java index 7790d069ac3..59325adc9f8 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/SecondaryErrorTest.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022 SAP SE. All rights reserved. + * Copyright (c) 2014, 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 +25,7 @@ /* * @test - * @bug 8065896 + * @bug 8065895 * @summary Synchronous signals during error reporting may terminate or hang VM process * @library /test/lib * @requires vm.debug @@ -63,27 +64,13 @@ public static void main(String[] args) throws Exception { output_detail.shouldMatch("#.+SIGFPE.*"); // extract hs-err file - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs-err file in output.\n"); - } + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); // scan hs-err file: File should contain the "[error occurred during error reporting..]" // markers which show that the secondary error handling kicked in and handled the // error successfully. As an added test, we check that the last line contains "END.", // which is an end marker written in the last step and proves that hs-err file was // completely written. - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs-err file missing at " - + f.getAbsolutePath() + ".\n"); - } - - System.out.println("Found hs_err file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; Pattern [] pattern = new Pattern[] { Pattern.compile("Will crash now \\(TestCrashInErrorHandler=14\\)..."), @@ -91,29 +78,8 @@ public static void main(String[] args) throws Exception { Pattern.compile("Will crash now \\(TestCrashInErrorHandler=14\\)..."), Pattern.compile("\\[error occurred during error reporting \\(test secondary crash 2\\).*\\]"), }; - int currentPattern = 0; - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern ++; - } - } - lastLine = line; - } - br.close(); - - if (currentPattern < pattern.length) { - throw new RuntimeException("hs-err file incomplete (first missing pattern: " + currentPattern + ")"); - } - - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, false); System.out.println("OK."); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java index f0e44564a0e..7f967a0a74d 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/ShowRegistersOnAssertTest.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018, 2022 SAP SE. All rights reserved. * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java index 3ef7c868462..c7d91637b38 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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,6 +37,7 @@ import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.IOException; +import java.util.regex.Pattern; public class TestCrashOnOutOfMemoryError { @@ -88,36 +89,15 @@ public static void main(String[] args) throws Exception { */ output.shouldContain("Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit"); // extract hs-err file - String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new Error("Did not find hs-err file in output.\n"); - } + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output); - /* - * Check if hs_err files exist or not - */ - File f = new File(hs_err_file); - if (!f.exists()) { - throw new Error("hs-err file missing at "+ f.getAbsolutePath() + ".\n"); - } + // Do a perfunctory check of the hs-err file produced by the crash. + Pattern[] pattern = new Pattern[] { + Pattern.compile(".*fatal error: OutOfMemory encountered: Requested array size exceeds VM limit.*") + }; + + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, false); - /* - * Checking the completness of hs_err file. If last line of hs_err file is "END" - * then it proves that file is complete. - */ - try (FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis))) { - String line = null; - String lastLine = null; - while ((line = br.readLine()) != null) { - lastLine = line; - } - if (!lastLine.equals("END.")) { - throw new Error("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } - } System.out.println("PASSED"); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java index 398bb81d589..244cda0d24a 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestDwarf.java @@ -123,18 +123,16 @@ private static void runAndCheck(Flags flags, DwarfConstraint... constraints) thr crashOut = ProcessTools.executeProcess(ProcessTools.createTestJvm(flags.getFlags())); String crashOutputString = crashOut.getOutput(); Asserts.assertNotEquals(crashOut.getExitValue(), 0, "Crash JVM should not exit gracefully"); - Pattern pattern = Pattern.compile("hs_err_pid[0-9]*.log"); - Matcher matcher = pattern.matcher(crashOutputString); System.out.println(crashOutputString); - if (matcher.find()) { - String hsErrFileName = matcher.group(); - System.out.println("hs_err_file: " + hsErrFileName); - File hs_err_file = new File(hsErrFileName); - BufferedReader reader = new BufferedReader(new FileReader(hs_err_file)); + + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(crashOut); + try (FileReader fr = new FileReader(hs_err_file); + BufferedReader reader = new BufferedReader(fr)) { String line; boolean foundNativeFrames = false; int matches = 0; int frameIdx = 0; + Pattern pattern = Pattern.compile("[CV][\\s\\t]+\\[([a-zA-Z0-9_.]+)\\+0x.+][\\s\\t]+.*\\+0x.+[\\s\\t]+\\([a-zA-Z0-9_.]+\\.[a-z]+:[1-9][0-9]*\\)"); // Check all stack entries after the line starting with "Native frames" in the hs_err_file until an empty line // is found which denotes the end of the stack frames. while ((line = reader.readLine()) != null) { @@ -147,8 +145,7 @@ private static void runAndCheck(Flags flags, DwarfConstraint... constraints) thr matches++; // File and library names are non-empty and may contain English letters, underscores, dots or numbers ([a-zA-Z0-9_.]+). // Line numbers have at least one digit and start with non-zero ([1-9][0-9]*). - pattern = Pattern.compile("[CV][\\s\\t]+\\[([a-zA-Z0-9_.]+)\\+0x.+][\\s\\t]+.*\\+0x.+[\\s\\t]+\\([a-zA-Z0-9_.]+\\.[a-z]+:[1-9][0-9]*\\)"); - matcher = pattern.matcher(line); + Matcher matcher = pattern.matcher(line); if (!matcher.find()) { checkNoSourceLine(crashOutputString, line); } @@ -167,8 +164,6 @@ private static void runAndCheck(Flags flags, DwarfConstraint... constraints) thr } } Asserts.assertGreaterThan(matches, 0, "Could not find any stack frames"); - } else { - throw new RuntimeException("Could not find an hs_err_file"); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java index 5ab7ad6c1b4..682753b2464 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -70,22 +70,7 @@ public static void main(String[] args) throws Exception { System.out.println("Found specific fatal error."); // Extract hs_err_pid file. - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs_err_pid file in output.\n"); - } - - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs_err_pid file missing at " - + f.getAbsolutePath() + ".\n"); - } - - System.out.println("Found hs_err_pid file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); Pattern [] pattern = new Pattern[] { // The "Current thread" line should show a hazard ptr @@ -101,31 +86,9 @@ public static void main(String[] args) throws Exception { // should show no nested hazard ptrs: Pattern.compile("=>.* JavaThread \"main\" .*, _nested_threads_hazard_ptr_cnt=0.*"), }; - int currentPattern = 0; - - String lastLine = null; - while ((line = br.readLine()) != null) { - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern++; - } - } - lastLine = line; - } - br.close(); - - if (currentPattern < pattern.length) { - throw new RuntimeException("hs_err_pid file incomplete (first missing pattern: " + currentPattern + ")"); - } - if (!lastLine.equals("END.")) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, false); - System.out.println("Done scanning hs_err_pid_file."); System.out.println("PASSED."); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TimeoutInErrorHandlingTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/TimeoutInErrorHandlingTest.java index 646aeeef80e..1fc57e248be 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TimeoutInErrorHandlingTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TimeoutInErrorHandlingTest.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2017, 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 @@ -95,68 +96,29 @@ public static void main(String[] args) throws Exception { output_detail.shouldMatch(".*timer expired, abort.*"); // extract hs-err file - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { + File hs_err_file; + try { + hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); + } catch (Exception e) { if (!verbose) { System.err.println(""); System.err.println(output_detail.getOutput()); System.err.println(""); } - throw new RuntimeException("Did not find hs-err file in output.\n"); - } - - File f = new File(hs_err_file); - if (!f.exists()) { - if (!verbose) { - System.err.println(""); - System.err.println(output_detail.getOutput()); - System.err.println(""); - } - throw new RuntimeException("hs-err file missing at " - + f.getAbsolutePath() + ".\n"); + throw e; } System.out.println("Found hs_err file. Scanning..."); - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; - - Pattern [] pattern = new Pattern[] { Pattern.compile(".*timeout occurred during error reporting in step.*"), Pattern.compile(".*timeout occurred during error reporting in step.*") }; - int currentPattern = 0; - - String lastLine = null; - StringBuilder saved_hs_err = new StringBuilder(); - while ((line = br.readLine()) != null) { - saved_hs_err.append(line + System.lineSeparator()); - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern ++; - } - } - lastLine = line; - } - br.close(); - - if (verbose) { - System.err.println(""); - System.err.print(saved_hs_err); - System.err.println(""); - } - if (currentPattern < pattern.length) { - if (!verbose) { - System.err.println(""); - System.err.print(saved_hs_err); - System.err.println(""); - } - throw new RuntimeException("hs-err file incomplete (first missing pattern: " + currentPattern + ")"); - } + // Note: we *dont* check for the end marker, since the hs-err file will likely not have + // one but a global timeout marker. As explained above, we don't check for that one either + // since it is too instable. + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, null, false /* check end marker */,true /* verbose */); System.out.println("OK."); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java index 09b5c045684..b8170ee2426 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, SAP. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022 SAP. 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 @@ -61,55 +61,18 @@ public static void main(String[] args) throws Exception { output_detail.shouldMatch("#.*HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION.*"); // extract hs-err file - String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_file == null) { - throw new RuntimeException("Did not find hs-err file in output.\n"); - } + File hs_err_file = HsErrFileUtils.openHsErrFileFromOutput(output_detail); // scan hs-err file: File should contain the same assertion message. Other than that, // do not expect too much: file will be littered with secondary errors. The test // should test that we get a hs-err file at all. - File f = new File(hs_err_file); - if (!f.exists()) { - throw new RuntimeException("hs-err file missing at " - + f.getAbsolutePath() + ".\n"); - } + // It is highly likely that we miss the END marker, too, since its likely we hit the + // secondary error recursion limit. - System.out.println("Found hs_err file. Scanning..."); - - FileInputStream fis = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line = null; - - Pattern[] pattern = new Pattern[]{ + Pattern[] pattern = new Pattern[] { Pattern.compile(".*HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION.*") }; - int currentPattern = 0; - - boolean endMarkerFound = false; - while ((line = br.readLine()) != null) { - if (currentPattern < pattern.length) { - if (pattern[currentPattern].matcher(line).matches()) { - System.out.println("Found: " + line + "."); - currentPattern++; - } - } - if (line.equals("END.")) { - endMarkerFound = true; - break; - } - } - br.close(); - - if (currentPattern < pattern.length) { - throw new RuntimeException("hs-err file incomplete (first missing pattern: " + currentPattern + ")"); - } - - if (!endMarkerFound) { - throw new RuntimeException("hs-err file incomplete (missing END marker.)"); - } else { - System.out.println("End marker found."); - } + HsErrFileUtils.checkHsErrFileContent(hs_err_file, pattern, null, false /* check end marker */, true /* verbose */); System.out.println("OK."); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java new file mode 100644 index 00000000000..0b57e1c0120 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java @@ -0,0 +1,144 @@ +/* + * 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. + * + */ + + +/* + * @test + * @summary Check that -XX:+AutoCreateSharedArchive automatically recreates an archive when you change the JDK version. + * @requires os.family == "linux" & vm.bits == "64" & (os.arch=="amd64" | os.arch=="x86_64") + * @library /test/lib + * @compile -source 1.8 -target 1.8 ../test-classes/HelloJDK8.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar Hello.jar HelloJDK8 + * @run driver TestAutoCreateSharedArchiveUpgrade + */ + +import java.io.File; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestAutoCreateSharedArchiveUpgrade { + // The JDK being tested + private static final String TEST_JDK = System.getProperty("test.jdk", null); + + // If you're running this test manually, specify the location of a previous version of + // the JDK using "jtreg -vmoption:-Dtest.previous.jdk=${JDK19_HOME} ..." + private static final String PREV_JDK = System.getProperty("test.previous.jdk", null); + + // If you're unning this test using something like + // "make test TEST=test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java", + // the test.boot.jdk property is passed by make/RunTests.gmk + private static final String BOOT_JDK = System.getProperty("test.boot.jdk", null); + + private static final String USER_DIR = System.getProperty("user.dir", "."); + private static final String FS = System.getProperty("file.separator", "/"); + + private static final String JAR = ClassFileInstaller.getJarPath("Hello.jar"); + private static final String JSA = USER_DIR + FS + "Hello.jsa"; + + private static String oldJVM; + private static String newJVM; + + public static void main(String[] args) throws Throwable { + setupJVMs(); + doTest(); + } + + static void setupJVMs() throws Throwable { + if (TEST_JDK == null) { + throw new RuntimeException("-Dtest.jdk should point to the JDK being tested"); + } + + newJVM = TEST_JDK + FS + "bin" + FS + "java"; + + if (PREV_JDK != null) { + oldJVM = PREV_JDK + FS + "bin" + FS + "java"; + } else if (BOOT_JDK != null) { + oldJVM = BOOT_JDK + FS + "bin" + FS + "java"; + } else { + throw new RuntimeException("Use -Dtest.previous.jdk or -Dtest.boot.jdk to specify a " + + "previous version of the JDK that supports " + + "-XX:+AutoCreateSharedArchive"); + } + + System.out.println("Using newJVM = " + newJVM); + System.out.println("Using oldJVM = " + oldJVM); + } + + static void doTest() throws Throwable { + File jsaF = new File(JSA); + jsaF.delete(); + OutputAnalyzer output; + + // NEW JDK -- create and then use the JSA + output = run(newJVM); + assertJSANotFound(output); + assertCreatedJSA(output); + + output = run(newJVM); + assertUsedJSA(output); + + // OLD JDK -- should reject the JSA created by NEW JDK, and create its own + output = run(oldJVM); + assertJSAVersionMismatch(output); + assertCreatedJSA(output); + + output = run(oldJVM); + assertUsedJSA(output); + + // NEW JDK -- should reject the JSA created by OLD JDK, and create its own + output = run(newJVM); + assertJSAVersionMismatch(output); + assertCreatedJSA(output); + + output = run(newJVM); + assertUsedJSA(output); + } + + static OutputAnalyzer run(String jvm) throws Throwable { + OutputAnalyzer output = + ProcessTools.executeCommand(jvm, "-XX:+AutoCreateSharedArchive", + "-XX:SharedArchiveFile=" + JSA, + "-Xlog:cds", + "-cp", JAR, "HelloJDK8"); + output.shouldHaveExitValue(0); + return output; + } + + static void assertJSANotFound(OutputAnalyzer output) { + output.shouldContain("Specified shared archive not found"); + } + + static void assertCreatedJSA(OutputAnalyzer output) { + output.shouldContain("Dumping shared data to file"); + } + + static void assertJSAVersionMismatch(OutputAnalyzer output) { + output.shouldContain("does not match the required version"); + } + + static void assertUsedJSA(OutputAnalyzer output) { + output.shouldContain("Mapped dynamic region #0"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloJDK8.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloJDK8.java new file mode 100644 index 00000000000..542402ce98a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloJDK8.java @@ -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. + * + */ + + +// Used by tests like dynamicArchive/TestAutoCreateSharedArchiveUpgrade.java, which +// runs this class in an earlier JDK +// +// It should be compiled like this in the jtreg spec: +// @compile -source 1.8 -target 1.8 test-classes/HelloJDK8.java + +public class HelloJDK8 { + public static void main(String args[]) { + System.out.println("This class is compiled by JDK 8"); + } +} diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 9bd9394f9fc..c3306a228ff 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -30,4 +30,3 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/ref/ReferenceEnqueue.java 8284236 generic-all -java/lang/Float/Binary16Conversion.java 8295351 generic-x64 diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b51f30fffcc..c191755713e 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -485,7 +485,6 @@ java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic- java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-x64 java/lang/invoke/RicochetTest.java 8251969 generic-all -jdk/internal/misc/TerminatingThreadLocal/TestTerminatingThreadLocal.java 8292051 generic-all ############################################################################ @@ -500,7 +499,6 @@ java/lang/instrument/RetransformBigClass.sh 8065756 generic- java/io/pathNames/GeneralWin32.java 8180264 windows-all java/io/File/createTempFile/SpecialTempFile.java 8274122 windows11 -java/io/File/TempDirDoesNotExist.java 8297528 windows-all ############################################################################ @@ -723,8 +721,6 @@ sun/util/locale/provider/CalendarDataRegression.java 8268379 macosx-x # svc_tools -sun/tools/jhsdb/BasicLauncherTest.java 8228649 linux-ppc64,linux-ppc64le - sun/tools/jstatd/TestJstatdDefaults.java 8081569,8226420 windows-all sun/tools/jstatd/TestJstatdRmiPort.java 8226420,8251259,8293577 generic-all sun/tools/jstatd/TestJstatdServer.java 8081569,8226420 windows-all diff --git a/test/jdk/java/io/File/TempDirDoesNotExist.java b/test/jdk/java/io/File/TempDirDoesNotExist.java index 36a72b575f1..d7b242d039c 100644 --- a/test/jdk/java/io/File/TempDirDoesNotExist.java +++ b/test/jdk/java/io/File/TempDirDoesNotExist.java @@ -42,7 +42,7 @@ public class TempDirDoesNotExist { public static void main(String... args) throws Exception { String userDir = System.getProperty("user.home"); - String timeStamp = java.time.Instant.now().toString(); + String timeStamp = System.currentTimeMillis() + ""; String tempDir = Path.of(userDir,"non-existing-", timeStamp).toString(); for (String arg : args) { diff --git a/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java b/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java index 1aa56c9b728..068acad0ed0 100644 --- a/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java +++ b/test/jdk/java/lang/ProcessBuilder/SecurityManagerClinit.java @@ -24,7 +24,7 @@ /* * @test - * @bug 6980747 + * @bug 6980747 8297451 * @summary Check that Process-related classes have the proper * doPrivileged blocks, and can be initialized with an adversarial * security manager. @@ -52,6 +52,17 @@ public boolean implies(ProtectionDomain pd, Permission p) { } } + // Security manager that unconditionally performs Thread Modify Access checks. + @SuppressWarnings("removal") + private static class TMACSecurityManager extends SecurityManager { + static final RuntimePermission MODIFY_THREAD_PERMISSION = + new RuntimePermission("modifyThread"); + @Override + public void checkAccess(Thread thread) { + checkPermission(MODIFY_THREAD_PERMISSION); + } + } + public static void main(String[] args) throws Throwable { String javaExe = System.getProperty("java.home") + @@ -60,10 +71,11 @@ public static void main(String[] args) throws Throwable { final SimplePolicy policy = new SimplePolicy (new FilePermission("<>", "execute"), - new RuntimePermission("setSecurityManager")); + new RuntimePermission("setSecurityManager"), + new RuntimePermission("modifyThread")); Policy.setPolicy(policy); - System.setSecurityManager(new SecurityManager()); + System.setSecurityManager(new TMACSecurityManager()); try { String[] cmd = { javaExe, "-version" }; diff --git a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java new file mode 100644 index 00000000000..f1274696d0f --- /dev/null +++ b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java @@ -0,0 +1,1146 @@ +/* + * Copyright (c) 2022 SAP SE. 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. + * + */ + +/** + * @test id=policy-1-without-gc-with-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyContinuations -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 1 0 + */ + +/** + * @test id=policy-2-without-gc-with-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyContinuations -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 2 0 + */ + +/** + * @test id=policy-3-without-gc-with-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyContinuations -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 3 0 + */ + +/** + * @test id=policy-4-without-gc-with-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyContinuations -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 4 0 + */ + +/** + * @test id=policy-5-without-gc-with-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyContinuations -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 5 0 + */ + +/** + * @test id=policy-1-with-gc-without-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 1 1 + */ + +/** + * @test id=policy-2-with-gc-without-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 2 1 + */ + +/** + * @test id=policy-3-with-gc-without-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 3 1 + */ + +/** + * @test id=policy-4-with-gc-without-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 4 1 + */ + +/** + * @test id=policy-5-with-gc-without-verification + * @summary Collection of basic continuation tests. CompilationPolicy controls which frames in a sequence should be compiled when calling Continuation.yield(). + * @requires vm.continuations + * @requires vm.flavor == "server" & vm.opt.TieredCompilation != true + * @enablePreview + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @build java.base/java.lang.StackWalkerHelper + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=dontinline,*::*dontinline* + * -XX:CompileCommand=dontinline,*::*dontjit* + * -XX:CompileCommand=exclude,*::*dontjit* + * -XX:CompileCommand=dontinline,java/lang/String*.* + * BasicExt 5 1 + */ + +import java.lang.reflect.Method; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import jdk.internal.vm.Continuation; +import jdk.internal.vm.ContinuationScope; +import static jdk.test.lib.Asserts.*; + +import compiler.whitebox.CompilerWhiteBoxTest; +import jdk.test.whitebox.WhiteBox; + +public class BasicExt { + static final ContinuationScope THE_SCOPE = new ContinuationScope() {}; + + public static final Pattern COMP_NONE = Pattern.compile("COMP_NONE"); + public static final Pattern COMP_ALL = Pattern.compile("COMP_ALL"); + public static final Pattern CONT_METHS = Pattern.compile("^(enter|enter0|yield|yield0)$"); + + public static int compPolicySelection; + public static boolean triggerGCAfterYield; + public static int compLevel; + + public static final WhiteBox WB = WhiteBox.getWhiteBox(); + + enum TestCaseVariants { + NO_VARIANT, + // Exception + THROW_HANDLED_EXCEPTION, + THROW_UNHANDLED_EXCEPTION, + // Synchronization + ALLOC_MONITOR, + // There are values on the expression stack that are not call parameters + EXPR_STACK_NOT_EMPTY, + } + + public static class HandledException extends Exception { } + public static class UnhandledException extends Error { } + + public static void main(String[] args) { + try { + // Run tests with C2 compilations + compLevel = CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION; + // // Run tests with C1 compilations + // compLevel = CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE; + + compPolicySelection = Integer.parseInt(args[0]); + triggerGCAfterYield = Integer.parseInt(args[1]) == 1; + runTests(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + public static void runTests() { + System.out.println("$$$0 Running test cases with the following settings:"); + System.out.println("compLevel=" + compLevel); + System.out.println("callSystemGC=" + triggerGCAfterYield); + System.out.println(); + + WB.deoptimizeAll(); + + boolean all = compPolicySelection == 0; + if (compPolicySelection == 1 || all) + runTests(new CompilationPolicy(7 /*warmup*/, COMP_NONE, COMP_NONE /*Cont. pattern*/)); + if (compPolicySelection == 2 || all) + runTests(new CompilationPolicy(7 /*warmup*/, 1 /* length comp. window */)); + if (compPolicySelection == 3 || all) + runTests(new CompilationPolicy(7 /*warmup*/, 2 /* length comp. window */)); + if (compPolicySelection == 4 || all) + runTests(new CompilationPolicy(7 /*warmup*/, 3 /* length comp. window */)); + if (compPolicySelection == 5 || all) + runTests(new CompilationPolicy(7 /*warmup*/, COMP_ALL, CONT_METHS /*Cont. pattern*/)); + if (compPolicySelection >= 6) + throw new Error("CompilationPolicy with number " + compPolicySelection + " does not exist"); + } + + public static void runTests(CompilationPolicy compPolicy) { + System.out.println("$$$1 Running test cases with the following policy:"); + compPolicy.print(); System.out.println(); + + new ContinuationRunYieldRunTest().runTestCase(3, compPolicy); + new Continuation3Frames(TestCaseVariants.NO_VARIANT).runTestCase(4, compPolicy); + new Continuation3Frames(TestCaseVariants.THROW_HANDLED_EXCEPTION).runTestCase(4, compPolicy); + new Continuation3Frames(TestCaseVariants.THROW_UNHANDLED_EXCEPTION).runTestCase(4, compPolicy); + new Continuation3Frames(TestCaseVariants.ALLOC_MONITOR).runTestCase(4, compPolicy); + new Continuation3Frames(TestCaseVariants.EXPR_STACK_NOT_EMPTY).runTestCase(4, compPolicy); + new ContinuationRunYieldRunTest().runTestCase( 1, compPolicy); + new ContinuationYieldEnlargeStackYield().runTestCase(1, compPolicy); + new ContinuationYieldReduceStackYield().runTestCase(1, compPolicy); + new ContinuationCompiledFramesWithStackArgs_3c0().runTestCase(1, compPolicy); + new ContinuationCompiledFramesWithStackArgs_3c4().runTestCase(1, compPolicy); + new ContinuationCompiledFramesWithStackArgs().runTestCase(1, compPolicy); + new ContinuationDeepRecursion().runTestCase(3, compPolicy); + new ContinuationDeepRecursionStackargs().runTestCase(3, compPolicy); + } + + // Control which frames are compiled/interpreted when calling Continuation.yield() + // With COMP_WINDOW the methods in the window are supposed to be compiled and others + // are interpreted. With DEOPT_WINDOW vice versa. + // The methods that are subject to the CompilationPolicy are set with setMethods(). + // Their order has to correspond to the stack order when calling yield(). + public static class CompilationPolicy { + public int warmupIterations; + public Pattern methodPattern; + public Pattern contMethPattern; + + public CompWindowMode compWindowMode; + public int winPos; + public int winLen; + + public Method[] methods; + + public enum CompWindowMode { + NO_COMP_WINDOW, COMP_WINDOW, DEOPT_WINDOW + } + + public CompilationPolicy(int warmupIterations, Pattern methodPattern, + Pattern contMethPattern) { + this(warmupIterations, 0, methodPattern, contMethPattern, + CompWindowMode.NO_COMP_WINDOW); + } + + public CompilationPolicy(int warmupIterations, int windowLength, + Pattern methodPattern, Pattern contMethPattern) { + this(warmupIterations, windowLength, methodPattern, contMethPattern, + CompWindowMode.COMP_WINDOW); + } + + public CompilationPolicy(int warmupIterations, int windowLength, + Pattern methodPattern, Pattern contMethPattern, + CompWindowMode startMode) { + this.warmupIterations = warmupIterations; + this.methodPattern = methodPattern; + this.contMethPattern = contMethPattern; + this.winPos = 0; + this.winLen = windowLength; + this.compWindowMode = startMode; + } + + public CompilationPolicy(int warmupIterations, int windowLength) { + this(warmupIterations, windowLength, COMP_ALL, CONT_METHS); + } + + public int warmupIterations() { + return this.warmupIterations; + } + + public boolean compileMethods() { + boolean newCompilation = false; + log("@@ Compiling test methods according to compilation policy"); + print(); + for (int i = 0; i < methods.length; i++) { + Method meth = methods[i]; + boolean inWindow = i >= winPos && i < (winPos + winLen); + boolean shouldBeCompiled = compWindowMode == CompWindowMode.NO_COMP_WINDOW + || (inWindow && compWindowMode == CompWindowMode.COMP_WINDOW) + || (!inWindow && compWindowMode == CompWindowMode.DEOPT_WINDOW); + boolean isCompiled = WB.isMethodCompiled(meth); + log("methods[" + i + "] inWindow=" + inWindow + " isCompiled=" + isCompiled + + " shouldBeCompiled=" + shouldBeCompiled + " method=`" + meth + "`"); + if (isCompiled != shouldBeCompiled) { + if (shouldBeCompiled) { + log(" Compiling methods[" + i + "]"); + enqForCompilation(meth); + newCompilation = true; + assertTrue(WB.isMethodCompiled(meth), "Run with -Xbatch"); + } else { + assertFalse(WB.isMethodQueuedForCompilation(meth), "Run with -Xbatch"); + log(" Deoptimizing methods[" + i + "]"); + WB.deoptimizeMethod(meth); + } + } + } + return newCompilation; + } + + @SuppressWarnings("deprecation") + public boolean enqForCompilation(Method meth) { + return WB.enqueueMethodForCompilation(meth, compLevel); + } + + public void log(String m) { + System.out.println(m); + } + + public void print() { + log("warmupIterations=" + warmupIterations); + log("methodPattern=" + methodPattern); + log("continuationMethPattern=" + contMethPattern); + log("compWindowMode=" + compWindowMode); + log("winLen=" + winLen); + } + + public void setMethods(Method[] methods) { + this.methods = methods; + if (compWindowMode == CompWindowMode.NO_COMP_WINDOW) { + winLen = methods.length; + } + } + + public boolean shiftWindow() { + if (compWindowMode == CompWindowMode.NO_COMP_WINDOW) return false; + if (++winPos == methods.length) { + winPos = 0; + if (compWindowMode == CompWindowMode.DEOPT_WINDOW) { + compWindowMode = CompWindowMode.COMP_WINDOW; + return false; // we're done + } + compWindowMode = CompWindowMode.DEOPT_WINDOW; + } + return true; // continue + } + } + + /** + * Base class for test cases + */ + public static abstract class TestCaseBase implements Runnable { + public int yieldCalls; + public int warmUpCount; + public CompilationPolicy compPolicy; + public final TestCaseVariants testVariant; + + public TestCaseBase() { + testVariant = TestCaseVariants.NO_VARIANT; + } + + public TestCaseBase(TestCaseVariants excBehav) { + this.testVariant = excBehav; + } + + public void log_dontjit() { + System.out.println(); + } + + public void log_dontjit(String m) { + if (warmUpCount > 0) { + System.out.print("[" + warmUpCount + "] "); + } + System.out.println(m); + } + + public void runTestCase(int yieldCalls, CompilationPolicy compPolicy) { + this.yieldCalls = yieldCalls; + log_dontjit(">>>> Executing test case " + getClass().getName() + + " (yieldCalls=" + yieldCalls + ", " + "testVariant=" + testVariant + ")"); + init(compPolicy); + try { + log_dontjit("Warm-up test case"); + setup_dontjit(true /* for warmup */); + for(warmUpCount = 1; warmUpCount <= compPolicy.warmupIterations(); warmUpCount++) { + testEntry_dontinline(); + } + warmUpCount = 0; + log_dontjit("Warm-up test case DONE"); + + setup_dontjit(false /* for warmup */); + do { + compPolicy.compileMethods(); + do { + log_dontjit("Running test case (Reresolve Call Sites)"); + testEntry_dontinline(); + log_dontjit("Running test case DONE (Reresolve Call Sites)"); + } while(compPolicy.compileMethods()); + + log_dontjit("Running test case BEGIN"); + testEntry_dontinline(); + log_dontjit("Running test case DONE"); + } while(compPolicy.shiftWindow()); + } finally { + log_dontjit("<<<< Finished test case " + getClass().getName()); log_dontjit(); + } + } + + public void setup_dontjit(boolean warmup) { + } + + public void init(CompilationPolicy compPolicy) { + this.compPolicy = compPolicy; + ArrayList selectedMethods = new ArrayList(); + Pattern p = compPolicy.methodPattern; + if (p != COMP_NONE) { + Class c = getClass(); + Method methods[] = c.getDeclaredMethods(); + for (Method meth : methods) { + if (p == COMP_ALL || p.matcher(meth.getName()).matches()) { + if (!meth.getName().contains("dontjit")) { + selectedMethods.add(meth); + } + } + } + } + + p = compPolicy.contMethPattern; + if (compPolicy.contMethPattern != COMP_NONE) { + Class c = Continuation.class; + Method methods[] = c .getDeclaredMethods(); + for (Method meth : methods) { + if (p.matcher(meth.getName()).matches()) { + selectedMethods.add(meth); + } + } + } + // Sort in caller/callee order + selectedMethods.sort(new Comparator() { + @Override + public int compare(Method m1, Method m2) { + String n1 = m1.getName(); + String n2 = m2.getName(); + // log_dontjit("n1=" + n1 + " n2=" + n2); + int p1 = -1; + int p2 = -1; + int i = n1.indexOf("ord"); + if (i >= 0) { + p1 = Integer.parseInt(n1.substring(i + 3, i + 6)); + } + i = n2.indexOf("ord"); + if (i >= 0) { + p2 = Integer.parseInt(n2.substring(i + 3, i + 6)); + } + if (p1 < 0) p1 = getScoreKnownMethods(n1); + if (p2 < 0) p2 = getScoreKnownMethods(n2); + assertFalse(p1 == -1 || p2 == -1, "Cannot compare " + n1 + " with " + n2); + return p1 - p2; + } + + private int getScoreKnownMethods(String n) { + int p = -1; + if (n.equals("enter")) p = 20; // Continuation.enter + if (n.equals("enter0")) p = 30; // Continuation.enter0 + if (n.equals("run")) p = 50; // Called by Continuation.enter0 + if (n.equals("yield")) p = 1000; // caller of yield0 + if (n.equals("yield0")) p = 2000; // top frame + return p; + } + }); + compPolicy.setMethods(selectedMethods.toArray(new Method[selectedMethods.size()])); + } + + public void testEntry_dontinline() { + Continuation cont = new Continuation(THE_SCOPE, this); + do { + try { + cont.run(); + } catch (UnhandledException e) { + log_dontjit("Exc: " + e); + } + if (triggerGCAfterYield) WB.youngGC(); + checkFrames_dontjit(cont); + } while (!cont.isDone()); + } + + public void checkFrames_dontjit(Continuation cont) { + } // Override in subclass as appropriate + + @Override + public void run() { + fail("Should not call TestCaseBase::run"); + } + + public void sleep(Duration d) { + try { Thread.sleep(d); } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + + static final long i1=1; static final long i2=2; static final long i3=3; + static final long i4=4; static final long i5=5; static final long i6=6; + static final long i7=7; static final long i8=8; static final long i9=9; + static final long i10=10; static final long i11=11; static final long + i12=12; static final long i13=13; static final long i14=14; static final + long i15=15; static final long i16=16; + } + + /** + * Trivial run/yield/run test + */ + public static class ContinuationRunYieldRunTest extends TestCaseBase { + public String sField; + + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + for(int i = 0; i < yieldCalls; i++) { + log_dontjit("Yield #" + i); + String s1 = "str1"; + Continuation.yield(THE_SCOPE); + String s2 = s1 + "str2"; + sField = s2; + } + } + } + + /** + * Yield, make continuation (stack) larger, yield again. + */ + public static class ContinuationYieldEnlargeStackYield extends TestCaseBase { + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + Continuation.yield(THE_SCOPE); + log_dontjit("Back from 1st yield. Now call a method to make the stack larger."); + ord101_callYieldWithLargerStackAgain_dontinline(); + } + + private void ord101_callYieldWithLargerStackAgain_dontinline() { + log_dontjit("Now there's a new frame on stack. Call yield again."); + Continuation.yield(THE_SCOPE); + log_dontjit("Back again after 2nd yield."); + } + } + + + /** + * Yield, make continuation (stack) larger, yield again. + */ + public static class ContinuationYieldReduceStackYield extends TestCaseBase { + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + ord101_methodWithFirstYield_dontinline(); + log_dontjit("The frame of ord101_methodWithFirstYield_dontinline has been removed now. Call yield again."); + Continuation.yield(THE_SCOPE); + log_dontjit("Back again after 2nd yield."); + } + + public void ord101_methodWithFirstYield_dontinline() { + Continuation.yield(THE_SCOPE); + log_dontjit("Back from 1st yield. Now return to reduce stack size."); + } + } + + /** + * Freeze/thaw 3 compiled frames. + */ + public static class Continuation3Frames extends TestCaseBase { + public int yieldCount; + public long resLong; + public volatile String putOnExprStack; + + public Continuation3Frames(TestCaseVariants excBehav) { + super(excBehav); + } + + @Override + public void run() { + for(int i = 0; i < yieldCalls; i++) { + Throwable caughtException = null; + putOnExprStack = "exprStckVal "; + resLong = 0; + try { + String s1 = "str1"; + String result = ord101_testMethod_dontinline(i1, i2, i3, s1); + assertEQ(resLong, testVariant == TestCaseVariants.ALLOC_MONITOR ? 7L : 6L); + assertEQ(result, testVariant == TestCaseVariants.EXPR_STACK_NOT_EMPTY ? + "exprStckVal str1str2str3" : "str1str2str3"); + } catch (HandledException e) { + caughtException = e; + } + assertTrue(testVariant != TestCaseVariants.THROW_HANDLED_EXCEPTION + || (caughtException instanceof HandledException), + "Exception handling error"); + } + } + + public String ord101_testMethod_dontinline(long a1, long a2, long a3, String s1) + throws HandledException { + String s2 = s1 + "str2"; + return ord102_testMethod_dontinline(a1, a2, a3, s2); + } + + public String ord102_testMethod_dontinline(long a1, long a2, long a3, String s2) + throws HandledException { + if (testVariant == TestCaseVariants.ALLOC_MONITOR) { + synchronized (this) { + resLong++; + } + } + if (testVariant == TestCaseVariants.EXPR_STACK_NOT_EMPTY) { + return putOnExprStack_testMethod_dontjit_dontinline() + + ord103_testMethod_dontinline(a1, a2, a3, s2); + } else { + return ord103_testMethod_dontinline(a1, a2, a3, s2); + } + } + + public String ord103_testMethod_dontinline(long a1, long a2, long a3, String s2) + throws HandledException { + return ord104_testMethod_dontinline(a1, a2, a3, s2); + } + + public String ord104_testMethod_dontinline(long a1, long a2, long a3, String s2) + throws HandledException { + long res = a2; + String s3 = s2 + "str3"; + log_dontjit("Yield #" + yieldCount++); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount); + if (testVariant == TestCaseVariants.THROW_HANDLED_EXCEPTION) { + log_dontjit("Exc: throw handled"); + throw new HandledException(); + } + if (testVariant == TestCaseVariants.THROW_UNHANDLED_EXCEPTION) { + log_dontjit("Exc: throw unhandled"); + throw new UnhandledException(); + } + resLong += res + a1 + a3; + return s3; + } + + public String putOnExprStack_testMethod_dontjit_dontinline() { + return putOnExprStack; + } + + @Override + public void checkFrames_dontjit(Continuation cont) { + List frames = + cont.stackWalker() + .walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); + assertEquals(frames, cont.isDone() ? List.of() + : Arrays.asList("yield", "ord104_testMethod_dontinline", + "ord103_testMethod_dontinline", + "ord102_testMethod_dontinline", + "ord101_testMethod_dontinline", + "run", "enter0", "enter")); + } + } + + /** + * Deep recursion to exercise fast freezing into non-empty chunk + */ + public static class ContinuationDeepRecursion extends TestCaseBase { + public int limit; + public int yield1_depth; + public int yield2_depth; + + @Override + public void setup_dontjit(boolean warmup) { + if (warmup) { + limit = 10; + yield1_depth = 7; + yield2_depth = 3; + } else { + limit = 100; + yield1_depth = 70; + yield2_depth = 60; + } + } + + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + ord101_recurse_dontinline(0); + } + + public void ord101_recurse_dontinline(int depth) { + if (depth >= limit) { + log_dontjit("yield at depth " + depth); + ord102_yield_dontinline(0); + log_dontjit("After yield at depth " + depth); + return; + } + ord101_recurse_dontinline(depth + 1); + if (depth == yield1_depth || depth == yield2_depth) { + log_dontjit("yield at depth " + depth); + ord102_yield_dontinline(0); + log_dontjit("After yield at depth " + depth); + } + } + + // Add a few frames before yield + public void ord102_yield_dontinline(int depth) { + if (depth >= 2) { + Continuation.yield(THE_SCOPE); + return; + } + ord102_yield_dontinline(depth + 1); + } + } + + /** + * Deep recursion to exercise fast freezing into non-empty chunk. + * nmethods have stack arguments. + */ + public static class ContinuationDeepRecursionStackargs extends TestCaseBase { + public int limit; + public int yield1_depth; + public int yield2_depth; + + @Override + public void setup_dontjit(boolean warmup) { + if (warmup) { + limit = 10; + yield1_depth = 7; + yield2_depth = 3; + } else { + limit = 100; + yield1_depth = 70; + yield2_depth = 60; + } + } + + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + long res = ord101_recurse_dontinline(0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); + if (res != i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11) { + throw new Error(); + } + } + + public long ord101_recurse_dontinline(int depth, long l1, long l2, long + l3, long l4, long l5, long l6, + long l7, long l8, long l9, long + l10, long l11) { + if (depth >= limit) { + log_dontjit("yield at depth " + depth); + ord102_yield_dontinline(0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11); + log_dontjit("After yield at depth " + depth); + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + l10 + l11; + } + long res = ord101_recurse_dontinline(depth + 1, l1, l2, l3, l4, l5, + l6, l7, l8, l9, l10, l11); + if (res != l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + l10 + l11) { + throw new Error(); + } + if (depth == yield1_depth || depth == yield2_depth) { + log_dontjit("yield at depth " + depth); + long res1 = ord102_yield_dontinline(0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11); + if (res1 != l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + l10 + l11) { + throw new Error(); + } + log_dontjit("After yield at depth " + depth); + } + return res; + } + + // Add a few frames before yield + public long ord102_yield_dontinline(int depth, long l1, long l2, long l3, long l4, long l5, + long l6, long l7, long l8, long l9, long l10, long l11) { + if (depth >= 2) { + Continuation.yield(THE_SCOPE); + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + l10 + l11; + } + long res = ord102_yield_dontinline(depth + 1, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11); + if (res != l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + l10 + l11) { + throw new Error(); + } + return res; + } + } + + /** + * Freeze/thaw compiled frame with a few stack arguments + * icj is a call with i incoming stack parameters and j outgoing stack parameters. + */ + public static class ContinuationCompiledFramesWithStackArgs_3c0 extends TestCaseBase { + public int yieldCount; + + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + yieldCount = 0; + long result = ord101_testMethod_dontinline(); + assertEQ(result, 136L); + } + + public long ord101_testMethod_dontinline() { + long res = ord102_testMethod_dontinline(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11); + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord108_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord108_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord102_testMethod_dontinline(long a1, long a2, long a3, long + a4, long a5, long a6, long a7, + long a8, long a9, long a10, + long a11) { + long res = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + + i12 + i13 + i14 + i15 + i16; + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord109_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord109_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + } + + /** + * Freeze/thaw compiled frame with a few stack arguments, incoming _and_ outgoing + * icj is a call with i incoming stack parameters and j outgoing stack parameters. + */ + public static class ContinuationCompiledFramesWithStackArgs_3c4 extends TestCaseBase { + public int yieldCount; + + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + yieldCount = 0; + long result = ord101_testMethod_dontinline(); + assertEQ(result, 136L); + } + + public long ord101_testMethod_dontinline() { + long res = ord102_testMethod_dontinline(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14); + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord108_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord108_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord102_testMethod_dontinline(long a1, long a2, long a3, long + a4, long a5, long a6, long a7, + long a8, long a9, long a10, + long a11, long a12, long a13, + long a14) { + long res = ord103_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, i15); + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord109_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord109_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord103_testMethod_dontinline(long a1, long a2, long a3, long + a4, long a5, long a6, long a7, + long a8, long a9, long a10, + long a11, long a12, long a13, + long a14, long a15) { + long res = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + + a12 + a13 + a14 + a15 + i16; + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord109_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord109_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + } + + /** + * Freeze/thaw compiled frame with many stack arguments + */ + public static class ContinuationCompiledFramesWithStackArgs extends TestCaseBase { + public int yieldCount; + + @Override + public void run() { + log_dontjit("Continuation running on thread " + Thread.currentThread()); + yieldCount = 0; + long result = ord101_testMethod_dontinline(i1); + assertEQ(result, 136L); + } + + public long ord101_testMethod_dontinline(long a1) { + long res = ord102_testMethod_dontinline(a1, i2); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord102_testMethod_dontinline(long a1, long a2) { + long res = ord103_testMethod_dontinline(a1, a2, i3); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord103_testMethod_dontinline(long a1, long a2, long a3) { + long res = ord104_testMethod_dontinline(a1, a2, a3, i4); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord104_testMethod_dontinline(long a1, long a2, long a3, long a4) { + long res = ord105_testMethod_dontinline(a1, a2, a3, a4, i5); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord105_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5) { + long res = ord106_testMethod_dontinline(a1, a2, a3, a4, a5, i6); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord106_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6) { + long res = ord107_testMethod_dontinline(a1, a2, a3, a4, a5, a6, i7); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord107_testMethod_dontinline(long a1, long a2, long a3, long + a4, long a5, long a6, long a7) { + long res = ord108_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, i8); + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord108_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord108_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord108_testMethod_dontinline(long a1, long a2, long a3, long + a4, long a5, long a6, long a7, long a8) { + long res = ord109_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, i9); + log_dontjit("Yield #" + yieldCount); + log_dontjit("ord109_testMethod_dontinline res=" + res); + Continuation.yield(THE_SCOPE); + log_dontjit("a/y ord109_testMethod_dontinline res=" + res); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord109_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9) { + long res = ord110_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, i10); + Continuation.yield(THE_SCOPE); + return res; + } + + public long ord110_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10) { + long res = ord111_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, i11); + log_dontjit("Yield #" + yieldCount); Continuation.yield(THE_SCOPE); log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord111_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10, long a11) { + long res = ord112_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, i12); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord112_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10, long a11, long a12) { + long res = ord113_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, i13); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord113_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10, long a11, long a12, + long a13) { + long res = ord114_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, i14); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord114_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10, long a11, long a12, + long a13, long a14) { + long res = ord115_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, i15); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord115_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10, long a11, long a12, + long a13, long a14, long a15) { + long res = ord116_testMethod_dontinline(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, i16); + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + return res; + } + + public long ord116_testMethod_dontinline(long a1, long a2, long a3, long a4, long a5, long a6, + long a7, long a8, long a9, long a10, long a11, long a12, + long a13, long a14, long a15, long a16) { + long res = a2 + a4 + a6 + a8 + a10 + a12 + a14 + a16; + log_dontjit("Yield #" + yieldCount); + Continuation.yield(THE_SCOPE); + log_dontjit("/Yield #" + yieldCount++); + res += a1 + a3 + a5 + a7 + a9 + a11 + a13 + a15; + return res; + } + } +} diff --git a/test/jdk/jdk/jfr/threading/TestDeepVirtualStackTrace.java b/test/jdk/jdk/jfr/threading/TestDeepVirtualStackTrace.java index 77c05daf03b..427ab85f387 100644 --- a/test/jdk/jdk/jfr/threading/TestDeepVirtualStackTrace.java +++ b/test/jdk/jdk/jfr/threading/TestDeepVirtualStackTrace.java @@ -92,6 +92,9 @@ private static void assertStackTrace(Runnable eventEmitter, String eventName, St System.out.println(); System.out.println("Testing event: " + eventName); System.out.println("============================="); + + boolean isTargetEventFound = false; + try (Recording r = new Recording()) { r.enable(eventName).withoutThreshold(); r.start(); @@ -99,25 +102,40 @@ private static void assertStackTrace(Runnable eventEmitter, String eventName, St vt.join(); r.stop(); List events = Events.fromRecording(r); - Asserts.assertEquals(events.size(), 1, "No event found in virtual thread"); - RecordedEvent event = events.get(0); - System.out.println(event); - RecordedStackTrace stackTrace = event.getStackTrace(); - List frames = stackTrace.getFrames(); - Asserts.assertTrue(stackTrace.isTruncated()); - int count = 0; - for (RecordedFrame frame : frames) { - Asserts.assertTrue(frame.isJavaFrame()); - Asserts.assertNotNull(frame.getMethod()); - RecordedMethod m = frame.getMethod(); - Asserts.assertNotNull(m.getType()); - if (m.getName().contains(stackMethod)) { - count++; + Asserts.assertFalse(events.isEmpty(), "No event found in virtual thread"); + for (RecordedEvent event : events) { + System.out.println(event); + RecordedStackTrace stackTrace = event.getStackTrace(); + if (stackTrace == null) { + continue; + } + List frames = stackTrace.getFrames(); + int count = 0; + boolean isTargetEvent = false; + boolean isFirstFrame = true; + for (int c = 0; c < frames.size(); c++) { + RecordedFrame frame = frames.get(c); + Asserts.assertTrue(frame.isJavaFrame()); + Asserts.assertNotNull(frame.getMethod()); + RecordedMethod m = frame.getMethod(); + Asserts.assertNotNull(m.getType()); + if (m.getName().contains(stackMethod)) { + if (c == 0) { + isTargetEvent = true; + } + count++; + } + } + if (isTargetEvent) { + isTargetEventFound = true; + Asserts.assertTrue(stackTrace.isTruncated()); + Asserts.assertEquals(count, FRAME_COUNT); + Asserts.assertEquals(frames.size(), FRAME_COUNT); } } - Asserts.assertEquals(count, FRAME_COUNT); - Asserts.assertEquals(frames.size(), FRAME_COUNT); } + + Asserts.assertTrue(isTargetEventFound, "At least one target event found"); } } diff --git a/test/langtools/tools/javac/T8295447.java b/test/langtools/tools/javac/T8295447.java new file mode 100644 index 00000000000..76fcaf10f8d --- /dev/null +++ b/test/langtools/tools/javac/T8295447.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010, 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. + */ +/** + * @test + * @bug 8295447 + * @summary NullPointerException with invalid pattern matching construct in constructor call + * @modules jdk.compiler + * @compile/fail/ref=T8295447.out -XDrawDiagnostics --enable-preview -source ${jdk.version} T8295447.java + */ +public class T8295447 { + class Foo { + void m(Object o) { + if(o instanceof Foo(int x)) {} + } + + Foo(Object o) { + m((o instanceof Foo(int x))? 0 : 1); + } + void m(int i) { } + } + + class Base { int i; Base(int j) { i = j; } } + class Sub extends Base { + Sub(Object o) { super(o instanceof java.awt.Point(int x, int y)? x + y: 0); } + } +} diff --git a/test/langtools/tools/javac/T8295447.out b/test/langtools/tools/javac/T8295447.out new file mode 100644 index 00000000000..7f6746f802f --- /dev/null +++ b/test/langtools/tools/javac/T8295447.out @@ -0,0 +1,6 @@ +T8295447.java:33:29: compiler.err.deconstruction.pattern.only.records: T8295447.Foo +T8295447.java:37:29: compiler.err.deconstruction.pattern.only.records: T8295447.Foo +T8295447.java:44:44: compiler.err.deconstruction.pattern.only.records: java.awt.Point +- compiler.note.preview.filename: T8295447.java, DEFAULT +- compiler.note.preview.recompile +3 errors \ No newline at end of file diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index c51490a4a75..5cf07cc2c42 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java @@ -94,7 +94,7 @@ public class CDSArchiveUtils { offsetCrc = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_crc"); offsetVersion = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_version"); offsetHeaderSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_header_size"); - offsetCommonAppClasspathPrefixSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_common_app_classpath_prefix_size"); + offsetCommonAppClasspathPrefixSize = wb.getCDSOffsetForName("FileMapHeader::_common_app_classpath_prefix_size"); offsetBaseArchiveNameOffset = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_offset"); offsetBaseArchiveNameSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_size"); offsetJvmIdent = wb.getCDSOffsetForName("FileMapHeader::_jvm_ident");